@zohodesk/client_build_tool 0.0.11-exp.26.0 → 0.0.11-exp.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -102
- package/README_backup.md +0 -102
- package/lib/schemas/defaultConfigValues.js +13 -29
- package/lib/schemas/defaultConfigValuesOnly.js +10 -14
- package/lib/shared/bundler/webpack/common/i18nOptionsValidator.js +144 -0
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nGroupRuntimeModule.js +130 -169
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexHtmlInjectorPlugin.js +47 -35
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin.js +200 -128
- package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/utils/i18nDataLoader.js +33 -59
- package/lib/shared/bundler/webpack/loaderConfigs/i18nIdReplaceLoaderConfig.js +28 -39
- package/lib/shared/bundler/webpack/loaders/i18nIdReplaceLoader.js +24 -60
- package/lib/shared/bundler/webpack/optimizationConfig.js +1 -4
- package/lib/shared/bundler/webpack/pluginConfigs/configI18nNumericIndexPlugin.js +40 -61
- package/lib/shared/bundler/webpack/plugins.js +1 -4
- package/package.json +1 -1
- package/docs/DYNAMIC_TEMPLATE_EXAMPLE.md +0 -129
- package/docs/I18N_NUMERIC_INDEXING_PLUGIN.md +0 -225
- package/docs/I18N_SINGLE_FILE_MODE.md +0 -126
- package/docs/client_build_tool_source_doc.md +0 -390
|
@@ -1,37 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.i18nIdReplaceLoaderConfig = i18nIdReplaceLoaderConfig;
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
var _propertiesUtils = require("../custom_plugins/I18nSplitPlugin/utils/propertiesUtils.js");
|
|
9
|
+
|
|
10
|
+
var _i18nOptionsValidator = require("../common/i18nOptionsValidator.js");
|
|
11
|
+
|
|
12
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
13
|
+
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
8
15
|
|
|
9
16
|
function loadJSResourcesOnce(options) {
|
|
10
|
-
let jsResourcePath;
|
|
17
|
+
let jsResourcePath;
|
|
11
18
|
|
|
12
19
|
if (options.i18nIndexing && options.i18nIndexing.enable) {
|
|
13
20
|
jsResourcePath = options.i18nIndexing.jsResourcePath;
|
|
14
21
|
} else if (options.i18nChunkSplit && options.i18nChunkSplit.chunkSplitEnable && options.i18nChunkSplit.useNumericIndexing) {
|
|
15
22
|
jsResourcePath = options.i18nChunkSplit.jsResource;
|
|
16
|
-
} else {
|
|
17
|
-
throw new Error('i18nIdReplaceLoader requires either i18nIndexing to be enabled or i18nChunkSplit with useNumericIndexing');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (!jsResourcePath) {
|
|
21
|
-
throw new Error('Missing required jsResourcePath in i18n options');
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
try {
|
|
25
|
-
const i18nData = getPropertiesAsJSON(jsResourcePath);
|
|
26
|
-
|
|
27
|
-
if (Object.keys(i18nData).length === 0) {
|
|
28
|
-
console.warn(`[i18nIdReplaceLoaderConfig] Warning: No i18n data found in JSResource file: ${jsResourcePath}`);
|
|
29
|
-
return {};
|
|
30
|
-
}
|
|
31
|
-
|
|
26
|
+
const i18nData = (0, _propertiesUtils.getPropertiesAsJSON)(jsResourcePath);
|
|
32
27
|
return i18nData;
|
|
33
28
|
} catch (err) {
|
|
34
|
-
throw new Error(`Error reading JSResource file ${jsResourcePath}: ${err.message}`);
|
|
29
|
+
throw new Error(`[I18nIdReplaceLoaderConfig] Error reading JSResource file ${jsResourcePath}: ${err.message}`);
|
|
35
30
|
}
|
|
36
31
|
}
|
|
37
32
|
|
|
@@ -39,37 +34,35 @@ function readNumericMapOnce(numericMapPath) {
|
|
|
39
34
|
if (!numericMapPath) return null;
|
|
40
35
|
|
|
41
36
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
const fileContent = _fs.default.readFileSync(numericMapPath, 'utf-8');
|
|
38
|
+
|
|
44
39
|
const parsed = JSON.parse(fileContent);
|
|
45
|
-
if (!parsed) return null;
|
|
46
40
|
return parsed.originalKeyToNumericId ? parsed.originalKeyToNumericId : parsed;
|
|
47
41
|
} catch (err) {
|
|
48
|
-
|
|
42
|
+
throw new Error(`[I18nIdReplaceLoaderConfig] Failed to read numeric map from ${numericMapPath}: ${err.message}`);
|
|
49
43
|
}
|
|
50
44
|
}
|
|
51
45
|
|
|
52
|
-
function i18nIdReplaceLoaderConfig(options
|
|
53
|
-
|
|
46
|
+
function i18nIdReplaceLoaderConfig(options) {
|
|
47
|
+
(0, _i18nOptionsValidator.validateI18nOptions)(options);
|
|
48
|
+
let numericMapPath;
|
|
54
49
|
|
|
55
50
|
if (options.i18nIndexing && options.i18nIndexing.enable) {
|
|
56
51
|
numericMapPath = options.i18nIndexing.numericMapPath;
|
|
57
52
|
} else if (options.i18nChunkSplit && options.i18nChunkSplit.chunkSplitEnable && options.i18nChunkSplit.useNumericIndexing) {
|
|
58
53
|
numericMapPath = options.i18nChunkSplit.numericMapPath;
|
|
59
|
-
} else {
|
|
60
|
-
throw new Error('i18nIdReplaceLoader requires either i18nIndexing to be enabled or i18nChunkSplit with useNumericIndexing');
|
|
61
54
|
}
|
|
62
55
|
|
|
63
|
-
if (!numericMapPath) {
|
|
64
|
-
throw new Error('numericMapPath is required in i18nIndexing or i18nChunkSplit config');
|
|
65
|
-
} // Load all i18n data for key detection
|
|
66
|
-
|
|
67
|
-
|
|
68
56
|
const allI18nData = loadJSResourcesOnce(options);
|
|
57
|
+
const i18nKeyReplaceLoaderPath = new URL('../loaders/i18nIdReplaceLoader.js', import.meta.url).pathname;
|
|
58
|
+
let numericIdMap;
|
|
69
59
|
|
|
70
|
-
|
|
60
|
+
try {
|
|
61
|
+
numericIdMap = readNumericMapOnce(numericMapPath);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
throw new Error(`[I18nIdReplaceLoaderConfig] Failed to load numeric map: ${err.message}`);
|
|
64
|
+
}
|
|
71
65
|
|
|
72
|
-
const numericIdMap = readNumericMapOnce(numericMapPath);
|
|
73
66
|
const loaderOptions = {
|
|
74
67
|
allI18nData: allI18nData,
|
|
75
68
|
sourceMaps: false,
|
|
@@ -83,8 +76,4 @@ function i18nIdReplaceLoaderConfig(options, webpackContext) {
|
|
|
83
76
|
loader: i18nKeyReplaceLoaderPath,
|
|
84
77
|
options: loaderOptions
|
|
85
78
|
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
module.exports = {
|
|
89
|
-
i18nIdReplaceLoaderConfig
|
|
90
|
-
};
|
|
79
|
+
}
|
|
@@ -20,19 +20,10 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
20
20
|
const resourcePath = this.resourcePath;
|
|
21
21
|
this.cacheable && this.cacheable();
|
|
22
22
|
const options = getOptions(this) || {};
|
|
23
|
-
const callback = this.async();
|
|
24
|
-
let numericMapAbsPath = null;
|
|
23
|
+
const callback = this.async(); // Skip files in excluded paths
|
|
25
24
|
|
|
26
|
-
if (options.
|
|
27
|
-
|
|
28
|
-
numericMapAbsPath = path.isAbsolute(options.numericMapPath) ? options.numericMapPath : path.resolve(this.rootContext || this.context || process.cwd(), options.numericMapPath);
|
|
29
|
-
this.addDependency(numericMapAbsPath);
|
|
30
|
-
} catch (e) {}
|
|
31
|
-
} // Skip files in excluded paths
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (options.excludePaths) {
|
|
35
|
-
const shouldExclude = options.excludePaths.some(excludePath => resourcePath.includes(excludePath));
|
|
25
|
+
if (options.excludePaths && Array.isArray(options.excludePaths)) {
|
|
26
|
+
const shouldExclude = options.excludePaths.some(excludePath => typeof excludePath === 'string' && resourcePath.includes(excludePath));
|
|
36
27
|
|
|
37
28
|
if (shouldExclude) {
|
|
38
29
|
return callback(null, source, map);
|
|
@@ -40,57 +31,35 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
40
31
|
} // Only process files in included paths if specified
|
|
41
32
|
|
|
42
33
|
|
|
43
|
-
if (options.includePaths && options.includePaths.length > 0) {
|
|
44
|
-
const shouldInclude = options.includePaths.some(includePath => resourcePath.includes(includePath));
|
|
34
|
+
if (options.includePaths && Array.isArray(options.includePaths) && options.includePaths.length > 0) {
|
|
35
|
+
const shouldInclude = options.includePaths.some(includePath => typeof includePath === 'string' && resourcePath.includes(includePath));
|
|
45
36
|
|
|
46
37
|
if (!shouldInclude) {
|
|
47
38
|
return callback(null, source, map);
|
|
48
39
|
}
|
|
49
|
-
} //
|
|
40
|
+
} // Basic runtime validation - options should already be validated by config
|
|
50
41
|
|
|
51
42
|
|
|
52
43
|
if (!options.allI18nData || Object.keys(options.allI18nData).length === 0) {
|
|
53
44
|
return callback(new Error(`i18nIdReplaceLoader: 'allI18nData' option is missing or empty`));
|
|
54
|
-
} // Load numeric ID mapping
|
|
45
|
+
} // Load numeric ID mapping - paths already validated by config
|
|
55
46
|
|
|
56
47
|
|
|
57
|
-
let numericIdMap = options.numericIdMap
|
|
48
|
+
let numericIdMap = options.numericIdMap;
|
|
58
49
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
global.__CBT_I18N_NUMERIC_MAP_CACHE__ = {};
|
|
64
|
-
}
|
|
50
|
+
if (!numericIdMap && options.numericMapPath) {
|
|
51
|
+
try {
|
|
52
|
+
const mapPath = path.isAbsolute(options.numericMapPath) ? options.numericMapPath : path.resolve(this.rootContext || this.context || process.cwd(), options.numericMapPath);
|
|
53
|
+
this.addDependency(mapPath);
|
|
65
54
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const stat = fs.statSync(p);
|
|
71
|
-
const key = `${p}`;
|
|
72
|
-
const mtime = stat && stat.mtimeMs ? stat.mtimeMs : 0;
|
|
73
|
-
const hit = cache[key];
|
|
74
|
-
|
|
75
|
-
if (hit && hit.mtime === mtime && hit.map) {
|
|
76
|
-
numericIdMap = hit.map;
|
|
77
|
-
} else if (fs.existsSync(p)) {
|
|
78
|
-
const txt = fs.readFileSync(p, 'utf-8');
|
|
79
|
-
const parsed = JSON.parse(txt);
|
|
80
|
-
const mapObj = parsed && parsed.originalKeyToNumericId ? parsed.originalKeyToNumericId : parsed;
|
|
81
|
-
|
|
82
|
-
if (mapObj && typeof mapObj === 'object') {
|
|
83
|
-
cache[key] = {
|
|
84
|
-
mtime,
|
|
85
|
-
map: mapObj
|
|
86
|
-
};
|
|
87
|
-
numericIdMap = mapObj;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
} catch (e) {// ignore and proceed without map
|
|
55
|
+
if (fs.existsSync(mapPath)) {
|
|
56
|
+
const mapContent = fs.readFileSync(mapPath, 'utf-8');
|
|
57
|
+
const parsed = JSON.parse(mapContent);
|
|
58
|
+
numericIdMap = parsed.originalKeyToNumericId || parsed;
|
|
91
59
|
}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return callback(new Error(`i18nIdReplaceLoader: Failed to load numeric map from ${options.numericMapPath}: ${e.message}`));
|
|
92
62
|
}
|
|
93
|
-
} catch (e) {// ignore
|
|
94
63
|
} // If no numeric map available, return source as-is
|
|
95
64
|
|
|
96
65
|
|
|
@@ -98,8 +67,6 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
98
67
|
return callback(null, source, map);
|
|
99
68
|
}
|
|
100
69
|
|
|
101
|
-
const isDevMode = options.devMode || process.env.NODE_ENV === 'development';
|
|
102
|
-
|
|
103
70
|
try {
|
|
104
71
|
// Parse the JavaScript/TypeScript source code
|
|
105
72
|
const ast = parser.parse(source, {
|
|
@@ -107,23 +74,20 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
107
74
|
plugins: ['jsx', 'typescript', 'classProperties', 'optionalChaining', 'nullishCoalescingOperator'],
|
|
108
75
|
sourceFilename: resourcePath
|
|
109
76
|
});
|
|
110
|
-
let hasTransformations = false;
|
|
77
|
+
let hasTransformations = false;
|
|
78
|
+
let transformationCount = 0; // Traverse AST and replace i18n keys with numeric IDs
|
|
111
79
|
|
|
112
80
|
traverse(ast, {
|
|
113
81
|
StringLiteral(path) {
|
|
114
82
|
const {
|
|
115
83
|
node
|
|
116
|
-
} = path; // Check if this string is an i18n key
|
|
117
|
-
|
|
118
|
-
if (!options.allI18nData.hasOwnProperty(node.value)) {
|
|
119
|
-
return;
|
|
120
|
-
} // Replace with numeric ID if available
|
|
121
|
-
|
|
84
|
+
} = path; // Check if this string is an i18n key and has numeric mapping
|
|
122
85
|
|
|
123
|
-
if (numericIdMap.hasOwnProperty(node.value)) {
|
|
86
|
+
if (options.allI18nData.hasOwnProperty(node.value) && numericIdMap.hasOwnProperty(node.value)) {
|
|
124
87
|
const numericId = String(numericIdMap[node.value]);
|
|
125
88
|
path.replaceWith(t.stringLiteral(numericId));
|
|
126
89
|
hasTransformations = true;
|
|
90
|
+
transformationCount++;
|
|
127
91
|
}
|
|
128
92
|
}
|
|
129
93
|
|
|
@@ -141,6 +105,6 @@ module.exports = function i18nIdReplaceLoader(source, map) {
|
|
|
141
105
|
callback(null, source, map);
|
|
142
106
|
}
|
|
143
107
|
} catch (err) {
|
|
144
|
-
callback(err);
|
|
108
|
+
callback(new Error(`i18nIdReplaceLoader: Failed to process ${resourcePath}: ${err.message}`));
|
|
145
109
|
}
|
|
146
110
|
};
|
|
@@ -23,10 +23,7 @@ function optimizationConfig(options) {
|
|
|
23
23
|
} = options;
|
|
24
24
|
const {
|
|
25
25
|
chunkSplitEnable
|
|
26
|
-
} = options.i18nChunkSplit;
|
|
27
|
-
|
|
28
|
-
console.log('MINIFY_TEST: optimizationConfig called in mode:', options.mode);
|
|
29
|
-
console.log('MINIFY_TEST: TerserPlugin and CSS minification active');
|
|
26
|
+
} = options.i18nChunkSplit;
|
|
30
27
|
const i18nChunkFilename = (0, _nameTemplates.nameTemplates)('i18njs', options);
|
|
31
28
|
const chunkFilenameHasContentHash = (0, _hashUtils.hasContentHash)(i18nChunkFilename);
|
|
32
29
|
/**
|
|
@@ -11,17 +11,26 @@ var _I18nNumericIndexHtmlInjectorPlugin = require("../custom_plugins/I18nNumeric
|
|
|
11
11
|
|
|
12
12
|
var _readI18nValues = require("../custom_plugins/I18nSplitPlugin/readI18nValues");
|
|
13
13
|
|
|
14
|
+
var _i18nOptionsValidator = require("../common/i18nOptionsValidator.js");
|
|
15
|
+
|
|
14
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
17
|
|
|
16
18
|
function configI18nNumericIndexPlugin(options) {
|
|
17
|
-
if (!
|
|
19
|
+
if (!options.i18nIndexing) {
|
|
18
20
|
return null;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
const i18nOpts = options.i18nIndexing;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const result = (0, _i18nOptionsValidator.validateI18nIndexingOptions)(i18nOpts);
|
|
27
|
+
|
|
28
|
+
if (result.skipValidation) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
} catch (error) {
|
|
32
|
+
throw new Error(`[I18nNumericIndexPlugin] ${error.message}`);
|
|
33
|
+
}
|
|
25
34
|
|
|
26
35
|
const emitFiles = i18nOpts.emitFiles !== undefined ? i18nOpts.emitFiles : true;
|
|
27
36
|
const injectHtml = i18nOpts.injectI18nUrlInIndex !== undefined ? i18nOpts.injectI18nUrlInIndex : true;
|
|
@@ -29,85 +38,55 @@ function configI18nNumericIndexPlugin(options) {
|
|
|
29
38
|
|
|
30
39
|
if (!emitFiles && !injectHtml && !hasCustomGroups) {
|
|
31
40
|
return [];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const requiredOptions = ['jsResourcePath', 'propertiesFolderPath', 'numericMapPath', 'jsonpFunc', 'htmlTemplateLabel', 'localeVarName'];
|
|
36
|
-
const missingOptions = requiredOptions.filter(opt => !i18nOpts[opt]);
|
|
41
|
+
}
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
console.warn(`[I18nNumericIndexPlugin] Missing required options: ${missingOptions.join(', ')}`);
|
|
40
|
-
return null;
|
|
41
|
-
} // Read i18n values
|
|
43
|
+
let i18nData;
|
|
42
44
|
|
|
45
|
+
try {
|
|
46
|
+
i18nData = (0, _readI18nValues.readI18nValues)({
|
|
47
|
+
jsResource: i18nOpts.jsResourcePath,
|
|
48
|
+
propertiesFolder: i18nOpts.propertiesFolderPath,
|
|
49
|
+
disableDefault: false
|
|
50
|
+
});
|
|
51
|
+
} catch (error) {
|
|
52
|
+
throw new Error(`[I18nNumericIndexPlugin] Failed to read i18n data: ${error.message}`);
|
|
53
|
+
}
|
|
43
54
|
|
|
44
55
|
const {
|
|
45
56
|
locales,
|
|
46
57
|
allI18nObject
|
|
47
|
-
} =
|
|
48
|
-
jsResource: i18nOpts.jsResourcePath,
|
|
49
|
-
propertiesFolder: i18nOpts.propertiesFolderPath,
|
|
50
|
-
disableDefault: false
|
|
51
|
-
}); // Ensure templates have [locale] placeholder
|
|
52
|
-
|
|
58
|
+
} = i18nData;
|
|
53
59
|
const numericTemplate = i18nOpts.numericFilenameTemplate || '[locale]/numeric.i18n.js';
|
|
54
60
|
const dynamicTemplate = i18nOpts.dynamicFilenameTemplate || '[locale]/dynamic.i18n.js';
|
|
55
|
-
|
|
56
|
-
if (!numericTemplate.includes('[locale]')) {
|
|
57
|
-
console.warn('[I18nNumericIndexPlugin] numericFilenameTemplate must include [locale] placeholder');
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (!dynamicTemplate.includes('[locale]')) {
|
|
62
|
-
console.warn('[I18nNumericIndexPlugin] dynamicFilenameTemplate must include [locale] placeholder');
|
|
63
|
-
return null;
|
|
64
|
-
} // Resolve singleFileTemplate if it's a function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
let resolvedSingleFileTemplate = i18nOpts.singleFileTemplate || '[locale].js';
|
|
68
|
-
|
|
69
|
-
if (typeof i18nOpts.singleFileTemplate === 'function') {
|
|
70
|
-
resolvedSingleFileTemplate = i18nOpts.singleFileTemplate(isDevelopment);
|
|
71
|
-
} // Plugin options
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const numericIndexPluginOptions = {
|
|
75
|
-
enable: i18nOpts.enable,
|
|
61
|
+
const sharedOptions = {
|
|
76
62
|
outputFolder: i18nOpts.outputFolder || 'i18n-chunk',
|
|
63
|
+
numericFilenameTemplate: numericTemplate,
|
|
64
|
+
dynamicFilenameTemplate: dynamicTemplate,
|
|
65
|
+
singleFileTemplate: i18nOpts.singleFileTemplate,
|
|
66
|
+
singleFile: i18nOpts.singleFile || false,
|
|
67
|
+
includeContentHash: i18nOpts.includeContentHash || false
|
|
68
|
+
};
|
|
69
|
+
const numericIndexPluginOptions = { ...sharedOptions,
|
|
70
|
+
enable: i18nOpts.enable,
|
|
77
71
|
jsResourcePath: i18nOpts.jsResourcePath,
|
|
78
72
|
propertiesFolderPath: i18nOpts.propertiesFolderPath,
|
|
79
73
|
numericMapPath: i18nOpts.numericMapPath,
|
|
80
74
|
locales,
|
|
81
75
|
allI18nObject,
|
|
82
|
-
numericFilenameTemplate: numericTemplate,
|
|
83
|
-
dynamicFilenameTemplate: dynamicTemplate,
|
|
84
|
-
singleFileTemplate: resolvedSingleFileTemplate,
|
|
85
76
|
jsonpFunc: i18nOpts.jsonpFunc,
|
|
86
77
|
localeVarName: i18nOpts.localeVarName,
|
|
87
|
-
singleFile: i18nOpts.singleFile || false,
|
|
88
78
|
restrictToBaseKeys: i18nOpts.restrictToBaseKeys || false,
|
|
89
|
-
includeContentHash: i18nOpts.includeContentHash || false,
|
|
90
79
|
generateManifest: i18nOpts.generateManifest || false,
|
|
91
80
|
manifestPath: i18nOpts.manifestPath || null,
|
|
92
81
|
customGroups: i18nOpts.customGroups || null,
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
chunkToGroupMapping: i18nOpts.chunkToGroupMapping || {},
|
|
83
|
+
emitFiles,
|
|
95
84
|
i18nPublicPathVar: i18nOpts.i18nPublicPathVar
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const htmlInjectorOptions = {
|
|
99
|
-
outputFolder: i18nOpts.outputFolder || 'i18n-chunk',
|
|
100
|
-
numericFilenameTemplate: numericTemplate,
|
|
101
|
-
dynamicFilenameTemplate: dynamicTemplate,
|
|
102
|
-
singleFileTemplate: resolvedSingleFileTemplate,
|
|
85
|
+
};
|
|
86
|
+
const htmlInjectorOptions = { ...sharedOptions,
|
|
103
87
|
htmlTemplateLabel: i18nOpts.htmlTemplateLabel,
|
|
104
|
-
singleFile: i18nOpts.singleFile || false,
|
|
105
88
|
i18nAssetsPublicPathPrefix: '',
|
|
106
|
-
injectI18nUrlInIndex:
|
|
107
|
-
// Control HTML injection
|
|
108
|
-
isDevelopment: isDevelopment
|
|
89
|
+
injectI18nUrlInIndex: injectHtml
|
|
109
90
|
};
|
|
110
|
-
|
|
111
|
-
const htmlInjectorPluginInstance = new _I18nNumericIndexHtmlInjectorPlugin.I18nNumericIndexHtmlInjectorPlugin(htmlInjectorOptions);
|
|
112
|
-
return [i18nNumericPluginInstance, htmlInjectorPluginInstance];
|
|
91
|
+
return [new _I18nNumericIndexPlugin.default(numericIndexPluginOptions), new _I18nNumericIndexHtmlInjectorPlugin.I18nNumericIndexHtmlInjectorPlugin(htmlInjectorOptions)];
|
|
113
92
|
}
|
|
@@ -55,9 +55,6 @@ var _configCustomScriptLoadingStrategyPlugin = require("./pluginConfigs/configCu
|
|
|
55
55
|
function plugins(options) {
|
|
56
56
|
const {
|
|
57
57
|
webpackPlugins
|
|
58
|
-
} = options;
|
|
59
|
-
|
|
60
|
-
console.log('MINIFY_TEST: plugins function called with options:', options.mode);
|
|
61
|
-
console.log('MINIFY_TEST: This message should be visible if minification is disabled');
|
|
58
|
+
} = options;
|
|
62
59
|
return [(0, _configEnvVariables.configEnvVariables)(options), (0, _configCustomAttributesPlugin.configCustomAttributesPlugin)(options), (0, _configTPHashMappingPlugin.configTPHashMappingPlugin)(options), (0, _configCopyPublicFolders.configCopyPublicFolders)(options), (0, _configIgnorePlugin.configIgnorePlugin)(options), (0, _configMiniCSSExtractPlugin.configMiniCSSExtractPlugin)(options), (0, _configSelectorWeightPlugin.configSelectorWeightPlugin)(options), (0, _configVariableConversionPlugin.configVariableConversionPlugin)(options), (0, _configI18nSplitPlugin.configI18nSplitPlugin)(options), ...((0, _configI18nNumericIndexPlugin.configI18nNumericIndexPlugin)(options) || []), (0, _configRtlCssPlugin.configRtlCssPlugin)(options), (0, _configHtmlWebpackPlugin.configHtmlWebpackPlugin)(options), (0, _configCustomScriptLoadingStrategyPlugin.configCustomScriptLoadingStrategyPlugin)(options), (0, _configCdnChangePlugin.configCdnChangePlugin)(options), (0, _configServiceWorkerPlugin.configServiceWorkerPlugin)(options), (0, _configEFCTemplatePlugin.configEFCTemplatePlugin)(options), (0, _configResourceHintsPlugin.configResourceHintsPlugin)(options), (0, _configBundleAnalyzer.configBundleAnalyzer)(options), (0, _configManifestJsonPlugin.configManifestJsonPlugin)(options), (0, _configSourceMapPlugin.configSourceMapPlugin)(options), (0, _configProgressPlugin.configProgressPlugin)(options), (0, _configBundleIntegrityReport.configBundleIntegrityReport)(options), (0, _configRuntimeResourceCleanup.configRuntimeResourceCleanup)(options), ...webpackPlugins].filter(Boolean);
|
|
63
60
|
}
|
package/package.json
CHANGED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# Dynamic singleFileTemplate Configuration
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
The `singleFileTemplate` option now supports both static strings and dynamic functions, allowing different filename patterns based on build mode.
|
|
5
|
-
|
|
6
|
-
## Configuration Options
|
|
7
|
-
|
|
8
|
-
### 1. Static Template (Simple)
|
|
9
|
-
```javascript
|
|
10
|
-
i18nIndexing: {
|
|
11
|
-
singleFileTemplate: '[locale].js' // Always uses this format
|
|
12
|
-
}
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
### 2. Dynamic Template with Function
|
|
16
|
-
```javascript
|
|
17
|
-
i18nIndexing: {
|
|
18
|
-
isDevelopment: isDevelopment, // Pass from your app
|
|
19
|
-
singleFileTemplate: (isDev) =>
|
|
20
|
-
isDev ? '[locale].js' : '[locale].[contenthash].js'
|
|
21
|
-
}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### 3. Inline Conditional (Pre-resolved)
|
|
25
|
-
```javascript
|
|
26
|
-
i18nIndexing: {
|
|
27
|
-
isDevelopment: isDevelopment, // Pass from your app
|
|
28
|
-
singleFileTemplate: isDevelopment
|
|
29
|
-
? '[locale].js'
|
|
30
|
-
: '[locale].[contenthash].js'
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Template Placeholders
|
|
35
|
-
|
|
36
|
-
- `[locale]` - Replaced with actual locale code (e.g., en_US, fr_FR)
|
|
37
|
-
- `[contenthash]` - Replaced with content-based hash for cache busting
|
|
38
|
-
|
|
39
|
-
## Output Examples
|
|
40
|
-
|
|
41
|
-
### Development Mode (isDevelopment = true)
|
|
42
|
-
```
|
|
43
|
-
Template: '[locale].js'
|
|
44
|
-
Output:
|
|
45
|
-
i18n/en_US.js
|
|
46
|
-
i18n/fr_FR.js
|
|
47
|
-
i18n/de_DE.js
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Production Mode (isDevelopment = false)
|
|
51
|
-
```
|
|
52
|
-
Template: '[locale].[contenthash].js'
|
|
53
|
-
Output:
|
|
54
|
-
i18n/en_US.b9ef890a.js
|
|
55
|
-
i18n/fr_FR.3452451e.js
|
|
56
|
-
i18n/de_DE.e8b84364.js
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Complete Example Configuration
|
|
60
|
-
|
|
61
|
-
```javascript
|
|
62
|
-
exports.config = {
|
|
63
|
-
context: 'src',
|
|
64
|
-
output: 'build',
|
|
65
|
-
mode: process.env.NODE_ENV || 'production',
|
|
66
|
-
|
|
67
|
-
// Pass isDevelopment from your app
|
|
68
|
-
isDevelopment: process.env.NODE_ENV === 'development',
|
|
69
|
-
|
|
70
|
-
i18nIndexing: {
|
|
71
|
-
enable: true,
|
|
72
|
-
outputFolder: 'i18n',
|
|
73
|
-
jsResourcePath: './resources/ApplicationResources.properties',
|
|
74
|
-
propertiesFolderPath: './resources',
|
|
75
|
-
numericMapPath: './numericMap.json',
|
|
76
|
-
|
|
77
|
-
// Dynamic template based on build mode
|
|
78
|
-
singleFileTemplate: function(isDevelopment) {
|
|
79
|
-
return isDevelopment ? '[locale].js' : '[locale].[contenthash].js';
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
// Or using arrow function
|
|
83
|
-
// singleFileTemplate: (isDev) => isDev ? '[locale].js' : '[locale].[contenthash].js',
|
|
84
|
-
|
|
85
|
-
// Or pre-resolved
|
|
86
|
-
// singleFileTemplate: isDevelopment ? '[locale].js' : '[locale].[contenthash].js',
|
|
87
|
-
|
|
88
|
-
singleFile: true,
|
|
89
|
-
jsonpFunc: 'var imAppI18n=',
|
|
90
|
-
htmlTemplateLabel: '{{--user-locale}}',
|
|
91
|
-
localeVarName: 'window.userLangCode',
|
|
92
|
-
generateManifest: true,
|
|
93
|
-
manifestPath: 'i18n/manifest.json'
|
|
94
|
-
|
|
95
|
-
// Note: includeContentHash is now optional when using [contenthash] in template
|
|
96
|
-
// includeContentHash: true // Not needed with [contenthash] placeholder
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Benefits
|
|
102
|
-
|
|
103
|
-
1. **Development**: Clean, readable filenames without hashes for easier debugging
|
|
104
|
-
2. **Production**: Content-hashed filenames for optimal caching
|
|
105
|
-
3. **Flexibility**: Single configuration handles both environments
|
|
106
|
-
4. **No Redundancy**: Using `[contenthash]` in template eliminates need for `includeContentHash` option
|
|
107
|
-
|
|
108
|
-
## Migration from includeContentHash
|
|
109
|
-
|
|
110
|
-
### Old Way
|
|
111
|
-
```javascript
|
|
112
|
-
singleFileTemplate: '[locale].js',
|
|
113
|
-
includeContentHash: true // Adds hash before .js
|
|
114
|
-
// Output: en_US.abc123.js
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### New Way (Recommended)
|
|
118
|
-
```javascript
|
|
119
|
-
singleFileTemplate: isDevelopment ? '[locale].js' : '[locale].[contenthash].js'
|
|
120
|
-
// Output: en_US.abc123.js (production) or en_US.js (development)
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
## Notes
|
|
124
|
-
|
|
125
|
-
- The function receives `isDevelopment` as a boolean parameter
|
|
126
|
-
- You must pass `isDevelopment` in your main options object
|
|
127
|
-
- The `[contenthash]` placeholder is automatically replaced with the actual hash
|
|
128
|
-
- For HTML injection, the hash placeholder is removed since the exact hash isn't known at HTML generation time
|
|
129
|
-
- The manifest will map clean names to hashed versions for deployment scripts
|