It seems like every web project I do involves interacting with time, which inevitably evolves into dealing with multiple timezones. I always go down the road of trying to use the native Javascript Date object, but it never fails that it is not robust enough – even with the new’ish Intl.DateTimeFormat
MomentJS to the rescue
MomentJS is great, Moment Timezone is even better. It does everything you should ever need when working with dates and/or time zones.
Moment and Moment timezone can be bloated
Moment supports TONS of locales. Awesome, yes but also large as it includes all them by default. Moment timezone supports TONS of timezones, and all their changes over the years. Awesome, yes but also large as it includes this large matrix of timezones and their idiosyncrasies over time (and in the future).
Here is an example of an Angular production build of a simple web-application that uses the default setup of Moment and Moment timezone. Lets build with:
ng build --stats-json --prod --build-optimizer --delete-output-path --aot --output-path=dist
ec2944dd8b20ec099bf3.js (runtime) 1.41 kB [entry] [rendered]
chunk {1} main.a669168c0ae7b41b368c.js (main) 2.07 MB [initial] [rendered]
chunk {2} polyfills.c6871e56cb80756a5498.js (polyfills) 37.5 kB [initial] [rendered]
chunk {3} styles.d121423864e1eb24cdc1.css (styles) 63.1 kB [initial] [rendered]
WARNING in budgets, maximum exceeded for initial. Budget 2 MB was exceeded by 170 kB.
See that main
is 2.07 MB? Yikes! That will gzip down, but still way bigger then we want for a simple web application.
Figuring out what’s wrong
Noice the --stats-json
param in the ng build
above? It allows us to use an awesome tool called webpack-bundle-analyzer Simply run the following after running your build:
webpack-bundle-analyzer ./dist/stats.json
This will open up a web browser with a graph that looks like this

All the big boxes above (bigger means more bytes) are moment related. But we already kinda figured that…
Including only what we need
The moment docs and googling moment typescript moment angular will tell you to include moment like so:
import * as _moment from 'moment-timezone';
Note here I only include moment-timezone
, as it has moment bundled inside of it. By default when I build this ALL timezones and ALL locales will be bundled in my build (as reflected in the bundle-analyzer graph above).
Step 1 is to not include ALL the timezone data. Change the import to:
import * as _moment from 'moment-timezone/builds/moment-timezone-with-data-2012-2022.min';
This will include all the timezone data for 2012-2022. Of course if your requirements don’t fit inside these dates you are stuck, but if they do it will save you lots of bytes.
Step 2 is to only include the locale(s) you care about. In my case I’m lucky enough to only need en-us
for my simple web application. To do this we will use @angular-builders/custom-webpack to allow customization of the ng build
webpack’ing.
yarn/npm install @angular-builders/custom-webpack, then set your angular.json
‘s, architect.build.builder
attribute to be @angular-builders/custom-webpack:browser
Then add the following object to the options
object:
"customWebpackConfig": {
"path": "./extra-webpack.config.js",
"replaceDuplicatePlugins": true,
"mergeStrategies": {
"externals": "prepend"
}
}
Now create a extra-webpack.config.js
at the root of your Angular project with the following contents:
'use strict';
const webpack = require('webpack');
// https://webpack.js.org/plugins/context-replacement-plugin/
module.exports = {
plugins: [new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en-us/)]
};
Lets see if it paid off
ng build --stats-json --prod --build-optimizer --delete-output-path --aot --output-path=dist
Produces:
chunk {0} runtime.ec2944dd8b20ec099bf3.js (runtime) 1.41 kB [entry] [rendered]
chunk {1} main.4ec69d3753f8d4c43048.js (main) 962 kB [initial] [rendered]
chunk {2} polyfills.c6871e56cb80756a5498.js (polyfills) 37.5 kB [initial] [rendered]
chunk {3} styles.d121423864e1eb24cdc1.css (styles) 63.1 kB [initial] [rendered]
962 kB? Very Nice!

PS – don’t forget to gzip those ng build
generated static resources!
Hello, you are missing a ‘}’ in your angular.json “options” snippet :]