ES2015 module imports in production

Josh Trout
USA TODAY NETWORK
Published in
2 min readApr 9, 2018

Two years ago, we began building the next generation of the USA TODAY NETWORK’s web framework. The front end of the framework uses web components heavily, but we expected there would always be some core, non-component JavaScript. Our plan was to write this core script as modular ES2015 classes, then use SystemJS as the polyfill method for importing, since no browser had native import support. We chose SystemJS since it was based on a proposed native implementation and because it offered a lot of flexibility.

Close to two years later, things progressed differently than we expected, which we had anticipated. The flexibility of SystemJS helped us at times, but that flexibility came at the cost of performance. We found few features that needed to exist outside web components in the core centralized JavaScript, so that performance penalty really wasn’t worth the cost. ES2015 module imports had been implemented in all modern browsers, but the implementation was significantly differently than SystemJS.

The dawn of a new era in JavaScript

The new standard syntax kept backwards compatibility in mind, unlike many new web platform features, so migration did not require any drastic changes. We only needed to make two small changes to our build process. One was to skip transpiling the core code through Babel. The second was to generate a fallback ES5 bundle for older browsers. For this, we added RollupJS to build the bundle, then passed the bundled code through Babel to transpile back to ES5. The final step was switching our base page template to directly import either the root module or the bundle.

<script type="module" src="https://cpt-static.gannettdigital.com/universal-web-client/master/latest/core/scripts/gallium.js" rel="preload"></script>
<script src="https://cpt-static.gannettdigital.com/universal-web-client/master/latest/core/bundles/gallium.js" defer nomodule></script>

The next big step for us will be migrating our web components from HTML Imports to ES2015 modules. That will enable the rest of our front-end code to see the performance gains associated with running native ES2015+ code over the existing transpiled code. The challenge is that our components are heavily dependent on dynamic loading so that we only deliver the code that is needed to a page. Dynamic import will allow for that architecture, but is only in production in Chrome at this point.

Moving from HTML Imports to ES2015 modules also means that the web platform no longer handles our dependency management. Most likely, we will need to move to using NPM bare module specifiers instead of Uniform Resource Location paths. This will keep us compatible with the direction Polymer 3 is headed. The other option is to use SystemJS so that modules can be dynamically imported by either path or bare module specifier on the client. Oh. We just removed that dependency…

--

--