Skip to content

Commit

Permalink
* Ensure updated locales are auto-reloaded in electron renderer dev mode
Browse files Browse the repository at this point in the history
  • Loading branch information
PikachuEXE committed Sep 24, 2023
1 parent 825aa4e commit e2f4665
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 42 deletions.
103 changes: 63 additions & 40 deletions _scripts/ProcessLocalesPlugin.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { existsSync, readFileSync } = require('fs')
const { existsSync, readFileSync, statSync } = require('fs')
const { brotliCompress, constants } = require('zlib')
const { promisify } = require('util')
const { load: loadYaml } = require('js-yaml')
Expand All @@ -21,10 +21,11 @@ class ProcessLocalesPlugin {
}
this.outputDir = options.outputDir

this.locales = []
this.locales = {}
this.localeNames = []
this.activeLocales = []

this.cache = []
this.cache = {}

this.loadLocales()
}
Expand All @@ -37,66 +38,88 @@ class ProcessLocalesPlugin {

compilation.hooks.additionalAssets.tapPromise('process-locales-plugin', async (_assets) => {

// While running in the webpack dev server, this hook gets called for every incrememental build.
// While running in the webpack dev server, this hook gets called for every incremental build.
// For incremental builds we can return the already processed versions, which saves time
// and makes webpack treat them as cached
if (IS_DEV_SERVER && this.cache.length > 0) {
for (const { filename, source } of this.cache) {
compilation.emitAsset(filename, source, { minimized: true })
}
} else {
const promises = []

for (const { locale, data } of this.locales) {
promises.push(new Promise(async (resolve) => {
if (Object.prototype.hasOwnProperty.call(data, 'Locale Name')) {
delete data['Locale Name']
const promises = []
this.loadLocales(true)

Object.values(this.locales).forEach((localeEntry) => {
const { locale, data, mtimeMs } = localeEntry
promises.push(new Promise(async (resolve) => {
if (IS_DEV_SERVER) {
const cacheEntry = this.cache[locale]
if (cacheEntry != null) {
const { filename, source, mtimeMs: cachedMtimeMs } = cacheEntry
if (cachedMtimeMs === mtimeMs) {
compilation.emitAsset(filename, source, { minimized: true })
resolve()
return
}
}
}

this.removeEmptyValues(data)
if (Object.prototype.hasOwnProperty.call(data, 'Locale Name')) {
delete data['Locale Name']
}

let filename = `${this.outputDir}/${locale}.json`
let output = JSON.stringify(data)
this.removeEmptyValues(data)

if (this.compress) {
filename += '.br'
output = await this.compressLocale(output)
}
let filename = `${this.outputDir}/${locale}.json`
let output = JSON.stringify(data)

let source = new RawSource(output)
if (this.compress) {
filename += '.br'
output = await this.compressLocale(output)
}

if (IS_DEV_SERVER) {
source = new CachedSource(source)
this.cache.push({ filename, source })
}
let source = new RawSource(output)

compilation.emitAsset(filename, source, { minimized: true })
if (IS_DEV_SERVER) {
source = new CachedSource(source)
this.cache[locale] = { filename, source, mtimeMs }
}

resolve()
}))
}
compilation.emitAsset(filename, source, { minimized: true })

await Promise.all(promises)
resolve()
}))

if (IS_DEV_SERVER) {
// we don't need the unmodified sources anymore, as we use the cache `this.cache`
// so we can clear this to free some memory
delete this.locales
delete localeEntry.data
}
}
})

await Promise.all(promises)
})
})
}

loadLocales() {
const activeLocales = JSON.parse(readFileSync(`${this.inputDir}/activeLocales.json`))
loadLocales(loadModifiedFilesOnly = false) {
if (this.activeLocales.length === 0) {
this.activeLocales = JSON.parse(readFileSync(`${this.inputDir}/activeLocales.json`))
}

for (const locale of activeLocales) {
const contents = readFileSync(`${this.inputDir}/${locale}.yaml`, 'utf-8')
for (const locale of this.activeLocales) {
const filePath = `${this.inputDir}/${locale}.yaml`
// Cannot use `mtime` since values never equal
const mtimeMsFromStats = statSync(filePath).mtimeMs
if (loadModifiedFilesOnly) {
// Skip reading files where mtime (modified time) same as last read
// (stored in mtime)
const existingMtime = this.locales[locale]?.mtimeMs
if (existingMtime != null && existingMtime === mtimeMsFromStats) {
continue
}
}
const contents = readFileSync(filePath, 'utf-8')
const data = loadYaml(contents)
this.locales[locale] = { locale, data, mtimeMs: mtimeMsFromStats }

this.localeNames.push(data['Locale Name'] ?? locale)
this.locales.push({ locale, data })
const localeName = data['Locale Name'] ?? locale
if (!this.localeNames.includes(localeName)) { this.localeNames.push(localeName) }
}
}

Expand Down
8 changes: 7 additions & 1 deletion _scripts/webpack.renderer.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const VueLoaderPlugin = require('vue-loader/lib/plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const ProcessLocalesPlugin = require('./ProcessLocalesPlugin')
const WatchExternalFilesPlugin = require('webpack-watch-external-files-plugin')

const isDevMode = process.env.NODE_ENV === 'development'

Expand Down Expand Up @@ -128,7 +129,12 @@ const config = {
new MiniCssExtractPlugin({
filename: isDevMode ? '[name].css' : '[name].[contenthash].css',
chunkFilename: isDevMode ? '[id].css' : '[id].[contenthash].css',
})
}),
new WatchExternalFilesPlugin({
files: [
'./static/locales/*.yaml',
],
}),
],
resolve: {
alias: {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"webpack-watch-external-files-plugin": "^2.0.0",
"yaml-eslint-parser": "^1.2.2"
}
}
36 changes: 35 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4453,6 +4453,17 @@ glob-to-regexp@^0.4.1:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==

[email protected]:
version "8.1.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^5.0.1"
once "^1.3.0"

glob@^10.2.5:
version "10.2.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-10.2.6.tgz#1e27edbb3bbac055cb97113e27a066c100a4e5e1"
Expand Down Expand Up @@ -6426,6 +6437,14 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==

[email protected]:
version "0.12.7"
resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==
dependencies:
process "^0.11.1"
util "^0.10.3"

pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
Expand Down Expand Up @@ -6808,7 +6827,7 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==

process@^0.11.10:
process@^0.11.1, process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
Expand Down Expand Up @@ -8358,6 +8377,13 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=

util@^0.10.3:
version "0.10.4"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
dependencies:
inherits "2.0.3"

util@^0.12.4:
version "0.12.4"
resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253"
Expand Down Expand Up @@ -8677,6 +8703,14 @@ webpack-sources@^3.2.3:
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==

webpack-watch-external-files-plugin@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/webpack-watch-external-files-plugin/-/webpack-watch-external-files-plugin-2.0.0.tgz#4c4e08c59b092c1d705e94d7a380eaa827a76d9c"
integrity sha512-dPUCEcgBjJHWyD4b0HcHD6h3mkPxVKmsfUSks5CvCbrF7HHLvIl/Wq4KSkUMMiNymloZKKkBjYpQxhubAEFM+Q==
dependencies:
glob "8.1.0"
path "0.12.7"

webpack@^5.88.2:
version "5.88.2"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e"
Expand Down

0 comments on commit e2f4665

Please sign in to comment.