Cannot import standard ES6 modules from npm
See original GitHub issueWhat
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.
- Webpack example: https://github.com/alphagov/govuk-frontend/tree/master/examples/webpack
- Rollup advice on modules https://github.com/rollup/rollup/wiki/pkg.module
- Microbundle https://github.com/developit/microbundle
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:
- Created 5 years ago
- Reactions:3
- Comments:26 (24 by maintainers)
Top GitHub Comments
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 customall.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 sameall.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:
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!
@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-frontendpackage/package.json
. I originally set this tofalse
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
totrue
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 setsideEffects
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 ourall.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
andgenerateUniqueID
) 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 kBNote: 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.