diff --git a/README.md b/README.md index da12c7c5cd..f4ff322e22 100644 --- a/README.md +++ b/README.md @@ -527,5 +527,3 @@ It should appear on the map as you refresh your local browser. - `ERROR: for X Cannot create container for service X: Invalid bind mount spec "": Invalid volume specification: ''`. If you get this error after running `docker-compose up` on Windows, you should tell `docker-compose` to properly understand Windows paths by setting the environment variable `COMPOSE_CONVERT_WINDOWS_PATHS` to `0` by running `setx COMPOSE_CONVERT_WINDOWS_PATHS 0`. You will also need a recent version of `docker-compose`. We have successfully seen this fix work with [v1.13.0-rc4](https://github.com/docker/toolbox/releases/tag/v1.13.0-rc4). More info here: https://github.com/docker/compose/issues/4274. - No website found at `http://localhost:8000`: This can happen if you're running Docker in a virtual machine. Find out docker's IP using `docker-machine ip default`, and replace `localhost` by your Docker IP when connecting. - -- When running `docker-compose up` you get the error: `Cannot read property 'BUNDLE_HASH' of undefined`. This can occur if your OS's default language is not english - since we by default only compile the english site. You can fix this by going into `web/package.json` and changing this line : `"watch-en": "webpack --watch --progress --mode development --config-name en"` to use the abbreviation for your system's language. ie, if your systems language is italian, you should change it to `"watch-en": "webpack --watch --progress --mode development --config-name it"`. diff --git a/docker-compose.yml b/docker-compose.yml index 526b80568d..cb15668551 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,7 +34,7 @@ services: - './web/topogen.sh:/home/web/topogen.sh' - './web/views:/home/web/views' - './web/webpack.config.js:/home/web/webpack.config.js' - web-watch-en: + web-watch: build: context: . dockerfile: web/Dockerfile @@ -43,7 +43,7 @@ services: - eu.gcr.io/tmrow-152415/electricitymap_web:staging - eu.gcr.io/tmrow-152415/electricitymap_web:latest image: eu.gcr.io/tmrow-152415/electricitymap_web:latest - command: npm run watch-en + command: npm run watch environment: - NODE_ENV=development volumes: diff --git a/mobileapp/generate-index.js b/mobileapp/generate-index.js index 205c9e67e5..5cbc78cd64 100644 --- a/mobileapp/generate-index.js +++ b/mobileapp/generate-index.js @@ -48,16 +48,6 @@ function getHash(key, ext, obj) { } return filename.replace('.' + ext, '').replace(key + '.', ''); } -const srcHashes = Object.fromEntries(locales.map((k) => { - const obj = JSON.parse(fs.readFileSync(`${STATIC_PATH}/dist/manifest_${k}.json`)); - const BUNDLE_HASH = getHash('bundle', 'js', obj); - const STYLES_HASH = getHash('styles', 'css', obj); - const VENDOR_HASH = getHash('vendor', 'js', obj); - const VENDOR_STYLES_HASH = getHash('vendor', 'css', obj); - return [k, { - BUNDLE_HASH, STYLES_HASH, VENDOR_HASH, VENDOR_STYLES_HASH, - }]; -})); // * i18n i18n.configure({ @@ -70,18 +60,21 @@ i18n.configure({ updateFiles: false // whether to write new locale information to disk - defaults to true }); +const template = ejs.compile(fs.readFileSync('../web/views/pages/index.ejs', 'utf8')); +const manifest = JSON.parse(fs.readFileSync(`${STATIC_PATH}/dist/manifest.json`)); + locales.forEach(function(locale) { i18n.setLocale(locale); - var template = ejs.compile(fs.readFileSync('../web/views/pages/index.ejs', 'utf8')); - var html = template({ + const html = template({ alternateUrls: [], - bundleHash: srcHashes[locale].BUNDLE_HASH, - vendorHash: srcHashes[locale].VENDOR_HASH, - stylesHash: srcHashes[locale].STYLES_HASH, - vendorStylesHash: srcHashes[locale].VENDOR_STYLES_HASH, + bundleHash: getHash('bundle', 'js', manifest), + vendorHash: getHash('vendor', 'js', manifest), + stylesHash: getHash('styles', 'css', manifest), + vendorStylesHash: getHash('vendor', 'css', manifest), isCordova: true, locale: locale, FBLocale: localeToFacebookLocale[locale], + locales: { en: localeConfigs['en'], [locale]: localeConfigs[locale] }, supportedLocales: locales, supportedFBLocales: supportedFacebookLocales, '__': function() { diff --git a/mobileapp/package.json b/mobileapp/package.json index 5d92fa0e70..1fe340eab5 100644 --- a/mobileapp/package.json +++ b/mobileapp/package.json @@ -60,4 +60,4 @@ "devDependencies": { "app-icon": "^0.13.1" } -} \ No newline at end of file +} diff --git a/web/package.json b/web/package.json index 13e3ada0ba..5cb4be7fe2 100644 --- a/web/package.json +++ b/web/package.json @@ -79,12 +79,11 @@ }, "scripts": { "build-debug": "webpack --bail --progress --mode development", - "build-release": "export NODE_ENV=production && cat locales-config.json| jq '.languageNames | keys[]' | xargs -L1 -I {} node_modules/.bin/webpack --mode production --bail --config-name {}", + "build-release": "export NODE_ENV=production && webpack --bail --mode production", "clean": "mkdir -p public/dist && rm public/dist/bundle.*.js", "lint": "eslint --quiet src", "server-dev": "nodemon server.js", "watch": "webpack --watch --progress --mode development", - "watch-en": "webpack --watch --progress --mode development --config-name en", "watch-poll": "webpack --watch --watch-poll --progress --mode development" }, "browserslist": [ diff --git a/web/server.js b/web/server.js index f384351824..f6fb860e7f 100644 --- a/web/server.js +++ b/web/server.js @@ -94,21 +94,8 @@ function getHash(key, ext, obj) { } return filename.replace('.' + ext, '').replace(key + '.', ''); } -const srcHashes = Object.fromEntries(locales.map((k) => { - try { - const obj = JSON.parse(fs.readFileSync(`${STATIC_PATH}/dist/manifest_${k}.json`)); - const BUNDLE_HASH = getHash('bundle', 'js', obj); - const STYLES_HASH = getHash('styles', 'css', obj); - const VENDOR_HASH = getHash('vendor', 'js', obj); - const VENDOR_STYLES_HASH = getHash('vendor', 'css', obj); - return [k, { - BUNDLE_HASH, STYLES_HASH, VENDOR_HASH, VENDOR_STYLES_HASH, - }]; - } catch (err) { - console.warn(`Warning: couldn't load manifest for locale ${k}: ${err}`); - return null; // Ignore - } -}).filter(d => d)); + +const manifest = JSON.parse(fs.readFileSync(`${STATIC_PATH}/dist/manifest.json`)); // * Error handling function handleError(err) { @@ -189,12 +176,13 @@ app.get('/', (req, res) => { } } }), - bundleHash: srcHashes[locale].BUNDLE_HASH, - vendorHash: srcHashes[locale].VENDOR_HASH, - stylesHash: srcHashes[locale].STYLES_HASH, - vendorStylesHash: srcHashes[locale].VENDOR_STYLES_HASH, + bundleHash: getHash('bundle', 'js', manifest), + vendorHash: getHash('vendor', 'js', manifest), + stylesHash: getHash('styles', 'css', manifest), + vendorStylesHash: getHash('vendor', 'css', manifest), fullUrl, locale, + locales: { en: localeConfigs['en'], [locale]: localeConfigs[locale] }, supportedLocales: locales, FBLocale: localeToFacebookLocale[locale], supportedFBLocales: supportedFacebookLocales, diff --git a/web/src/helpers/translation.js b/web/src/helpers/translation.js index ffedbf108e..68ab8a732f 100644 --- a/web/src/helpers/translation.js +++ b/web/src/helpers/translation.js @@ -1,19 +1,12 @@ -/* eslint-disable import/no-dynamic-require */ -/* eslint-disable global-require */ /* eslint-disable prefer-rest-params */ /* eslint-disable prefer-spread */ // TODO: re-enable rules -// Import locales required -const locales = { - en: require('../../locales/en.json'), - [locale]: require(`../../locales/${locale}.json`), -}; -const { vsprintf } = require('sprintf-js'); +import { vsprintf } from 'sprintf-js'; function translateWithLocale(locale, keyStr) { const keys = keyStr.split('.'); - let result = locales[locale]; + let result = window.locales[locale]; for (let i = 0; i < keys.length; i += 1) { if (result == null) { break; } result = result[keys[i]]; diff --git a/web/views/pages/index.ejs b/web/views/pages/index.ejs index 5067a263c1..1f4a66e301 100644 --- a/web/views/pages/index.ejs +++ b/web/views/pages/index.ejs @@ -68,6 +68,7 @@ var bundleHash = '<%= bundleHash %>'; var locale = '<%= locale %>'; var FBLocale = '<%= FBLocale %>'; + var locales = <%- JSON.stringify(locales) %>; var isCordova = <%= (typeof isCordova !== 'undefined' && isCordova) %>; diff --git a/web/webpack.config.js b/web/webpack.config.js index 7b914db30f..2bddbb6a03 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -6,18 +6,15 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const isProduction = process.env.NODE_ENV === 'production'; -const { languageNames } = require('./locales-config.json'); const { version } = require('./package.json'); -/* - Note exporting a config per language makes the build slower. - Sequential builds are faster (using jq and `--config-name`) -*/ -module.exports = Object.keys(languageNames).map(locale => ({ - name: locale, +module.exports = { devtool: isProduction ? 'sourcemap' : 'eval', - entry: { bundle: ['@babel/polyfill', './src/main.js'], styles: './src/scss/styles.scss' }, + entry: { + bundle: ['@babel/polyfill', './src/main.js'], + styles: './src/scss/styles.scss', + }, module: { noParse: /(mapbox-gl)\.js$/, rules: [ @@ -44,9 +41,6 @@ module.exports = Object.keys(languageNames).map(locale => ({ ], }, plugins: [ - new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, new RegExp(`/${locale}/`)), - // Only include current locale + en - new webpack.ContextReplacementPlugin(/locales/, new RegExp(`/${locale}|en/`)), new OptimizeCssAssetsPlugin(), new MiniCssExtractPlugin({ filename: '[name].' + (isProduction ? '[chunkhash]' : 'dev') + '.css', @@ -56,7 +50,7 @@ module.exports = Object.keys(languageNames).map(locale => ({ function () { this.plugin('done', (stats) => { fs.writeFileSync( - `${__dirname}/public/dist/manifest_${locale}.json`, + `${__dirname}/public/dist/manifest.json`, JSON.stringify(stats.toJson()) ); }); @@ -82,9 +76,7 @@ module.exports = Object.keys(languageNames).map(locale => ({ }, output: { // filename affects styles.js and bundle.js - filename: chunkData => (['styles'].includes(chunkData.chunk.name) - ? `[name].${isProduction ? '[chunkhash]' : 'dev'}.js` - : `[name].${isProduction ? '[chunkhash]' : 'dev'}.${locale}.js`), + filename: `[name].${isProduction ? '[chunkhash]' : 'dev'}.js`, // chunkFilename affects `vendor.js` chunkFilename: `[name].${isProduction ? '[chunkhash]' : 'dev'}.js`, path: `${__dirname}/public/dist`, @@ -94,4 +86,4 @@ module.exports = Object.keys(languageNames).map(locale => ({ node: { fs: 'empty', }, -})); +};