Codementor Events

How to code like playing LEGO™

Published Jun 13, 2018Last updated Dec 10, 2018
How to code like playing LEGO™

Modularity is a big trend and I'm not the first to hop on this train. Today, I'm going to show you how easy you can build a multi-module app with vanilla Javascript and some awesome tools.

Ingredients

First of all, I'm going to assume you know a few things beforehand :

  1. Object Oriented Programming
  2. How to write JS
  3. Basics of NPM

Steps

The ground

Lets start with an empty directory for your project (we'll name it unicorn) and initialize it

npm init

and create the main file index.js with an old-school JS class

function Unicorn(name) {
  this.name = name;
}
Unicorn.prototype = {
  shine: function() {
    // All kind of good stuff here 🦄
  }
}
var dazzle = new Unicorn("Dazzle");
dazzle.shine();

Decoupling

Now imagine that you want to use the Unicorn class in another project, or just open-source it to the Humanity. You could create another directory with another repo, but let's be smarter. The Unicorn class is so linked to the Unicorn project that we'll use NPM scoped package name for clarity.

All that reduce index.js to 3 lines of codes.

import Unicorn from "@unicorn/model";
var dazzle = new Unicorn("Dazzle");
dazzle.shine();

Next, we create a sub-directory for our module.

mkdir packages/model
cd packages/model
npm init # and name it @unicorn/model

Which will have an index.js too with the class inside it. Since we left the plain browser JS with import/export statement, why not use the beautiful ES6 class syntax.

export default class Unicorn {
  constructor(name) {
    	this.name = name;
    }
    shine () {
    	// All kind of good stuff here 🦄
    }
}

At that point, the import statement is targeted at a package name that should be installed under the node_modules sub-directory. We could use a relative path like import Unicorn from "./packages/model/index.js";. What could be better is to create a link between packages.

Thankfully, npm can do that for you with the link command. Here's what it looks in our case.

cd packages/model
npm link
cd ..
npm link @unicorn/model

Perfect !
Perfect

Wrapping

Ok nice one, but now I can't use it in my browser, you dumbo !

First, how are you calling me ?
Then yeah, I know, for now it's all experimental syntax and stuff, but there's tools to handle it for you. I like to use webpack with babel, of course, it's not the only solution.

Adding some package on project's root.

npm install --save-dev babel-loader babel-core babel-preset-env webpack

The whole webpack configuration could fill another article, so I'll just show one that work. Set a new file called webpack.config.js with some instructions inside.

module.exports = {
    entry: "./index.js", // Main file to read
    module: {
        rules: [{
            test: /\.js$/, // For all file ending with ".js"
            use: {
                loader: "babel-loader", // Use babel
                options: {
                    presets: ["babel-preset-env"],
                },
            },
        }],
    },
    output: {
        filename: "dist/unicorn.js", // Output the result in another file
        library: "Unicorn", // Under "Unicorn" namespace
        libraryTarget: "this",
        libraryExport: "default",
    },
};

Then, if you run npx webpack it will build all your sources into one file usable by plain web browser.

Managing

You can now create lots of sub-modules and wrap them all in one file. You can even have sub-sub-modules and so on. Just put them all in the packages directory.
As your project grows, it'll be harder and harder to manage all this menagerie.

That where lerna come into play.

npm install -save-dev lerna

Think of it as a npm link on steroids.
Check out the full documentation on the project page, but here's a few useful commands.

npx lerna clean # Remove all node_modules directories
npx lerna bootstrap # Install remote dependencies and link local ones
npx lerna add package # Install a package to all sub-modules
npx lerna add package --scope=sub-module # Install a package to a specific sub-module
npx lerna publish # Bump, tag and publish all your modules over NPM

You should now be on track to write the most elegant project possible. I'm counting on you 😉

If you want more in-depth examples, I'm currently building yet another JS drawing library using the very same techniques.

See ya.

Discover and read more posts from Guillaume Martigny
get started
post commentsBe the first to share your opinion
Keyla Daviz
6 years ago

Hi, I got error when trying run webpack. It say “ERROR in ./index.js
Module not found: Error: Can’t resolve ‘@unicorn/model’ in bla bla bla …”

Guillaume Martigny
6 years ago

Hi Keyla,
In my example, the import statement is targeted at "@unicorn/model". When it’s a package name (as it is), webpack look for it into the node_modules sub-directory. So you have two solutions here:

  • Change the import to a relative path like `"./packages/model/index.js"
  • Or better, add a link in node_modules

You can add a link with the npm link command or with lerna.
Run this at your project root:

npm install -save-dev lerna
npx lerna bootstrap
Guillaume Martigny
6 years ago

By the way, you’re right, this part is not clear in my article. Thanks for your feedback, I’ll edit this part.

Peace

Keyla Daviz
6 years ago

Cool, now it’s work great. thanks

Show more replies