Skip to content

Instantly share code, notes, and snippets.

@gilmoreorless
Last active January 21, 2019 22:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gilmoreorless/30d77f9fbb58623a1e4d5609b4b61d56 to your computer and use it in GitHub Desktop.
Save gilmoreorless/30d77f9fbb58623a1e4d5609b4b61d56 to your computer and use it in GitHub Desktop.
Webpack helper for moment-timezone data

This is outdated!

The content of this gist has been superseded by a new proper plugin for webpack: https://github.com/gilmoreorless/moment-timezone-data-webpack-plugin

The original contents of the gist are kept below for context, but I encourage people to use the plugin instead.


This is a custom helper script I wrote for a project’s Webpack build. It reduces the amount of time zone definition data loaded by moment-timezone. This helps reduce the size of the JS bundle loaded in a browser.

The project only needed time zone data for Australia and New Zealand from 2016 onwards. Stripping down the data as much as possible reduced the gzipped data size from 23KB to 0.4KB (and the raw, unminified size went from 176KB to 1.3KB).

This script is provided here as an interim answer to iamakulov/moment-locales-webpack-plugin#17

⚠️ BE WARNED: This has only been tested with one specific project setup, with a specific set of requirements. There is zero guarantee that it will work for a different scenario.

I intend to turn this into a proper Webpack plugin with greater flexibility (and actual tests). But this raw script can be helpful to some people until then.

Usage

The file exports a new NormalModuleReplacementPlugin instance based on the data configuration. Therefore it can be require()d directly into your Webpack config file:

// webpack.config.js
module.exports = {
  // [your standard Webpack config goes here]
  
  plugins: [
    require('./exclude-moment-timezone-data'),
  ],
};
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const sourceData = require('moment-timezone/data/packed/latest.json')
const fileName = 'moment-timezone-data.json'
// `build` is the configured Webpack output directory
const filePath = path.resolve(`build/${fileName}`)
const requiredZones = ['Australia/', 'Pacific/Auckland', 'Etc/UTC']
const yearStart = 2016
const yearEnd = new Date().getFullYear() + 10
/**
* Take the full moment-timezone data set and filter it down to only the data
* we need (Aus/NZ since 2016). This massively reduces how much raw time zone data
* is sent to the browser.
*/
function filterData() {
const moment = require('moment-timezone/moment-timezone-utils')
const newZonesData = sourceData.zones
.filter(
zone => requiredZones.findIndex(prefix => zone.startsWith(prefix)) !== -1
)
.map(moment.tz.unpack)
const filteredData = moment.tz.filterLinkPack(
{
version: sourceData.version,
zones: newZonesData,
links: [],
},
yearStart,
yearEnd
)
fs.writeFileSync(filePath, JSON.stringify(filteredData, null, 2))
}
function needsFiltering() {
if (!fs.existsSync(filePath)) {
return true
}
// Make sure our previously-built data matches the current data version in moment-timezone
const cachedData = require(filePath)
return (
!cachedData ||
!cachedData.version ||
cachedData.version !== sourceData.version
)
}
module.exports = new webpack.NormalModuleReplacementPlugin(
/data\/packed\/latest\.json$/,
resource => {
if (resource.context.match(/\/moment-timezone$/)) {
if (needsFiltering()) {
filterData()
}
// New request location is relative to moment-timezone/index.js
resource.request = `../../build/${fileName}`
}
}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment