I created a drag and drop email editor, I’ve been working on it for the past month. It’s a lot of fun to work on, I completed it for first release, I’ll shed some light on the challenges I faced and how I solved them.

Why’s & What’s

why build this?

No free editors/open source editors that does the job,

but why not profit?

Not interested, I believe in Open Source. Heavily inspired by how LINUX (OPEN SOURCE) is useful for everyone now.

the real motivation?

Let me be frank here, I dont like unalyer github, MAINLY BECAUSE OF THEIR FALSE ADVERTISEMENT AS OPEN SOURCE, I understand that’s how the get their business going but, damn its scummy.

One by one respoectively

  • scumbag unlayer,
  • grapjs mjml,
  • company that I am working for, at the time of writing this, needed an email dnd editor.

Challenges

  • maintaining layer between MJML and Me.

  • writing parsers, serializers and deseriealizers.

  • design and code ui

  • manage drag and drop, mouse, key events, …etc.

  • deciding what kind of api to expose

  • deciding what inline editor to use

    • I can do one of two things
    • One, spend time & learn the api’s of an existing inline editor
    • Two, spend time creating a yet another inline editor, that I have full control of. (I’ll learn a lot of new things If I do this)

I did both, but after finding serveral small size inline editors, I decided to completely go ahead with creating a custom InlineEditor, it is not a major task if I used document.executeCommand

  • maintaining demo/docs/npm package in single repo

  • backend

    • using firebase fn in combination with express
    • firestore for database

I’ll explain maintaining demo/docs/npm package in single repo now, since that is the recent & last thing that I completed.

Maintaining demo/docs/npm package in single repo

Let me fist explain the layout of the items in the repo.

the repo contains,

  • create-react-app react-scripts by default for the demo page
  • the editor component
    • I want this to be bundled and published to npm
  • the demo branch, that automatically deploys with github pages
  • api docs for the project

checklist that I created before starting work on this

Its always better to plan ahead to avoid surprises later, created a small checklist to help me with this.

I should have,

  • verified that the Editor is standalone
    • (i.e). that there is no demo build dependencies directly in the editor (like on first editor load, fetch this template from the backend, ..etc)
  • verified that the Editor is fully functional
    • (i.e). that the editor can be used in a demo page without problems
  • decided on what build system to use
    • webpack
    • rollup
    • nd…etc, millions of other build systems out there
  • created the build system, in such a way that It wont affect the demo build (created with create-react-app)
    • at the time of writing this, react-scripts uses webpack v4, So installing another instance of webpack v5 for npm build, will cause react-scripts to fail, the same goes for its dependencies aswell.
  • created a seperate branch, do all documentations and changes in that branch
  • bundled only selected files in the npm build, should only contain
    • editor
    • css/sass files used with the editor
    • image files used with the editor
  • created sepereate scripts in package.json for the differnet builds
    • build = for react-scripts-build
    • build:module = for npm-build
  • created a seperate packge.json for the npm build, since the exported Editor component doesn’t need all the dependencies from the repository.

Choosing build system for the editor

I have already published packages using webpack in the past, So I already knew webpack and its different modules. But the problem is I don’t know if I can use two webpack instances in a single project.

I Could go for a new build system just to solve this problem alone, Or find a way to use two webpack instances in a single project.

This is the point in time, where I found out about yarn alias, After I found this, I knew which build system to choose (webpack v5).

webpack has an environment configuration named ‘WEBPACK_PACKAGE’, it takes the package name of the webpack, So I can utilize this to install multiple versions, one with name ‘webpack’ another with alias ‘webpack-module’

 "webpack-module": "npm:webpack@^5.60.0"

I can then run webpack normally with ‘react-scripts’ and ‘WEBPACK_PACKAGE=webpack-module webpack’ for npm build

Requirements for publishing to npm

For publishing to npm, I need,

  • npm account
  • a package.json with seperate dependencies from the demo package.json
    • there should be a two package.json now. One for demo build, another for package build
  • a webpack configuration file for bundling
  • typescript definition file
  • output of npm pack

Webpack configuration

webpack configuration should process

  • process scss, css and module css, scss.

style loader - Inject the bundled styles into webpage.

since I used @import for fonts and url for background, I need to add css loader

I have also used sass, thus sass loader is required. To note, for the modern web, there is dart sass. I can instruct “sass loader” to use “dart sass”

// css
{
  test: /(\.css$|\.module\.css$)/i,
  use: ['style-loader-module', 'css-loader-module'],
},
// scss
{
  test: /(\.s[ac]ss$|\.module\.s[ac]ss$)/i,
  use: [
    {
      loader: 'style-loader-module',
    },
    {
      loader: 'css-loader-module',
      options: {
        importLoaders: 1,
        modules: {
          mode: 'local',
        },
      },
    },
    {
      loader: 'sass-loader-module',
      options: {
        implementation: require('sass'),
      },
    },
  ],
}
  • process .tsx, .ts and .jsx…etc.

    {
    test: /\.(js|jsx|ts|tsx)$/,
    exclude: /node_modules/,
    use: {
        loader: 'babel-loader-module',
        options: {
          presets: [
            '@babel/preset-env',
            ['@babel/preset-react', { runtime: 'automatic' }],
            '@babel/preset-typescript',
          ],
      },
    }
    }
    
  • instruct webpack to recognize .tsx file extensions.

    resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
    }
    
  • a way to make image assets work in extensions,In webpack 5, I can bundle images inline in js files.

    {
    test: /\.svg/,
    type: 'asset/inline',
    }
    

That is it for the webpack config, Isn’t this simple and concise.

Maintaining another package.json for npm

Obviously, only at the time of packing I need package.json untill then I can renaming to something else, I named it to ‘module-package.json’ then at time of ‘bundling and packing’, I rename it to ‘package.json’

the contents of ‘module-package.json’ should contain the following,

  "name": "dnd-email-editor",
  "version": "v0.0.0-alpha.3",
  "description": "Drag and Drop Editor designed for mails",
  "main": "./main.js",
  "files": ["**/*"],
  "types": "./index.d.ts",
  "peerDependencies": {
    "react": "^17.0.1",
    "react-dom": "^17.0.1"
  },
  "author": "https://github.com/aghontpi",
  "license": "GPL-3.0",
  "bugs": {
    "url": "https://github.com/aghontpi/dnde/issues"
  },
  "homepage": "https://github.com/aghontpi/dnde",

On every version change, change “version” key, It’ll automatically update in npmjs.

bundling and packing

I added the following command to package.json, (original package.json not ‘module-package.json’), note the environment variable ‘WEBPACK_PACKAGE’ I mentioned from before.

WEBPACK_PACKAGE=webpack-module webpack &&
  cp module-package.json module/package.json &&
  cp index.d.ts module/index.d.ts &&
  cp README.md module/README.md  &&
  npm pack ./module/

I can the publish the output from the previous command with

npm publish build-verion.tgz

Conclusion

I oversimplified in many cases but this covers ‘publishing to npm part’. I solved a lot of similar interesting problems in the project, Check it github dnde.