@zohodesk/client_build_tool 0.0.11-exp.15 → 0.0.11-exp.15.2

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.
Files changed (28) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +28 -0
  3. package/docs/I18N_NUMERIC_INDEXING_PLUGIN.md +225 -0
  4. package/docs/client_build_tool_source_doc.md +390 -0
  5. package/lib/schemas/defaultConfigValues.js +17 -14
  6. package/lib/schemas/defaultConfigValuesOnly.js +4 -21
  7. package/lib/shared/babel/getBabelPlugin.js +3 -4
  8. package/lib/shared/babel/runBabelForTsFile.js +1 -1
  9. package/lib/shared/bundler/webpack/custom_plugins/BundleIntegrityReport/index.js +10 -0
  10. package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nGroupRuntimeModule.js +124 -0
  11. package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin.js +207 -145
  12. package/lib/shared/bundler/webpack/jsLoaders.js +2 -20
  13. package/lib/shared/bundler/webpack/pluginConfigs/configCopyPublicFolders.js +3 -2
  14. package/lib/shared/bundler/webpack/pluginConfigs/configI18nIndexingPlugin.js +42 -0
  15. package/lib/shared/bundler/webpack/pluginConfigs/configI18nNumericHtmlInjector.js +92 -0
  16. package/lib/shared/bundler/webpack/plugins.js +6 -2
  17. package/lib/shared/postcss/custom_postcss_plugins/VariableModificationPlugin/index.js +1 -1
  18. package/lib/shared/server/mockApiHandler.js +7 -0
  19. package/lib/shared/server/urlConcat.js +4 -3
  20. package/npm-shrinkwrap.json +354 -38
  21. package/package.json +6 -5
  22. package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexHtmlInjectorPlugin.js +0 -49
  23. package/lib/shared/bundler/webpack/custom_plugins/I18nNumericIndexPlugin/utils/i18nDataLoader.js +0 -106
  24. package/lib/shared/bundler/webpack/custom_plugins/I18nSplitPlugin/utils/collectAstKeys.js +0 -96
  25. package/lib/shared/bundler/webpack/loaderConfigs/i18nIdReplaceLoaderConfig.js +0 -71
  26. package/lib/shared/bundler/webpack/loaders/i18nIdReplaceLoader.js +0 -106
  27. package/lib/shared/bundler/webpack/pluginConfigs/configI18nNumericIndexPlugin.js +0 -84
  28. package/lib/shared/bundler/webpack/utils/propertiesParser.js +0 -81
@@ -1,186 +1,248 @@
1
1
  "use strict";
2
2
 
3
- const path = require('path');
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
4
7
 
5
- const {
6
- sources,
7
- Compilation,
8
- util
9
- } = require('webpack');
8
+ var _fs = _interopRequireDefault(require("fs"));
10
9
 
11
- const {
12
- decodeUnicodeEscapes
13
- } = require('../../utils/propertiesParser');
10
+ var _path = _interopRequireDefault(require("path"));
14
11
 
15
- const {
16
- loadNumericMap,
17
- loadI18nData
18
- } = require('./utils/i18nDataLoader');
12
+ var _webpack = require("webpack");
13
+
14
+ var _propertiesUtils = require("../I18nSplitPlugin/utils/propertiesUtils");
15
+
16
+ var _I18nGroupRuntimeModule = require("./I18nGroupRuntimeModule");
17
+
18
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
19
 
20
20
  const {
21
21
  RawSource
22
- } = sources;
22
+ } = _webpack.sources;
23
23
  const pluginName = 'I18nNumericIndexPlugin';
24
24
 
