Build Node Modules Like a Pro with Packer CLI

Yohan Gomez
10 min readJan 8, 2019

--

TL;DR: Packer CLI helps you to kickstart new node module projects compliant with NodeJS and Browser, prescribing best practices. Packer encapsulating file-watching, live-reloading, transpiling, bundling and unit test framework integration with coverage and much more, so you don’t have to. You will get to enjoy the latest JavaScript awesomeness with the flexibility to custom fit your project needs.

To do so, we provide a generator ecosystem via command line to scaffold complete projects with full control over all exposed workflows.

Packer CLI: https://github.com/yohangz/packer-cli

Why bother about the build process?

You might be wonder why we need a build process to compose a node module. There are several reasons why we can’t directly publish our JavaScript source code as is to NPM registry;

  • Latest ECMAScript and TC39 proposal cutting edge features can’t be used directly due to support & compatibility of your target environments.
  • Use of script preprocessors like TypeScript require compilation to plain JavaScript.
  • Style preprocessors like SASS/SCSS/LESS/Stylus etc,. require compilation to plain CSS.
  • Required to bundle CSS, images and other assets inline within JavaScript in certain cases.
  • Bundling source into flat modules & treeshaking (remove dead code) to optimize performance and bundle size.
  • Dependency mappings should be corrected prior to publishing.
  • Include minified artifacts for optimized overall bundle size.
  • Include SourceMaps for better debugging experience.
  • Additional transformation steps should be performed to support JSX and templating engines like Handlebars.

You might need at least one of the above functionality within your project. It is almost impossible to avoid having a build process unless all target platforms support all the features out of the box, which is highly unlikely.

Why not use all the tooling readily available?

Have you ever published a node module to NPM registry? If so, you might already know that it is a headache to setup the development environment with all the build tasks prior to crafting the actual project source code.

I myself went through this several time as I maintain few libraries myself. Some of these modules are targeted to work in Web Browser or Browser like environment (Electron) while some of them are only targeted for NodeJS ecosystem hence, in certain cases I wanted to build libraries which are compliant with both NodeJS ecosystem and and Browser like environments in single source. It become extremely complex when you add all other tooling on top of the base build process which will improve development productivity and code quality. Preparing the build process itself is another mini project which may require around 20–30 development dependencies which are vastly changing over time.

In all the new projects I used the cutting edge technologies at the time and managed to get the build process implemented prior to actual project work which was a time consuming and a tedious task to understand and implement it to work as expected. In my very first project I used Grunt and it’s tooling, and then came Gulp. After some time I adopted Browserify and used gulp task runner to orchestrate the workflows and build node modules compliant with browser. Next big thing was Webpack which is super cool. Recently I stumbled across RollupJS which is the shiny new thing. This list grows on and on and I’m pretty sure that I will come across some other set of tools which are way better then what I used in previous projects.

In each of these iterations I managed to implement a new build process although, I was too lazy to convert the old build processes in my previous projects to the latest tech and most of the previously used libraries are deprecated. It is almost impossible to keep up.

When you think about it, some might argive that it is not required to update the build process when ever there is a new teach stack released. But on the other hand when you think about the performance aspects and bundle size improvements with tree shaking, it will be tempting to do so. Why not if it’s possible via a single dependency update rather than maintaining several development dependencies.

Motivation behind Packer CLI

With the most recent project I started thinking whether to spend some time and setup another build process with latest tooling or consolidate the knowledge I gathered throughout the year and build a CLI tool which will encapsulate all build ecosystem associated development dependencies and provide a common interface which can be easily used by any library developer without having to worry about whats going on underneath.

Basically I wanted to wrap the build process associated responsibilities in this tool and use it in all the library projects, whenever there is a build tooling update or dependency deprecation I can simply update the CLI tool which has a common interface where in target project is it just a matter of updating the CLI tool dependency. Pretty neat huh!

All most all modern frontend frameworks have their own CLI tooling which encapsulate the build process and provide a simple interface;

  • Angular CLI: Fully fledged development environment to build Angular applications and libraries.
  • Create React App: Fully fledged development environment to build ReactJS applications.
  • Vue CLI: Fully fledged development environment to build VueJS applications.

Packer CLI is a similar effort to encapsulate the build workflow of library node modules with whole lot of fancy features exposed out of the box.

Yet another tool huh?

Well, not actually. Are you building a node module which is;

  • Browser Compatible
  • NodeJS Compatible
  • Browser and NodeJS Compatible
  • NodeJS Command Line Tool
  • ReactJS Library

When you want a build workflow which support bundling the same source codebase to target multiple environments; Browser and NodeJS ecosystem compliant modules which seamlessly work with script preprocessors, style preprocessors, unit test frameworks with coverage reporting, style and script linting support, inline image and asset bundling, source minification, modern JS feature support with minimal bundle, etc… Packer will take away the pain of setting up development environment and provide you a simple CLI with comprehensive configuration support. It is equipped with all cutting edge tooling to improve build performance and productivity.

