My Experience Refactoring JSPM/SystemJS to Using Webpack

Matthew Goo
8 min readSep 3, 2016

--

Developers and engineers alike constantly face the age old question of asking what tools do I use? What technology can I utilize to build my apps as quickly, efficiently, and smoothly as possible? The answer is quite simple: you never know until you actually try all the tools out there. But who has time for that?? All you really want to do is build an app. Well, I did have some time…So I’m writing here to share with you my findings on the differences between JSPM/SystemJS and Webpack and converting from one to the other.

What is Webpack and/or JSPM/SystemJS?

tl;dr: if you know what they are, feel free to skip this section

If you’re not familiar with JSPM/SystemJS or Webpack, they are both a set of tools to allow you to modularize frontend apps, and try to be a one-stop solution build tool. What does that mean? Well, in my experience, both have acted as my dev server, minifier, uglifier, ES6-ifier, and static assets manager just to name a few.

Webpack has a much greater following, and it has become the industry standard among frontend web apps for better or for worse. But because of this popularity there are so many plugins and loaders that already have been built for you. Essentially all you (the developer) are responsible for is filling in the blanks in the configuration file. This makes it super easy, since finding tutorials and examples on the web are so prevalent. If you are just starting out, I would suggest to take a read through this eBook, http://survivejs.com/webpack/introduction/.

JSPM/SystemJS has certainly gained in popularity and is the brain child of Guy Bedford. SystemJS is a module loader, and manages all your components and js packages. JSPM is the package manager that handles installing all those great 3rd party packages that we so rely on similar to NPM or Bower, but better! Over the course of the past 6 months, I’ve built 3 production apps using this set of tools, and have loved it. The thing that makes SystemJS great is that it is built to the ES6-specs. The idea behind this is that when ES6 is finally universally accepted, there will be a minimal amount of refactoring that you will need to do to your app. Another major benefit to using JSPM is that the 3rd party package that you want to install doesn’t have to be an actual package. It can live on Github, NPM, Bower, or in the JSPM registry. Which at first may not sound like much, but its actually so nice when you want to unify the way you manage all your packages. It really takes away the complexities that are associated with package managing.

The Process

How did I do it? Well it was actually super easy, but tedious. Along with JSPM/SystemJS I was using Gulp as the dev server and to copy my static assets to their respective places in my file system. I also had a few Gulp tasks to minify the javascript and css for production. All pretty standard stuff. Here is my Gulpfile in this Gist:

Gulpfile.js for SystemJS/JSPM

You don’t necessarily need Gulp/Grunt or some build tool. But it does clean it up a bit, and makes it much more human readable. I have also been lead to be believe that Gulp is faster, since its piping all the data, instead of being synchronous.

What also comes with it is a huge auto-generated config.js file, that is not as interesting, but is the configuration file for SystemJS and a map for all our packages and dependencies installed by our favorite JSPM. You can think of it as your package.json (for all your npm lovers). It may look like a lot at first, but all you really care about are the first 6 options:

  1. defaultJSExtensions: [boolean] allows the developer to ignore the .js extension in each import statement
  2. transpiler: the transpiler you so choose
  3. babelOptions: options you pass to the babel transpiler
  4. paths: where all your dependencies live
  5. baseUrl: the root of your app
  6. map: the map of your dependencies and 3rd party packages

The easy part in the refactor was removing these two files completely. So what replaced them? Well I had to add a new webpack.config.js file, which is the config for webpack. I also was able to completely replace Gulp’ responsibilities (dev server, the minifier, and static assets manager).

The main things you need to focus on in the webpack.config.js file are the loaders and plugins. This is the meat of the config file, and is where you define how to handle each file in your application. The most difficult thing for me that I still don’t really understand is the output.path and output.publicPath properties. If you get them incorrect then the app just won’t work, and yet I don’t see why you need both. Please comment or tweet me if you do.

The dev server was fairly easy to setup, but getting the file proxies to work took a lot of trial and error. I don’t think my answer is very intuitive, but it works. For example:

‘/static/img/logos’: {
target: `${localhost}:${PORT}`,
pathRewrite: {
‘/static/img/logos’: ‘/assets/images/logos’
}
}

The /static/img/logos is the source path the server should catch when a request is made. /assets/images/logos is the destination path it should replace it with. There is probably some shorthand version that looks a lot better, but it took me about 20 tries to get this correct.

Another great thing about Webpack is that you can just use a templating tool, such as html-webpack-plugin. This allows the developer to get rid of an index.html template where you include your js and css and such. The one weird thing when doing this is that you have to import your main app.scss file into your entry js file (index.js in my case). This is so that Webpack is aware of the styles you have, which makes sense, but is a change worth noting when comparing it to SystemJS.