25
25
  class I18nNumericIndexPlugin {
26
- constructor(options = {}) {
27
- this.options = { ...options,
28
- singleFile: options.singleFile || false,
29
- singleFileTemplate: options.singleFileTemplate,
30
- includeContentHash: options.includeContentHash || false,
31
- generateManifest: options.generateManifest || false,
32
- manifestPath: options.manifestPath || 'i18n/manifest.json'
33
- };
34
- this.numericMap = null;
35
- this.i18nData = null;
36
- this.manifest = {};
26
+ constructor(options) {
27
+ this.options = options;
28
+ this.numericMap = {};
29
+ this.customGroups = {};
30
+ this.nextNumericId = 1;
37
31
  }
38
32
 
39
- getNumericMap(compilation) {
40
- if (!this.numericMap) {
41
- const mapPath = path.resolve(compilation.compiler.context, this.options.numericMapPath);
42
- this.numericMap = loadNumericMap(mapPath, compilation);
43
- }
33
+ apply(compiler) {
34
+ // Detect webpackI18nGroup comments in code
35
+ this.detectI18nGroupComments(compiler);
36
+ compiler.hooks.thisCompilation.tap(pluginName, compilation => {
37
+ // Add runtime module for group-based loading
38
+ if (this.options.customGroups) {
39
+ compilation.hooks.runtimeRequirementInTree.for(_webpack.RuntimeGlobals.ensureChunk).tap(pluginName, chunk => {
40
+ compilation.addRuntimeModule(chunk, new _I18nGroupRuntimeModule.I18nGroupRuntimeModule({
41
+ customGroups: this.options.customGroups,
42
+ localeVarName: this.options.localeVarName,
43
+ jsonpFunc: this.options.jsonpFunc
44
+ }));
45
+ });
46
+ }
44
47
 
45
- return this.numericMap;
48
+ compilation.hooks.processAssets.tap({
49
+ name: pluginName,
50
+ stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
51
+ }, () => {
52
+ this.processI18nFiles(compilation);
53
+ });
54
+ });
46
55
  }
47
56
 
48
- getI18nData(compilation) {
49
- if (!this.i18nData) {
50
- this.i18nData = loadI18nData(this.options, compilation);
51
- }
57
+ detectI18nGroupComments(compiler) {
58
+ compiler.hooks.normalModuleFactory.tap(pluginName, factory => {
59
+ factory.hooks.parser.for('javascript/auto').tap(pluginName, parser => {
60
+ parser.hooks.importCall.tap(pluginName, expr => {
61
+ // Check for webpackI18nGroup comment
62
+ const comments = expr.leadingComments || [];
63
+ comments.forEach(comment => {
64
+ if (comment.value && comment.value.includes('webpackI18nGroup')) {
65
+ const match = comment.value.match(/webpackI18nGroup:\s*["']([^"']+)["']/);
66
+
67
+ if (match) {
68
+ const groupName = match[1]; // Store this information for later use
69
+
70
+ if (!this.detectedGroups) {
71
+ this.detectedGroups = {};
72
+ } // Extract chunk name from webpackChunkName comment
73
+
52
74
 
53
- return this.i18nData;
75
+ const chunkNameMatch = comment.value.match(/webpackChunkName:\s*["']([^"']+)["']/);
76
+
77
+ if (chunkNameMatch) {
78
+ const chunkName = chunkNameMatch[1];
79
+ this.detectedGroups[chunkName] = groupName;
80
+ }
81
+ }
82
+ }
83
+ });
84
+ });
85
+ });
86
+ });
54
87
  }
55
88
 
56
- generateContentHash(content, compilation) {
89
+ processI18nFiles(compilation) {
57
90
  const {
58
- hashFunction,
59
- hashDigest,
60
- hashDigestLength
61
- } = compilation.outputOptions;
62
- const hash = util.createHash(hashFunction || 'xxhash64');
63
- hash.update(content);
64
- return hash.digest(hashDigest || 'hex').substring(0, hashDigestLength || 20);
65
- }
91
+ jsResourcePath,
92
+ propertiesFolderPath,
93
+ numericMapPath,
94
+ customGroups,
95
+ jsonpFunc,
96
+ numericFilenameTemplate,
97
+ dynamicFilenameTemplate
98
+ } = this.options;
66
99
 
67
- emitChunk(compilation, filename, locale, data, fileType = null) {
68
- const content = decodeUnicodeEscapes(JSON.stringify(data));
69
- const fileContent = `${this.options.jsonpFunc}(${content});`;
70
- let outputPath = filename.replace(/\[locale\]/g, locale);
71
- const hasContentHashPlaceholder = filename.includes('[contenthash]');
72
- const shouldIncludeHash = hasContentHashPlaceholder || this.options.includeContentHash;
100
+ if (!jsResourcePath || !propertiesFolderPath) {
101
+ return;
102
+ } // Read JSResources.properties
73
103
 
74
- if (shouldIncludeHash) {
75
- const contentHash = this.generateContentHash(fileContent, compilation);
76
104
 
77
- if (hasContentHashPlaceholder) {
78
- outputPath = outputPath.replace(/\[contenthash\]/g, contentHash);
79
- } else {
80
- outputPath = outputPath.replace(/\.js$/, `.${contentHash}.js`);
81
- }
105
+ const jsResourceKeys = (0, _propertiesUtils.getPropertiesAsJSON)(jsResourcePath); // Parse custom groups from banner markers
106
+
107
+ if (customGroups) {
108
+ this.parseCustomGroups(jsResourcePath, customGroups);
109
+ } // Get all locale translations
110
+
111
+
112
+ const allI18nObject = (0, _propertiesUtils.getAllI18n)({
113
+ folderPath: propertiesFolderPath,
114
+ disableDefault: false,
115
+ jsResourceI18nKeys: jsResourceKeys
116
+ });
117
+ const locales = Object.keys(allI18nObject); // Process each locale
118
+
119
+ locales.forEach(locale => {
120
+ const localeData = allI18nObject[locale];
121
+ const numericData = {};
122
+ const dynamicData = {};
123
+ const groupData = {}; // Initialize custom groups
124
+
125
+ Object.keys(customGroups || {}).forEach(groupName => {
126
+ groupData[groupName] = {};
127
+ }); // Process each key
128
+
129
+ Object.keys(localeData).forEach(key => {
130
+ const value = localeData[key]; // Check if key belongs to a custom group
131
+
132
+ const belongsToGroup = this.getKeyGroup(key);
133
+
134
+ if (belongsToGroup) {
135
+ // Add to custom group
136
+ const numericKey = this.getNumericKey(key);
137
+ groupData[belongsToGroup][numericKey] = value;
138
+ } else if (this.isDynamicKey(value)) {
139
+ // Add to dynamic chunk (keep string keys for dynamic)
140
+ dynamicData[key] = value;
141
+ } else {
142
+ // Add to numeric chunk
143
+ const numericKey = this.getNumericKey(key);
144
+ numericData[numericKey] = value;
145
+ }
146
+ }); // Emit numeric chunk
147
+
148
+ this.emitChunk(compilation, numericFilenameTemplate, locale, numericData, jsonpFunc); // Emit dynamic chunk
149
+
150
+ this.emitChunk(compilation, dynamicFilenameTemplate, locale, dynamicData, jsonpFunc); // Emit custom group chunks
151
+
152
+ Object.entries(groupData).forEach(([groupName, data]) => {
153
+ const groupConfig = customGroups[groupName];
154
+
155
+ if (groupConfig && Object.keys(data).length > 0) {
156
+ this.emitChunk(compilation, groupConfig.filenameTemplate || `i18n-chunk/[locale]/${groupName}.i18n.js`, locale, data, jsonpFunc, groupName);
157
+ }
158
+ });
159
+ }); // Save numeric map
160
+
161
+ if (numericMapPath) {
162
+ this.saveNumericMap(numericMapPath);
82
163
  }
164
+ }
165
+
166
+ parseCustomGroups(jsResourcePath, customGroups) {
167
+ const content = _fs.default.readFileSync(jsResourcePath, 'utf-8');
168
+
169
+ const lines = content.split('\n');
170
+ Object.entries(customGroups).forEach(([groupName, config]) => {
171
+ const {
172
+ bannerStart,
173
+ bannerEnd
174
+ } = config;
175
+ let inGroup = false;
176
+ const groupKeys = [];
177
+ lines.forEach(line => {
178
+ if (line.includes(bannerStart)) {
179
+ inGroup = true;
180
+ } else if (line.includes(bannerEnd)) {
181
+ inGroup = false;
182
+ } else if (inGroup && line.includes('=')) {
183
+ const key = line.split('=')[0].trim();
184
+
185
+ if (key && !key.startsWith('#')) {
186
+ groupKeys.push(key);
187
+ }
188
+ }
189
+ });
190
+ this.customGroups[groupName] = groupKeys;
191
+ });
192
+ }
83
193
 
84
- if (this.options.generateManifest) {
85
- const cleanName = filename.replace(/\[locale\]/g, locale).replace(/\.\[contenthash\]/g, '').replace(/\.js$/, '.js');
86
- const cleanNameWithType = fileType ? cleanName.replace(/\.js$/, `.${fileType}.js`) : cleanName;
87
- const manifestKey = cleanNameWithType.split('/').pop();
88
- this.manifest[manifestKey] = outputPath.split('/').pop();
194
+ getKeyGroup(key) {
195
+ for (const [groupName, keys] of Object.entries(this.customGroups)) {
196
+ if (keys.includes(key)) {
197
+ return groupName;
198
+ }
89
199
  }
90
200
 
91
- compilation.emitAsset(outputPath, new RawSource(fileContent));
92
- return outputPath;
201
+ return null;
93
202
  }
94
203
 
95
- apply(compiler) {
96
- compiler.hooks.thisCompilation.tap(pluginName, compilation => {
97
- compilation.hooks.processAssets.tapAsync({
98
- name: pluginName,
99
- stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
100
- }, (assets, callback) => {
101
- if (!this.options.enable) {
102
- return callback();
103
- }
204
+ isDynamicKey(value) {
205
+ // Check if value contains placeholders like {0}, {1}, etc.
206
+ return /\{\d+\}/.test(value);
207
+ }
104
208
 
105
- const {
106
- sortedKeys,
107
- totalKeys,
108
- originalKeyToNumericId
109
- } = this.getNumericMap(compilation);
110
- const {
111
- jsResourceBase,
112
- allI18n,
113
- locales
114
- } = this.getI18nData(compilation);
115
- if (!locales.length) return callback();
116
- const numericKeysSet = new Set(sortedKeys);
117
- const englishData = allI18n.en_US || jsResourceBase;
118
- const isDevMode = this.options.devMode || process.env.NODE_ENV === 'development';
119
- locales.forEach(locale => {
120
- const localeData = allI18n[locale] || {};
121
- const numericData = {};
122
- const unmappedData = {};
123
- Object.keys(jsResourceBase).forEach(key => {
124
- const translation = localeData[key] ?? englishData[key];
125
-
126
- if (originalKeyToNumericId && originalKeyToNumericId.hasOwnProperty(key)) {
127
- const numericId = originalKeyToNumericId[key];
128
- numericData[numericId] = translation;
129
- } else if (numericKeysSet.has(key)) {
130
- const index = sortedKeys.indexOf(key);
131
-
132
- if (index !== -1) {
133
- numericData[index] = translation;
134
- }
135
- } else {
136
- unmappedData[key] = translation;
137
- }
138
- });
209
+ getNumericKey(key) {
210
+ if (!this.numericMap[key]) {
211
+ this.numericMap[key] = this.nextNumericId++;
212
+ }
139
213
 
140
- if (this.options.singleFile) {
141
- const combinedData = { ...numericData,
142
- ...unmappedData
143
- };
214
+ return String(this.numericMap[key]);
215
+ }
144
216
 
145
- if (Object.keys(combinedData).length > 0) {
146
- const filename = this.options.singleFileTemplate || this.options.numericFilenameTemplate || this.options.dynamicFilenameTemplate;
147
- this.emitChunk(compilation, filename, locale, combinedData);
148
- }
149
- } else {
150
- if (Object.keys(numericData).length > 0) {
151
- this.emitChunk(compilation, this.options.numericFilenameTemplate, locale, numericData, 'numeric');
152
- }
217
+ emitChunk(compilation, filenameTemplate, locale, data, jsonpFunc, groupName = null) {
218
+ const filename = filenameTemplate.replace('[locale]', locale);
219
+ const content = this.generateChunkContent(data, jsonpFunc, groupName);
220
+ compilation.emitAsset(filename, new RawSource(content));
221
+ }
153
222
 
154
- if (Object.keys(unmappedData).length > 0) {
155
- this.emitChunk(compilation, this.options.dynamicFilenameTemplate, locale, unmappedData, 'dynamic');
156
- }
157
- }
158
- });
223
+ generateChunkContent(data, jsonpFunc, groupName) {
224
+ const jsonString = JSON.stringify(data);
159
225
 
160
- if (this.options.generateManifest && Object.keys(this.manifest).length > 0) {
161
- // Determine manifest path
162
- let manifestPath;
163
-
164
- if (this.options.manifestPath) {
165
- // Use explicitly configured path
166
- manifestPath = this.options.manifestPath;
167
- } else {
168
- // Default to same directory as i18n files with manifest.json name
169
- const template = this.options.singleFileTemplate || this.options.numericFilenameTemplate;
170
- manifestPath = path.dirname(template) + '/manifest.json';
171
- }
226
+ if (groupName) {
227
+ // Include group name for lazy loading identification
228
+ return `${jsonpFunc}(${jsonString}, "${groupName}");`;
229
+ }
172
230
 
173
- const manifestContent = JSON.stringify(this.manifest, null, 2);
174
- compilation.emitAsset(manifestPath, new RawSource(manifestContent));
175
- }
231
+ return `${jsonpFunc}(${jsonString});`;
232
+ }
176
233
 
177
- callback();
234
+ saveNumericMap(mapPath) {
235
+ const dir = _path.default.dirname(mapPath);
236
+
237
+ if (!_fs.default.existsSync(dir)) {
238
+ _fs.default.mkdirSync(dir, {
239
+ recursive: true
178
240
  });
179
- });
241
+ }
242
+
243
+ _fs.default.writeFileSync(mapPath, JSON.stringify(this.numericMap, null, 2));
180
244
  }
181
245
 
182
246
  }
183
247
 
184
- module.exports = {
185
- I18nNumericIndexPlugin
186
- };
248
+ exports.default = I18nNumericIndexPlugin;
@@ -7,29 +7,11 @@ exports.jsLoaders = jsLoaders;
7
7
 
8
8
  var _babelLoaderConfig = require("./loaderConfigs/babelLoaderConfig");
9
9
 
10
- const {
11
- i18nIdReplaceLoaderConfig
12
- } = require('./loaderConfigs/i18nIdReplaceLoaderConfig');
13
-
14
10
  function jsLoaders(options) {
15
- const useLoaders = [];
16
- useLoaders.push((0, _babelLoaderConfig.babelLoaderConfig)(options));
17
- const shouldUseNumericIndexing = options.i18nIndexing && options.i18nIndexing.enable || options.i18nChunkSplit && options.i18nChunkSplit.chunkSplitEnable && options.i18nChunkSplit.useNumericIndexing;
18
-
19
- if (shouldUseNumericIndexing) {
20
- try {
21
- const loaderConfig = i18nIdReplaceLoaderConfig(options, options.context);
22
-
23
- if (loaderConfig) {
24
- useLoaders.push(loaderConfig);
25
- }
26
- } catch (err) {// Silently skip if configuration fails
27
- }
28
- }
29
-
30
11
  return [{
31
12
  test: /\.js$/,
32
13
  exclude: /node_modules/,
33
- use: useLoaders
14
+ use: [(0, _babelLoaderConfig.babelLoaderConfig)(options)] // include: path.join(appPath, folder)
15
+
34
16
  }];
35
17
  }
@@ -43,9 +43,10 @@ function folderPatterns(publicFolders) {
43
43
 
44
44
  function configCopyPublicFolders(options) {
45
45
  let {
46
- publicFolders
46
+ publicFolders,
47
+ mode = 'dev'
47
48
  } = options;
48
- publicFolders = (0, _updateArrayWithDefault.updateArrayWithDefault)(publicFolders, defaultPublicFolders);
49
+ publicFolders = (0, _updateArrayWithDefault.updateArrayWithDefault)(publicFolders[mode], defaultPublicFolders);
49
50
 
50
51
  if (publicFolders.length === 0) {
51
52
  return null;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = configI18nIndexingPlugin;
7
+
8
+ var _I18nNumericIndexPlugin = _interopRequireDefault(require("../custom_plugins/I18nNumericIndexPlugin/I18nNumericIndexPlugin"));
9
+
10
+ var _resourceBasedPublicPath = require("../common/resourceBasedPublicPath");
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ function configI18nIndexingPlugin(config) {
15
+ const {
16
+ i18nIndexing,
17
+ cdnMapping
18
+ } = config;
19
+
20
+ if (!i18nIndexing || !i18nIndexing.enable) {
21
+ return null;
22
+ } // Get the public path for i18n resources
23
+
24
+
25
+ const i18nPublicPath = (0, _resourceBasedPublicPath.resourceBasedPublicPath)('i18n', config); // Get the CDN template for i18n resources if CDN is enabled
26
+
27
+ const i18nCdnTemplate = cdnMapping && cdnMapping.isCdnEnabled ? cdnMapping.i18nTemplate || cdnMapping.jsTemplate : '';
28
+ const options = {
29
+ jsResourcePath: i18nIndexing.jsResourcePath,
30
+ propertiesFolderPath: i18nIndexing.propertiesFolderPath,
31
+ numericMapPath: i18nIndexing.numericMapPath,
32
+ numericFilenameTemplate: i18nIndexing.numericFilenameTemplate || 'i18n-chunk/[locale]/numeric.i18n.js',
33
+ dynamicFilenameTemplate: i18nIndexing.dynamicFilenameTemplate || 'i18n-chunk/[locale]/dynamic.i18n.js',
34
+ jsonpFunc: i18nIndexing.jsonpFunc || 'window.loadI18nChunk',
35
+ htmlTemplateLabel: i18nIndexing.htmlTemplateLabel || '{{--user-locale}}',
36
+ localeVarName: i18nIndexing.localeVarName || 'window.userLangCode',
37
+ customGroups: i18nIndexing.customGroups || {},
38
+ publicPath: i18nPublicPath || '',
39
+ i18nCdnTemplate
40
+ };
41
+ return new _I18nNumericIndexPlugin.default(options);
42
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = configI18nNumericHtmlInjector;
7
+
8
+ var _htmlWebpackPlugin = _interopRequireDefault(require("html-webpack-plugin"));
9
+
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
+
12
+ const pluginName = 'I18nNumericHtmlInjectorPlugin';
13
+
14
+ class I18nNumericHtmlInjectorPlugin {
15
+ constructor(options) {
16
+ this.options = options;
17
+ }
18
+
19
+ apply(compiler) {
20
+ compiler.hooks.thisCompilation.tap(pluginName, compilation => {
21
+ // Hook into HtmlWebpackPlugin to inject i18n script tags
22
+ _htmlWebpackPlugin.default.getHooks(compilation).beforeAssetTagGeneration.tap(pluginName, hookData => {
23
+ const {
24
+ assets
25
+ } = hookData;
26
+ const {
27
+ numericFilenameTemplate,
28
+ dynamicFilenameTemplate,
29
+ htmlTemplateLabel,
30
+ i18nCdnTemplate,
31
+ customGroups
32
+ } = this.options;
33
+ const newI18nAssets = []; // Add numeric i18n chunk
34
+
35
+ if (numericFilenameTemplate) {
36
+ const numericFilename = numericFilenameTemplate.replace(/\[locale\]/g, htmlTemplateLabel).replace(/%5Blocale%5D/g, htmlTemplateLabel); // Don't add CDN template - HtmlWebpackPlugin handles it
37
+
38
+ newI18nAssets.push(numericFilename);
39
+ } // Add dynamic i18n chunk
40
+
41
+
42
+ if (dynamicFilenameTemplate) {
43
+ const dynamicFilename = dynamicFilenameTemplate.replace(/\[locale\]/g, htmlTemplateLabel).replace(/%5Blocale%5D/g, htmlTemplateLabel); // Don't add CDN template - HtmlWebpackPlugin handles it
44
+
45
+ newI18nAssets.push(dynamicFilename);
46
+ } // Add custom group chunks if they should be in initial HTML
47
+
48
+
49
+ if (customGroups) {
50
+ Object.entries(customGroups).forEach(([groupName, groupConfig]) => {
51
+ // Only add to initial HTML if preload is true
52
+ if (groupConfig.preload && groupConfig.filenameTemplate) {
53
+ const groupFilename = groupConfig.filenameTemplate.replace(/\[locale\]/g, htmlTemplateLabel).replace(/%5Blocale%5D/g, htmlTemplateLabel); // Don't add CDN template - HtmlWebpackPlugin handles it
54
+
55
+ newI18nAssets.push(groupFilename);
56
+ }
57
+ });
58
+ } // Prepend i18n assets to ensure they load before main bundle
59
+
60
+
61
+ if (newI18nAssets.length > 0) {
62
+ assets.js = [...newI18nAssets, ...assets.js];
63
+ }
64
+
65
+ return hookData;
66
+ });
67
+ });
68
+ }
69
+
70
+ }
71
+
72
+ function configI18nNumericHtmlInjector(config) {
73
+ const {
74
+ i18nIndexing,
75
+ cdnMapping
76
+ } = config; // Only create this plugin if i18nIndexing is enabled
77
+
78
+ if (!i18nIndexing || !i18nIndexing.enable) {
79
+ return null;
80
+ } // Get the CDN template for i18n resources if CDN is enabled
81
+
82
+
83
+ const i18nCdnTemplate = cdnMapping && cdnMapping.isCdnEnabled ? cdnMapping.i18nTemplate || cdnMapping.jsTemplate : '';
84
+ const options = {
85
+ numericFilenameTemplate: i18nIndexing.numericFilenameTemplate || 'i18n-chunk/[locale]/numeric.i18n.js',
86
+ dynamicFilenameTemplate: i18nIndexing.dynamicFilenameTemplate || 'i18n-chunk/[locale]/dynamic.i18n.js',
87
+ htmlTemplateLabel: i18nIndexing.htmlTemplateLabel || '{{--user-locale}}',
88
+ customGroups: i18nIndexing.customGroups || {},
89
+ i18nCdnTemplate
90
+ };
91
+ return new I18nNumericHtmlInjectorPlugin(options);
92
+ }
@@ -11,6 +11,10 @@ var _configEnvVariables = require("./pluginConfigs/configEnvVariables");
11
11
 
12
12
  var _configI18nSplitPlugin = require("./pluginConfigs/configI18nSplitPlugin");
13
13
 
14
+ var _configI18nIndexingPlugin = _interopRequireDefault(require("./pluginConfigs/configI18nIndexingPlugin"));
15
+
16
+ var _configI18nNumericHtmlInjector = _interopRequireDefault(require("./pluginConfigs/configI18nNumericHtmlInjector"));
17
+
14
18
  var _configMiniCSSExtractPlugin = require("./pluginConfigs/configMiniCSSExtractPlugin");
15
19
 
16
20
  var _configRtlCssPlugin = require("./pluginConfigs/configRtlCssPlugin");
@@ -49,12 +53,12 @@ var _configRuntimeResourceCleanup = require("./pluginConfigs/configRuntimeResour
49
53
 
50
54
  var _configCustomScriptLoadingStrategyPlugin = require("./pluginConfigs/configCustomScriptLoadingStrategyPlugin");
51
55
 
52
- var _configI18nNumericIndexPlugin = require("./pluginConfigs/configI18nNumericIndexPlugin");
56
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
53
57
 
54
58
  // import { IgnorePlugin } from 'webpack';
55
59
  function plugins(options) {
56
60
  const {
57
61
  webpackPlugins
58
62
  } = options;
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, _configRtlCssPlugin.configRtlCssPlugin)(options), (0, _configHtmlWebpackPlugin.configHtmlWebpackPlugin)(options), ...((0, _configI18nNumericIndexPlugin.configI18nNumericIndexPlugin)(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
+ 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, _configI18nIndexingPlugin.default)(options), (0, _configRtlCssPlugin.configRtlCssPlugin)(options), (0, _configHtmlWebpackPlugin.configHtmlWebpackPlugin)(options), (0, _configI18nNumericHtmlInjector.default)(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);
60
64
  }
@@ -259,7 +259,7 @@ var _default = ({
259
259
  if (range) {
260
260
  // console.log('multiple :', decl.value)
261
261
  let newVal = '';
262
- decl.value.split(' ').forEach(singleVal => {
262
+ decl.value.split(' ').filter(Boolean).forEach(singleVal => {
263
263
  newVal += `${singleConvertor(singleVal, settings.replacements.px, {
264
264
  decl,
265
265
  filename,
@@ -44,6 +44,13 @@ function handleMockApi(mockEntryFile, app) {
44
44
  const entryFilePath = (0, _constants.joinWithAppPath)(mockEntryFile); // eslint-disable-next-line no-use-before-define
45
45
 
46
46
  const mockFunc = safeRequire(entryFilePath);
47
+
48
+ if (typeof mockFunc === 'function') {
49
+ // eslint-disable-next-line no-use-before-define
50
+ mockFunc(app);
51
+ return;
52
+ }
53
+
47
54
  mockFunc?.mockApi?.(app);
48
55
  } // function handleMockApi(params) {
49
56
  // }
@@ -17,10 +17,11 @@ function urlConcat(url, path) {
17
17
  const slashRemovedPath = removeFrontSlash(path);
18
18
 
19
19
  if (slashRemovedUrl === '') {
20
- return path;
21
- }
20
+ return `${path}/`;
21
+ } //return `${slashRemovedUrl}/${slashRemovedPath}`;
22
22
 
23
- return `${slashRemovedUrl}/${slashRemovedPath}/`;
23
+
24
+ return `${[slashRemovedUrl, slashRemovedPath].filter(a => a).join('/')}/`;
24
25
  }
25
26
 
26
27
  function removeLastSlash(url) {