Angular CLI and Moment.js: A recipe for disaster … and how to fix it.
September 20, 2018
Beware: Angular CLI 6 makes it impossible to use Moment.js!
When I wrote about
“To use Angular CLI or not?”,
I claimed that there was not much risk involved in starting a project with
Angular CLI, since ng eject
allowed you to change your mind later and jump to
a vanilla Webpack setup.
This has changed since AngularCLI 6: the eject
command is now disabled.
Relying on Angular CLI has just become a much bigger risk for your project.
When I wrote about
“Angular vs. React: The CLI”
I claimed that I have not yet had a mandatory reason to eject
. In the meantime
I have come across several cases where the is a need to modify the webpack
config of an Angular CLI project, which could be achieved witheject
… but not
any more.
One reasons is an integration with three.js. Many
three.js extension rely on the global variable THREE
.
The typical solution
in a webpack build is to expose THREE
globally
via webpack config… bad luck,
with Angular CLI v6 you don’t have that option any more. Other solutions
are much more hacky
…
Another nasty example where you typically need access to the webpack configuration is when you want to use the popular library Moment.js.
Let me illustrate the problem:
1npx @angular/cli@6.1 new my-project2cd my-project3npm i moment @types/moment
Now use Moment.js in your project, i.e. in main.ts
:
1import * as moment from 'moment'2console.log(moment())
Now run the build and have look at the bundle:
1npm run build -- --prod --stats-json2npx webpack-bundle-analyzer dist/my-project/stats.json
You get the following scary picture:
The main bundle of your application has a size of 498 KB of which Moment.js is 329 KB! The biggest part of Moment.js consists of a bunch of locales, which you most probably do not need!
Of course this is a shortcoming of Moment.js in combination with webpack. This is not inherently a problem of the Angular CLI. However Moment.js is a very popular library, many Angular projects want/need to use it. Maybe only because some other library depends on Moment.js (many do!).
There is an easy fix for the problem: how-to-optimize-momentjs-with-webpack. However you need to modify the webpack config… which is not possible in a plain Angular CLI project! Bummer!
The answer of the Angular CLI is: that this is unfortunate, but they can’t deal
with such special cases… bummer again! Note: create-react-app
accepts that
Moment.js, as a very common library, deserves special handling and solves the
problem out of the box.
At this point your project has a problem…
Of course the JavaScript ecosystem has a solution for everything:
Monkey patch node_modules with https://t.co/p7p7L5FtDi
— Wayne Maurer (@waynemaurer) August 22, 2018
… but I don’t like that a “state-of-the-art” framework forces me into hacks like this.
A solution (sort of …)
https://t.co/1ObTgoXZ2L use this if you want to override config for some library without ejecting.
— Rob Wormald (@robwormald) August 22, 2018
With ngx-build-plus you can change the webpack configuration in an Angular CLI project without ejecting.
(Note: The section below was updated on 2018–12–29 for Angular CLI 7.1.4)
In the example from above you can do the following:
1ng add ngx-build-plus
Add a file webpack.extra.js
in the root of your project:
1const webpack = require('webpack')2module.exports = {3 plugins: [new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)],4}
And run:
1npm run build -- --prod --stats-json --extra-webpack-config webpack.extra.js2npx webpack-bundle-analyzer dist/my-project/stats.json
Yay! All the locales have disappeared from the bundle:
You have now solved the problem! … But did you consider the price of the solution?
At best I can congratulate someone for quickly and simply solving a problem on top of the shit that they are given. The only software that I like is one that I can easily understand and solves my problems. - > Ryan Dahl on Software
Yup, ngx-build-plus
is yet another “arcane” library you now depend on. Are you
prepared to maintain that library yourself?