Webpack with npm has the capability to act as the build tool for production, the dev server, and serve the production build. My file structure looks like this for those wondering:

|
| assets
- |images
_ | scripts
| fonts
| src
- | action-creators
- | api
- | components
- | middlewares
- | models
- | reducers
- | styles
- | 01-settings
- | 02-tools
- | 03-generic
- | 04-base
- | 05-objects
- | 06-components
- | 07-trumps
- | app.scss
- | index.hbs
- | index.js
| test
| webpack.config.js
| package.json
| karma.conf.js
| .babelrc (don't forget this)

And once I ran the build script (npm run build) it would build my static folder as so:

|
| index.html
| main.[hash].css
| bundle.[hash].js
| img
- | images
- | logos
- | icons
| fonts
- | font files
- | icon fonts

If you aren’t aware of npm scripts look into them! They really make your life and the rest of the developers on the project so much easier! They live in your package json and basically act as alias’s to run, build, and test your app. Here is a sample of mine:

“scripts”: {
“test”: “./node_modules/karma/bin/karma start karma.conf.js”,
“test:debug”: “./node_modules/karma/bin/karma start karma.conf.js — debug=true”,
“build”: “webpack -p — define process.env.NODE_ENV=’\”production\”’”,' “dev”: “webpack-dev-server — hot — inline”,
“dev:prod”: “webpack-dev-server — define process.env.NODE_ENV=’\”production\”’”
},

Say for example you wanted to run your tests. You would just run `npm run test`, or `npm run test: debug` if you wanted to run in chrome or some browser other than phantom. If you wanted to build you would run `npm run build`, which would minify your files. And if you wanted to run your dev server its `npm run dev`.

styles

In order for the sass to work I had to replace all the jspm: prefixes to ~, which is as easy find/replace, and pretty much everything worked after then. So if you were importing some files like:

@import “jspm:inuit-functions/tools.functions”;
@import “jspm:inuit-mixins/tools.mixins”;

you would change it to

@import "~inuit-functions/tools.functions";
@import "~inuit-mixins/tools.mixins";

Really easy!

tests

Tests on the other hand was just as challenging as filling in the blanks for the webpack.config.js file. I basically created a small webpack.config within the the karma.conf, and had to make sure to include all the karma plugins that I was using. But after doing the first webpack.config.js file, I felt really comfortable doing the karma.conf although it was much simpler.

What Do I Prefer?

If you’re still with me and have read up until here, you probably don’t care too much about my opinion. I get it…But I’m saying it anyway. JSPM and SystemJS have a lot going for it. Its very easy to setup, minimal learning curve, and is the package manager of the future. But the downside is in the build step. Every time you make a change it has to build the entire app. It doesn’t matter so much if your app is really small, but once you have a couple API calls and a few pages in your SPA, you might as well be doing your laundry in the mean time. If you have livereload it gets super annoying. I actually removed that feature while developing.

Which leads me to my preference, Webpack. Its the most popular tool for a reason. When developing there is no comparison. You could have a 100 files or a million files, and it would still compile just the same with every change (unless you changed all million files). What I’ve read is that it takes your diff and only compiles those one or two files and adds it back into the bundle, which is why its so much faster. The config is hard to learn, which is the reason it took about a week to convert the projects. I think in the end this is well worth its time. Saving 5–10 seconds every time you make a change may not sound like a lot, but I think it really brings up your focus when troubleshooting/debugging. There are also a lot of plugins made for Webpack, which makes the tool that much more valuable. For example hot reloading or autoprefixing are two things well worth the refactor. I don’t have a huge amount of experience in using either, but instantly I’m able to see a use for both. Hot reloading you never have to refresh the page, which makes it so much faster to develop. Autoprefixer allows the dev to never have to worry about vendor prefixing. Sure its a tiny issue, but its easy to integrate and allows you to write css as if you’re living in the future (which is sexy).

All in all if I were to go back in time, I would start off using Webpack. Its harder to learn and may not be the end all tool, but the community and the tools that come along with it are what make it worthwhile. While learning and reading other people’s how to blogs, take a walk away from the computer screen. Over half of my issues while learning Webpack were resolved from doing just that. Simply most of the issues was a spelling issue (missing a s or misspelled some camelCased word). And to be honest, its nice getting rid of Gulp/Grunt. That’s a whole other API that you have to learn and become accustom to that no one really wants to learn. All we want to do is code, and that’s exactly what Webpack allows a developer to do. Eat, sleep, code, repeat; That’s what we’re all here to do.

--

--