question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot import standard ES6 modules from npm

See original GitHub issue

What

At the moment if you try to import using our documentation using a standard ES6 bundler such as Rollup it will fail.

This is because we ship our bundles as UMD, which is great for browser and CommonJs support but not ES6 Modules (better for build pipelines).

This means our current guidance around rollup is misleading and only works when compiling from source.

We could consider adding more real world examples that import the package directly to ensure what we recommend is tested.

I’m not sure if we should be publishing these as .mjs files, which seems to be what Node.js is going towards.

Why

Some users rely on getting modules directly from /src, which we don’t recommend and don’t want to encourage. Many of these users say they’re running outdated versions. We should make it easier for them to import as standard ES6 modules.

Done when

  • Test including modules directly from /src
  • Research into type: module in the package.json
  • Test in some dummy apps/services
  • Automated testing
  • Implement decided approach
  • Do a pre-release and share with the community to make sure this solves the problems (try and reach out to those we know are going directly to /src)
  • Documentation
  • Raised a PR for using this in the Design System

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:3
  • Comments:26 (24 by maintainers)

github_iconTop GitHub Comments

3reactions
gunjamcommented, Mar 5, 2021

In our project we use very few govuk-frontend js modules: Button, Radios, Checkboxes, ErrorSummary, that’s about it. So to save on the bundle size I made a custom all.js file that only imports the components I need. The other reason we do this is that we have some custom components which use the same polyfills (and one that reuses Button) which can also be added to the same all.js file. The tree shaking will avoid bundling the same polyfills or components twice, resulting in a single small js bundle.

Unforuntatley the only way to achieve this is to add this Github repo as a npm depency, as the unbundled source is not included in the npm package and using the individually bundled components does not take advantage of tree shaking, bloating out the total bundle size.

This also presents us with some problems:

  • The version of the Github repo is not always accurately reported by the ‘out of date’ check in our CI pipeline so it’s always yellow with a warning
  • The Github repo package.json requires specifically node version 12 preventing us from updating to current LTS version 14 (the npm install fails)
  • govuk-frontend is already a subdepency of a DWP package meaing we’re effectively installing everything twice, with the nunjucks macros being the loaded from the subdepency but the client side js bundled from the source repo. Keeping these versions the same is a faff
  • This is clearly a messy hack

So in an ideal world the unbundled component js would be included in the govuk-frontend npm package in a way in which it could be imported as an ES6 module. This could also allow serving the ES6 modules directly over HTTP2 in the future, falling back to the bundle.

I’d be happy to help on the implementation of this if an approach could be agreed.

Thanks!

2reactions
vanitabarrettcommented, Apr 4, 2022

@domoscargin and I have been testing this approach with the following bundlers: Webpack; Parcel; Rollup; esbuild.

Setting sideEffects

The biggest change we’ve made since my last comment is setting sideEffects in the govuk-frontend package/package.json. I originally set this to false when first prototyping approaches to this card, for unknown reasons (most likely copied from an example without giving it much thought).

However, @domoscargin noticed when he was testing that polyfills were being ignored and weren’t being bundled. Having read https://sgom.es/posts/2020-06-15-everything-you-never-wanted-to-know-about-side-effects/, I came to the conclusion that we needed to set sideEffects to true because of the way we import polyfills - we import them and rely on them being there without having to ‘call’ them, which means our code has ‘side effects’. A bundler might otherwise exclude these because it thinks the imported code isn’t being referenced and therefore isn’t needed. I’ve gone one step further and actually set sideEffects to "govuk-esm/vendor/**” because I think these are the only JavaScript files that we use in this way.

I’ve updated the pre-release with this change and tested with all the bundlers listed above. All output JavaScript now seems to correctly include polyfills and only includes them once even if they’re imported by multiple components (tree-shaking).

common.mjs

As discussed on Slack, we’ve decided not to export the methods included in common.mjs in our all.mjs file. These are internal methods which were never intended to be made ‘public’, despite people importing them at the moment in the way we currently ship our JS as UMD probably because it’s convenient and there’s nothing to stop them from doing that. As this is a new feature, we’re not going to include the functions in that file (nodeListForEach and generateUniqueID) as an export in our ES modules.

Stats

Original UMD bundle in package/govuk: 96.01 kB Rollup: 55.98 kB Webpack: 76.05 kB Parcel: 36.14 kB (minified) esbuild: 42.76 kB

Note: variations in file size should be down to different config setups, there might be config tweaks/changes our users can make to bring that file size down even further.

Draft govuk-frontend PR

Updated pre-release branch

Test app for Webpack; Rollup; Parcel; esbuild Note: the commit history hasn’t been updated with the latest pre-release yet. Run npm install --save "alphagov/govuk-frontend#202c4c6f82b13dd6a06183380096c0e78933d5e0 before testing with that app.

Design System branch

Prototype Kit branch (to test backwards compatibility)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Unable to import module in nodejs using ES6 Modules
By default, Node JS uses modules according to the CommonJS standard. import - is an ES6 standard. You need to configure package.json for...
Read more >
How to use ES6 import syntax in Node.js - DEV Community ‍ ‍
An ES6 import syntax allows importing modules exported from a different JavaScript ... Node.js uses the CommonJS standard to import modules.
Read more >
CommonJS vs. ES Modules: Modules and Imports in NodeJS
With ES Modules, imports are static, which means they are executed at parse time. This is why imports are “hoisted”. They are implicitly...
Read more >
JavaScript modules - MDN Web Docs
This guide gives you all you need to get started with JavaScript module syntax.
Read more >
Avoid these issues when using new ECMAScript modules in ...
Es6 modules now have full support in Node.js 12 and above so it's time ... with your published module where a tool can't...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found