We take care of providing everything you need to get started without any hassle. Most importantly packer encapsulate the complexity of build process and expose a simple configuration file with granular level control while maintaining minimalism.

What we offer

  • Browser and Node support: Both Browser and Node environment target builds can be generated in parallel for maximum compatibility supporting all module loaders.
  • Managed build configuration: all build process associated configurations are exposed to enduser via .packerrc.js configuration file. Configuration inheritance is supported out of the box via extends config property. Additionally, explicit config file can be referenced via CLI argument.
  • Encapsulated build process: No need to worry about managing all the development environment dependencies and build workflow scripts like gulp tasks. We manage and keep them up to date for you while exposing a simple configuration interface.
  • Yarn support: Target project can be generated with yarn lock file.
  • Travis CI support: Travis continuous integration configuration out of the box.
  • Babel based code compilation: Babel is used to compile ES Next source to target ES version and include polyfills if required. Control over babel configuration is exposed via .babelrc file. You can use latest edge ES features today.
  • TypeScript support: Both TypeScript and Babel are used to compile source. TypeScript source is compiled to ESNext target JavaScript via Typescript compiler and then run through Babel compiler. Typescript configuration is exposed via tsconfg.json file.
  • Type definitions support: Generate type definition files for TypeScript based projects.
  • TSLint based Typescript code analysis: TypeScript source code static analysis is handled with TSLint. Standard linter configuration is exposed via tslint.json file
  • ESLint based Javascript code analysis: Plain JavaScript code static analysis is handled with ESLint. Standard linter configuration is exposed via eslint.json file.
  • Stylelint based style sheet code analysis: Style lint is used to statically analyze the style sheets codebase. Standard Stylelint configuration can be found in stylelint.yml file.
  • Precompiled handlebars templating: Packer supports handlebars templating out of the box. Templates are pre compiled and added to the target bundle to minimize the bundle size and improve performance.
  • Style preprocessor support: SCSS, SASS, LESS and Stylus style preprocessing via respective compiler tools.
  • PostCSS based stylesheet preprocessing: PostCSS configuration can be found in postcss.js file.
  • Inline style bundling support: Optional inline style bundling support with include stylesheets inline within target script. Styles will be injected to DOM on runtime.
  • Prettier based auto formatting support: Prettier integration is provided out of the box to auto format codebase.
  • Karma unit test runner: Karma unit test runner support with Jasmine and Mocha test frameworks for browser targeted modules.
  • Code Coverage Report: Code coverage report generation with IstanbulJS.
  • Unit test framework support: Standalone Jasmine, Mocha with Chai and Jest test framework support.
  • Rollup build process: Project build bundling is handled via RollupJS. Granular level configurability is provided via packer configurations to override plugin configurations and/or introduce additional plugins.
  • Multi Bundle Target: UMD, AMD, SYSTEM, IIFE and CommonJS bundle build output targets are supported. Additionally you can generate ES5 and ESNext bundles for the same source for extensive compatibility.
  • Gulp base task workflow: GulpJS is used to define task workflows under the hood.
  • React Library: Support compiling JSX and TSX source with Babel and TypeScript.
  • Node CLI Tool: Support building node CLI tools out of the box. Packer use itself to build and publish Packer CLI.
  • Package best practices: Bundled build include generated package configuration file adhering best practices.
  • Import path replace: Import path replace to handle environment specific conditional configuration.
  • Bundle dependencies: Support bundling none external dependencies within the target artifact. i.e: bundle Lodash within target artifact.
  • Ignore import: Ignore node specific imports like fs, path etc,. for browser target artifacts.
  • Copy static assets: Support copying specified static assets to distribution directory.
  • Banner comment: Custom banner comment inclusion support. Banner template can be update via .packer/banner.hbs file.

What’s under the hood

We use GulpJS task runner to orchestrate tasks with dependencies (i.e: Build task may require clean build directory, run multi target bundlers in parallel and copy static assets). RollupJS is used to compile script and generate bundle artifacts. All modern test frameworks are support with coverage reporting by invoking respective test framework CLI tools.

Packer is a SELF COMPILING BUILD PROCESS where it uses an older version of itself to build the latest source of Packer. Check out the packer source repo for more information.

I have seen similar tools out there

  • Yeoman: Yeoman is a general purpose generator ecosystem which will scaffold a project of preferred tech stack. Generated project will contain the full fledged build process associated code and you have to take the responsibility of understand & maintaining.
  • Create React Library: Create react library is a CLI tool specifically designed to build react library projects. However, Packer CLI has a lot more features including react library bundling support.

Future Plans

  • Further improve build performance.
  • Support AVA unit test framework support.
  • Generate none bundled artifacts.
  • Complete end to end unit test of Packer CLI.

Conclusion

Why bother setting up your own build process when Packer has all what you need? Use it and leave a comment for improvements and report bugs. Star the project if you thinks Packer is useful!

URL: https://github.com/yohangz/packer-cli

📝 Read this story later in Journal.

🗞 Wake up every Sunday morning to the week’s most noteworthy Tech stories, opinions, and news waiting in your inbox: Get the noteworthy newsletter >

--

--