|

From bundling to publishing: My first node module

Bundler, bundler in hand, how do I get my code into npm land?.

Earlier this year, my first custom node module was finally released. Working on it allowed me to learn a lot about npm, JavaScript bundling, and working with modules, and I can now say with confidence:

How on earth can it be so incredibly difficult to get the output you want with a command?

Fixed Scrollnav

I had the fixed scrollnav function that i wanted to reuse on several pages and therefore wanted to convert it to an importable module.

how did i proceed with my function

  • first prototyping , built small demo of the function
  • then refactor to more modularity, bundled through webpack
  • wrapped and exported
  • step 1 was done
  • my fixed scrollnav function worked
  • but was in a state that was not really consumable?
  • webpack overhead? wtf
  • this has to work better
  • because, my first module should be able to do the following...
the thing should be written in ES6 and transpiled in ES5

... is written in ES6 and should also run in IE11 i.e. under ES5. This should be possible with a JavaScript transpiler like Babel. Also I write my styles in Sass, so my style.scss has to be converted to CSS.

The files of my module (JS and CSS) should be available as minified .min version. Shouldn`t be that hard. *think!

I want a demo

via Github Pages [...] I set up the project with my own boilerplate based on webpack.

Write code. Adapt paths for webpack. Include polyfills. **Done. *Okay... it was a bit more demanding but for the sake of comprehensibility we will limit ourselves to this abstraction.

Already ./docs was recognized by Github and my project had a small but nice demo page.

this thing should go into the npm repo

Now I only had to upload my most important files (let's call them module.js and module.css) to npm. Of course the creation of the files should happen automated.

here we go

how do i start - with rollup

Through a colleague I knew that a bundler called Rollup is suitable for modules. So I started to read into the program. Quickly I found out that the info from the videos and text sources was outdated, but thanks to the good feedback from rollup's CLI, the errors were quickly found and fixed. Unfortunately, it didn't stay that easy.

The promised simplicity of the bundler failed like so many others as soon as it got to the CSS: just like other bundlers, it's a JS bundler. I.e. to insert CSS it has to be included within module.js. Meaning: I would have needed a different code base for my demo as for the npm module!

This was not an option for me. After a lot of trial and error and research it turned out that Rollup totz the various plugins will not be able to include external CSS via the config. It simply doesn't work (really).

So instead of looking into it further, I read a lot about the three big bundlers in comparison. Correct. Three bundlers. Because one bundler was not mentioned until just now: Parcel.

Parcel to the rescue!

For once, Parcel does exactly what it's supposed to. Parcel's special feature is that it automatically recognizes most file formats and handles them accordingly.

CSS should be precompiled by PostCSS?

No problem: Just select a CSS file, Parcel will do the rest if a PostCSS config is available.

JS to be chased through Babel?

.babelrc. The rest is done by Parcel.

The docs are nice and clear and quickly understood. The CLI works great and in the end after hours (4/5 of the time with webpack/rollup) I had my complete build process done in minutes:

First, I wanted to build my demo site in webpack with the simple yarn build-demo command. In the package.json:

"scripts": {
	"build-demo": ``webpack -p --mode production``
}

Parcel workflow via npm scripts.

Since Parcel minimizes by default, I wanted to bundle my JS part of the module minified in ./lib first:

"build-module-js-min": "parcel build src/js/libraries/fixedScrollNav.js --no-source-maps -d lib/js --out-file fixedScrollNav.js",
  • parcel build --> parcel task via CLI
  • src/js/libraries/fixedScrollNav.js --> path of my module
  • --no-source-maps --> No source maps, because it is the finished module.
  • -d lib/js --> Output path.
  • --out-file fixedScrollNav.js --> filename.

The same for CSS:

"build-module-css-min": ``parcel build src/css/bits/_fixedScrollNav.scss --no-source-maps -d lib/css --out-file fixedScrollNav.min.css``,

After that, I combine the two tasks:

 "build-module-min": yarn build-module-js-min && yarn build-module-css-min",
        "build-module-js-min": "parcel build src/js/libraries/fixedScrollNav.js --no-source-maps -d lib/js --out-file fixedScrollNav.min.js",
        "build-module-css-min": "parcel build src/css/bits/_fixedScrollNav.scss --no-source-maps -d lib/css --out-file fixedScrollNav.min.css",

To get the unminimized code, only the --no-minify flag must be supplied:

"build-module-unminified": "yarn build-module-js-unminified && yarn build-module-css-unminified",
        "build-module-js-unminified": "parcel build src/js/libraries/fixedScrollNav.js --no-source-maps -d lib/js --out-file fixedScrollNav.js --no-minify",
        "build-module-css-unminified": "parcel build src/css/bits/_fixedScrollNav.scss --no-source-maps -d lib/css --out-file fixedScrollNav.css --no-minify",

Since I want to get both outputs when building I merge the tasks into build-module.
build-module: yarn build-module-unminified && yarn build-module-min, `.

Done:

"scripts": {
    "start": "webpack-serve ./webpack.config.js",  
    "build-module": { "yarn build-module-unminified && yarn build-module-min",
      "build-module-unminified": "yarn build-module-js-unminified && yarn build-module-css-unminified",
        "build-module-js-unminified": "parcel build src/js/libraries/fixedScrollNav.js --no-source-maps -d lib/js --out-file fixedScrollNav.js --no-minify",
        "build-module-css-unminified": "parcel build src/css/bits/_fixedScrollNav.scss --no-source-maps -d lib/css --out-file fixedScrollNav.css --no-minify",
      "build-module-min": "yarn build-module-js-min && yarn build-module-css-min",
        "build-module-js-min": "parcel build src/js/libraries/fixedScrollNav.js --no-source-maps -d lib/js --out-file fixedScrollNav.min.js",
        "build-module-css-min": "parcel build src/css/bits/_fixedScrollNav.scss --no-source-maps -d lib/css --out-file fixedScrollNav.min.css",
    "build-demo": "webpack -p --mode production"
  },
  • This is mega verbose.

... but super good to understand right away.

  • It looks so ugly!

... but the indentations are for the hierarchy of the tasks

The whole effort for build processes is insane!

We should think about what we are doing here: It is about bundling some files. Nothing more. That can't and in my opinion shouldn't be that difficult. There must be something wrong, if we despair every time on Configs, which have the task to relieve us of work.

Somewhere something has gone wrong. With taskrunners, bundlers and what not, a huge effort is created for objectively simple tasks.
And about this sensefulness we can and should talk.

Therefore my call to all readers: Try KISS again: Keep it simple stupid. KISS - For more love and joy among developers!

Spread the love <3