How to migrate your SPA from JSPM/SystemsJS to Webpack?
webpack jspm systemjs migration build optimization performance configuration english
Intro
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.
JSPM
JSPM - is a package manager for SystemJS, based on ES6 module loader.
-
Allows you to download all module formats (ES6, AMD, CommonJS and Globals) directly from npm or Github with dependency management. Also allows you to use any non-standard sources of modules implemented through the Registry API.
-
Development mode: Load ES6 modules as separate files, and compiles them directly on browser.
-
Production mode: Build modules in one or more bundles, with a single command to run the entire application.
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.
Why?
I could to define next points why we have to migrate:
- Decrease build time of our application. (It was the main cause).
- Also
jspm install
takes much more times thannpm install
. - Many config files for SystemJS and JSPM. For Webpack you can use just one main config file, and you can use some separate config files for specific builds using inheritance and merge them.
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
gulp build
+ systemjs/jspm = 6.56+ minsgulp build
+ webpack + typechecking = 3.57minsgulp build
+ webpack = 1.38 mins
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.