Main page

How to migrate your SPA from JSPM/SystemsJS to Webpack?


webpack jspm systemjs migration build optimization performance configuration english

Intro

JSPM logo Webpack logo

I've done couple projects with this task, so I think my experience which I'll describe in this post will helpful for someone too. Actually I want to write this post a bit early but still got some free time for it only now :)

What is JSPM and SystemJS?

SystemJS

SystemJS - is a module loader that can import modules at run time in any of the popular formats used today (CommonJS, UMD, AMD, ES6). It is built on top of the ES6 module loader polyfill and is smart enough to detect the format being used and handle it appropriately.

Github

JSPM

JSPM - is a package manager for SystemJS, based on ES6 module loader.

Github

What is Webpack

Webpack - is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph which maps every module your project needs and generates one or more bundles.

Github

Why?

I could to define next points why we have to migrate:

How?

Let's put a few steps.

Step 1

Replace all packages with npm registry (no github, bower, etc...).

Before:

{
  "jspm": {
    "devDependencies": {
      "babel": "npm:babel-core@^6.26.3",
      ...
    }
  }
}

After:

"devDependencies": {
  "babel-core": "^6.26.3",
  ...
}

That's means that as result you need to move all packages under jspm accordingly to dependencies and devDependencies and remove "jspm:{...}" block.

At this step you can remove jspm_packages directory. Instead of it you will start to use node_modules.

Note: on this step you can do your work granularly. Just commit PR over PR to your repo without any big conflicts with code of your colleagues.

Step 2

Step 2.1

Replace all jspm plugins by their webpack-plugin analogs.

Before:

import myText from './mytext.html!text'; // remove `plugin-text`

After:

import myText from './mytext.html'; // use html-webpack-plugin

Step 2.2

Re-write gulp scripts (if you have it).

Remove all part which bundle your app for SystemJS. Ideally you will get build pipeline which will not depends on Gulp at all (only Webpack). Sometimes it could be super hard or impossible to achieve that. Especially if your project is too big. In this case try to minimize work for gulp. For example let him build some independent part of your project.

Step 2.3

Change tsconfig.json (if you use TypeScript):

Before:

{
  "compilerOptions": {
    "module": "system",
  }
}

After:

{
  "compilerOptions": {
    "module": "commonjs",
    ...
  }
}

This change will switch your project build from SystemJS to CommonJS in my particular case. Or it could be one of another options such as CommonJS, AMD, UMD, ES6, ES2015 or ESNext.

So now you can remove system.js itself and all your dependencies (f.e file systemjs.config.js).

Step 2.4

Change index.html.

Remove any mentions of <script> tags with jspm config files and system.js. Instead of it you will use index.js bundle created by webpack and which was injected by him to index.html (if you setup your webpack config so).

Step 2.5

Be sure that your project works perfectly.

In this part I mean that you have to be sure that all components of your app loads fine. In my case it didn't work with first time because of some import's for 3rd part libraries and wrong linked components into project itself.

Note: Definitely the step 2 is the biggest step in this work. In this case you couldn't to push your code with partly functional. That's means that you need to merge every changes in your work and make it works. And of course that project is bigger than it will more painful.

After this step your project will get rid of many config files. Will become more readable and build time will extremely decrease. See my test benchmarks below.

Step 3

Setup tests. I've used Karma as test runner, so what I've need to do just replace karma plugins accordingly with my changes.

Fix in karma.config.js:

Before:

  ...
  frameworks: ['jspm', 'jasmine'],
  plugins: [
    'karma-systemjs',
    'karma-jspm',
    ...
  ],

After:

  ...
  frameworks: ['jasmine'],
  plugins: [
    'karma-webpack',
    ...
  ],

Profit!

Work is done. So it's time to enjoy some coffee numbers!

SPA Perf

Type SystemJS Webpack
Finish load JS files 13.06s 12.12s
DOMContentLoad 3.89s 1.5-2s
Load 4.26s 1.6-2.2s

Build performance

Conclusion

Migration could depends on many factors such as current project settings. So I understand they I couldn't to cover all cases. I've tried to describe how I've done it. Feel free to share your expirience in comments. And good luck with your project migrations.

Further Reading