From 9d04de1c8d3efb745cfcae3519cee016751b86ec Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Mon, 22 May 2017 06:06:06 -0700 Subject: Only load Intl data for current language (#3130) * Only load Intl data for current language * Extract common chunk only from application.js and public.js * Generate locale packs, avoid caching on window object --- config/webpack/generateLocalePacks.js | 52 +++++++++++++++++++++++++++++++++++ config/webpack/shared.js | 19 +++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 config/webpack/generateLocalePacks.js (limited to 'config/webpack') diff --git a/config/webpack/generateLocalePacks.js b/config/webpack/generateLocalePacks.js new file mode 100644 index 000000000..10a66e994 --- /dev/null +++ b/config/webpack/generateLocalePacks.js @@ -0,0 +1,52 @@ +// To avoid adding a lot of boilerplate, locale packs are +// automatically generated here. These are written into the tmp/ +// directory and then used to generate locale_en.js, locale_fr.js, etc. + +const fs = require('fs'); +const path = require('path'); +const rimraf = require('rimraf'); +const mkdirp = require('mkdirp'); + +const localesJsonPath = path.join(__dirname, '../../app/javascript/mastodon/locales'); +const locales = fs.readdirSync(localesJsonPath).filter(filename => { + return /\.json$/.test(filename) && + !/defaultMessages/.test(filename) && + !/whitelist/.test(filename); +}).map(filename => filename.replace(/\.json$/, '')); + +const outPath = path.join(__dirname, '../../tmp/packs'); + +rimraf.sync(outPath); +mkdirp.sync(outPath); + +const outPaths = []; + +locales.forEach(locale => { + const localePath = path.join(outPath, `locale_${locale}.js`); + const baseLocale = locale.split('-')[0]; // e.g. 'zh-TW' -> 'zh' + const localeDataPath = [ + // first try react-intl + `../../node_modules/react-intl/locale-data/${baseLocale}.js`, + // then check locales/locale-data + `../../app/javascript/mastodon/locales/locale-data/${baseLocale}.js`, + // fall back to English (this is what react-intl does anyway) + `../../node_modules/react-intl/locale-data/en.js`, + ].filter(filename => fs.existsSync(path.join(outPath, filename))) + .map(filename => filename.replace(/..\/..\/node_modules\//, ''))[0]; + + const localeContent = `// +// locale_${locale}.js +// automatically generated by generateLocalePacks.js +// +import messages from '../../app/javascript/mastodon/locales/${locale}.json'; +import localeData from ${JSON.stringify(localeDataPath)}; +import { setLocale } from '../../app/javascript/mastodon/locales'; +setLocale({messages, localeData}); +`; + fs.writeFileSync(localePath, localeContent, 'utf8'); + outPaths.push(localePath); +}); + +module.exports = outPaths; + + diff --git a/config/webpack/shared.js b/config/webpack/shared.js index 4986ea24d..1d75e2af2 100644 --- a/config/webpack/shared.js +++ b/config/webpack/shared.js @@ -10,15 +10,20 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); const extname = require('path-complete-extname'); const { env, paths, publicPath, loadersDir } = require('./configuration.js'); +const localePackPaths = require('./generateLocalePacks'); const extensionGlob = `**/*{${paths.extensions.join(',')}}*`; const packPaths = sync(join(paths.source, paths.entry, extensionGlob)); +const entryPacks = [].concat(packPaths).concat(localePackPaths); module.exports = { - entry: packPaths.reduce( + entry: entryPacks.reduce( (map, entry) => { const localMap = map; - const namespace = relative(join(paths.source, paths.entry), dirname(entry)); + let namespace = relative(join(paths.source, paths.entry), dirname(entry)); + if (namespace === '../../../tmp/packs') { + namespace = ''; // generated by generateLocalePacks.js + } localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry); return localMap; }, {} @@ -41,7 +46,15 @@ module.exports = { new ManifestPlugin({ fileName: paths.manifest, publicPath, writeToFileEmit: true }), new webpack.optimize.CommonsChunkPlugin({ name: 'common', - minChunks: 2, + minChunks: (module, count) => { + if (module.resource && /node_modules\/react-intl/.test(module.resource)) { + // skip react-intl because it's useless to put in the common chunk, + // e.g. because "shared" modules between zh-TW and zh-CN will never + // be loaded together + return false; + } + return count >= 2; + }, }), ], -- cgit