@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.
@@ -20,29 +20,28 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
20
20
  customGroups,
21
21
  chunkIdToGroupMapping,
22
22
  localeVarName,
23
- jsonpFunc,
24
- i18nPublicPathVar
25
- } = this.options; // Use the pre-computed chunk ID to group mapping
26
-
23
+ i18nPublicPathVar,
24
+ groupAssetUrls,
25
+ includeContentHash,
26
+ mode
27
+ } = this.options;
27
28
  const chunkIdToGroup = chunkIdToGroupMapping || {};
29
+ const hasGroupAssetOverrides = !!groupAssetUrls && Object.values(groupAssetUrls).some(localeMap => localeMap && Object.keys(localeMap).length > 0);
30
+ const hashAware = includeContentHash || hasGroupAssetOverrides;
31
+ const isDevelopment = mode === 'development';
28
32
  return `
29
33
  // I18n Group Loading Runtime
30
34
  (function() {
31
35
  var loadedGroups = {};
32
36
  var chunkIdToGroup = ${JSON.stringify(chunkIdToGroup)};
37
+ var groupAssetUrls = ${JSON.stringify(groupAssetUrls || {})};
38
+ var hashAware = ${hashAware ? 'true' : 'false'};
39
+ var isDev = ${isDevelopment ? 'true' : 'false'};
33
40
  var cachedI18nBase;
34
- var loadReasonKey = '__i18nGroupLoadReason';
35
-
36
- // Only log if we have actual mappings to track
37
- if (Object.keys(chunkIdToGroup).length > 0) {
38
- console.log('[i18n-group:runtime] I18n Group Runtime Module loaded');
39
- console.log('[i18n-group:runtime] Chunk ID to Group mapping:', chunkIdToGroup);
40
- }
41
+ var scriptCache = null;
41
42
 
42
43
  function ensureTrailingSlash(path) {
43
- if (!path) {
44
- return '';
45
- }
44
+ if (!path) return '';
46
45
  return path.charAt(path.length - 1) === '/' ? path : path + '/';
47
46
  }
48
47
 
@@ -53,39 +52,11 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
53
52
  return candidate;
54
53
  }
55
54
  } catch (err) {
56
- // ignore – fall back to DOM/publicPath detection
55
+ // Fall back to DOM/publicPath detection
57
56
  }
58
57
  return '';
59
58
  }
60
59
 
61
- function withLoadReason(reason, fn) {
62
- var previous = __webpack_require__[loadReasonKey];
63
- __webpack_require__[loadReasonKey] = reason;
64
- try {
65
- return fn();
66
- } finally {
67
- __webpack_require__[loadReasonKey] = previous;
68
- }
69
- }
70
-
71
- if (typeof __webpack_require__.pfc === 'function') {
72
- var originalPrefetchChunk = __webpack_require__.pfc;
73
- __webpack_require__.pfc = function(prefetchChunkId) {
74
- return withLoadReason('prefetch', function() {
75
- return originalPrefetchChunk(prefetchChunkId);
76
- });
77
- };
78
- }
79
-
80
- if (typeof __webpack_require__.plc === 'function') {
81
- var originalPreloadChunk = __webpack_require__.plc;
82
- __webpack_require__.plc = function(preloadChunkId) {
83
- return withLoadReason('preload', function() {
84
- return originalPreloadChunk(preloadChunkId);
85
- });
86
- };
87
- }
88
-
89
60
  function resolveI18nBase() {
90
61
  if (cachedI18nBase !== undefined) {
91
62
  return cachedI18nBase;
@@ -94,9 +65,11 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
94
65
  var base = resolveConfiguredBase();
95
66
 
96
67
  if (!base && typeof document !== 'undefined') {
97
- var scripts = document.getElementsByTagName('script');
98
- for (var i = 0; i < scripts.length; i++) {
99
- var src = scripts[i].getAttribute('data-src') || scripts[i].getAttribute('src') || '';
68
+ if (!scriptCache) {
69
+ scriptCache = Array.from(document.getElementsByTagName('script'));
70
+ }
71
+ for (var i = 0; i < scriptCache.length; i++) {
72
+ var src = scriptCache[i].getAttribute('data-src') || scriptCache[i].getAttribute('src') || '';
100
73
  var markerIndex = src.indexOf('i18n-chunk/');
101
74
  if (markerIndex !== -1) {
102
75
  base = src.slice(0, markerIndex);
@@ -113,24 +86,18 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
113
86
  }
114
87
 
115
88
  cachedI18nBase = ensureTrailingSlash(base);
116
- if (typeof console !== 'undefined' && console.log) {
117
- console.log('[i18n-group:base]', cachedI18nBase || '<empty>');
118
- }
119
89
  return cachedI18nBase;
120
90
  }
121
91
 
122
92
  function buildI18nUrl(relativePath) {
123
93
  var base = resolveI18nBase();
124
- if (!relativePath) {
125
- return base;
126
- }
94
+ if (!relativePath) return base;
127
95
  if (relativePath.charAt(0) === '/') {
128
96
  relativePath = relativePath.slice(1);
129
97
  }
130
98
  return base + relativePath;
131
99
  }
132
-
133
- // Function to load i18n group
100
+
134
101
  function loadI18nGroup(groupName, loadReason) {
135
102
  if (loadedGroups[groupName]) {
136
103
  return Promise.resolve();
@@ -149,178 +116,172 @@ class I18nGroupRuntimeModule extends _webpack.RuntimeModule {
149
116
  (loadReason === 'preload' && config.preload === false);
150
117
 
151
118
  if (shouldSkip) {
152
- if (typeof console !== 'undefined' && console.log) {
153
- console.log('[i18n-group:skip]', groupName, loadReason, 'prefetch/preload disabled');
154
- }
155
119
  return Promise.resolve();
156
120
  }
157
121
 
158
122
  return new Promise(function(resolve, reject) {
159
- var relativePath = config.filenameTemplate
160
- .replace('[locale]', locale);
161
- var i18nUrl = buildI18nUrl(relativePath);
123
+ var relativePath = config.filenameTemplate.replace('[locale]', locale);
162
124
 
163
- if (typeof console !== 'undefined' && console.log) {
164
- console.log('[i18n-group:load]', groupName, loadReason || 'require', i18nUrl);
125
+ if (hashAware && groupAssetUrls[groupName] && groupAssetUrls[groupName][locale]) {
126
+ relativePath = groupAssetUrls[groupName][locale];
165
127
  }
166
128
 
129
+ var i18nUrl = buildI18nUrl(relativePath);
130
+
167
131
  var script = document.createElement('script');
168
132
  script.src = i18nUrl;
169
133
  script.async = true;
170
-
134
+
135
+ var cleanup = function() {
136
+ if (script.parentNode) {
137
+ script.parentNode.removeChild(script);
138
+ }
139
+ };
140
+
171
141
  script.onload = function() {
172
142
  loadedGroups[groupName] = true;
173
- if (typeof console !== 'undefined' && console.log) {
174
- console.log('[i18n-group:loaded]', groupName, loadReason || 'require', i18nUrl);
143
+ if (isDev) {
144
+ console.log('[i18n-group:loaded]', groupName, i18nUrl);
175
145
  }
146
+ cleanup();
176
147
  resolve();
177
148
  };
178
149
 
179
150
  script.onerror = function() {
180
- if (typeof console !== 'undefined' && console.error) {
151
+ if (isDev) {
181
152
  console.error('[i18n-group:error]', groupName, i18nUrl);
182
153
  }
183
- reject(new Error('Failed to load i18n group: ' + groupName));
154
+ cleanup();
155
+ loadedGroups[groupName] = true;
156
+ resolve();
184
157
  };
185
-
158
+
186
159
  document.head.appendChild(script);
187
160
  });
188
161
  }
189
162
 
190
163
  function findGroupByChunkId(chunkId) {
191
- // Direct numeric chunk ID lookup
192
164
  return chunkIdToGroup[chunkId];
193
165
  }
194
-
195
- // Store original webpack chunk loading function
166
+
196
167
  var originalEnsureChunk = __webpack_require__.e;
197
-
198
- // Override webpack's chunk loading if it exists
168
+
199
169
  if (originalEnsureChunk) {
200
170
  __webpack_require__.e = function(chunkId) {
201
- if (typeof console !== 'undefined' && console.log) {
202
- console.log('[i18n-group:debug] Chunk loading called for ID:', chunkId);
203
- }
204
-
205
- // Capture the arguments for later use
206
171
  var args = arguments;
207
172
  var self = this;
208
-
209
- // Check if this chunk needs an i18n group
210
173
  var groupName = findGroupByChunkId(chunkId);
211
- if (typeof console !== 'undefined' && console.log) {
212
- console.log('[i18n-group:debug] Found group for chunk', chunkId, ':', groupName);
213
- console.log('[i18n-group:debug] Chunk mapping:', chunkIdToGroup);
214
- }
215
174
 
216
175
  if (groupName && !loadedGroups[groupName]) {
217
- if (typeof console !== 'undefined' && console.log) {
218
- var chunkFilename = typeof __webpack_require__ !== 'undefined' && typeof __webpack_require__.u === 'function'
219
- ? __webpack_require__.u(chunkId)
220
- : '<no __webpack_require__.u>';
221
- console.log('[i18n-group:hook]', chunkId, '→', groupName, '| reason:', (__webpack_require__[loadReasonKey] || 'require'), '| file:', chunkFilename);
222
- }
223
- // Load the i18n group FIRST, then load the chunk
224
- var loadReason = __webpack_require__[loadReasonKey] || 'require';
225
- var i18nPromise = loadI18nGroup(groupName, loadReason);
226
- // Chain: i18n loads first, then chunk loads
176
+ var i18nPromise = loadI18nGroup(groupName, 'require');
177
+
227
178
  return i18nPromise.then(function() {
228
- // Only start loading the actual chunk after i18n is loaded
179
+ return originalEnsureChunk.apply(self, args);
180
+ }).catch(function(err) {
181
+ if (isDev) {
182
+ console.error('[i18n-group:critical] i18n failed, proceeding without:', err);
183
+ }
229
184
  return originalEnsureChunk.apply(self, args);
230
185
  });
231
186
  } else {
232
- if (typeof console !== 'undefined' && console.log) {
233
- if (!groupName) {
234
- console.log('[i18n-group:debug] No group found for chunk', chunkId);
235
- } else if (loadedGroups[groupName]) {
236
- console.log('[i18n-group:debug] Group', groupName, 'already loaded for chunk', chunkId);
237
- }
238
- }
239
- // No i18n needed, just load the chunk normally
240
187
  return originalEnsureChunk.apply(this, arguments);
241
188
  }
242
189
  };
243
190
  }
244
-
245
- // Also check for webpackI18nGroup comments in dynamic imports
246
- function wrapLoadScript(originalLoadScript) {
247
- return function(url, done, key, chunkId) {
248
- var groupName = findGroupByChunkId(chunkId);
249
- if (groupName && !loadedGroups[groupName]) {
250
- var locale = ${localeVarName} || 'en_US';
251
- var groupConfig = ${JSON.stringify(customGroups)};
252
- var config = groupConfig[groupName];
253
191
 
254
- if (config) {
255
- var relativePath = config.filenameTemplate
256
- .replace('[locale]', locale);
257
- var i18nUrl = buildI18nUrl(relativePath);
192
+ // Simple URL-based detection for setup pages
193
+ function detectGroupFromUrl() {
194
+ if (typeof window === 'undefined') return null;
258
195
 
259
- if (config.prefetch === false) {
260
- if (typeof console !== 'undefined' && console.log) {
261
- console.log('[i18n-group:skip-prefetch-loader]', groupName, chunkId, i18nUrl);
262
- }
263
- return originalLoadScript.call(__webpack_require__, url, done, key, chunkId);
264
- }
196
+ var url = window.location.href;
197
+ var groupConfig = ${JSON.stringify(customGroups)};
265
198
 
266
- var i18nScript = document.createElement('script');
267
- i18nScript.src = i18nUrl;
268
- i18nScript.onload = function() {
269
- loadedGroups[groupName] = true;
270
- originalLoadScript.call(__webpack_require__, url, done, key, chunkId);
271
- };
272
- i18nScript.onerror = function() {
273
- if (typeof console !== 'undefined' && console.error) {
274
- console.error('[i18n-group:error]', groupName, i18nUrl);
275
- }
276
- originalLoadScript.call(__webpack_require__, url, done, key, chunkId);
277
- };
278
- document.head.appendChild(i18nScript);
279
- return;
199
+ for (var groupName in groupConfig) {
200
+ var config = groupConfig[groupName];
201
+ if (config.urlPatterns && Array.isArray(config.urlPatterns)) {
202
+ for (var i = 0; i < config.urlPatterns.length; i++) {
203
+ var pattern = config.urlPatterns[i];
204
+ if (url.includes(pattern)) {
205
+ return groupName;
206
+ }
280
207
  }
281
208
  }
209
+ }
282
210
 
283
- return originalLoadScript.call(__webpack_require__, url, done, key, chunkId);
284
- };
211
+ return null;
285
212
  }
286
213
 
287
- function installLoadScriptHook(loadScript) {
288
- if (typeof loadScript !== 'function') {
289
- Object.defineProperty(__webpack_require__, 'l', {
290
- configurable: true,
291
- enumerable: true,
292
- get: function() {
293
- return loadScript;
294
- },
295
- set: function(newLoader) {
296
- installLoadScriptHook(newLoader);
214
+ function checkAndLoadGroupFromUrl() {
215
+ try {
216
+ var detectedGroup = detectGroupFromUrl();
217
+ if (detectedGroup && !loadedGroups[detectedGroup]) {
218
+ if (isDev) {
219
+ console.log('[i18n-group:url-detect]', detectedGroup, 'loading for current URL');
297
220
  }
298
- });
299
- return;
221
+ loadI18nGroup(detectedGroup, 'url-detection').catch(function(err) {
222
+ if (isDev) {
223
+ console.error('[i18n-group:url-detect] Failed to load', detectedGroup, ':', err);
224
+ }
225
+ });
226
+ }
227
+ } catch (err) {
228
+ if (isDev) {
229
+ console.error('[i18n-group:url-detect] Error in URL detection:', err);
230
+ }
300
231
  }
301
-
302
- Object.defineProperty(__webpack_require__, 'l', {
303
- configurable: true,
304
- enumerable: true,
305
- writable: true,
306
- value: wrapLoadScript(loadScript)
307
- });
308
232
  }
309
233
 
310
- if (typeof __webpack_require__.l === 'function') {
311
- installLoadScriptHook(__webpack_require__.l);
312
- } else {
313
- Object.defineProperty(__webpack_require__, 'l', {
314
- configurable: true,
315
- enumerable: true,
316
- set: function(newLoader) {
317
- installLoadScriptHook(newLoader);
318
- },
319
- get: function() {
320
- return undefined;
234
+ // Initialize preload and prefetch mechanisms
235
+ function initializeGroupLoading() {
236
+ if (typeof window === 'undefined') return;
237
+
238
+ var groupConfig = ${JSON.stringify(customGroups)};
239
+
240
+ // 1. Immediate preload for critical groups
241
+ for (var groupName in groupConfig) {
242
+ var config = groupConfig[groupName];
243
+ if (config.preload === true && !loadedGroups[groupName]) {
244
+ if (isDev) {
245
+ console.log('[i18n-group:preload]', groupName, 'loading immediately');
246
+ }
247
+ loadI18nGroup(groupName, 'preload').catch(function(err) {
248
+ if (isDev) {
249
+ console.error('[i18n-group:preload] Failed to preload', groupName, ':', err);
250
+ }
251
+ });
321
252
  }
322
- });
253
+ }
254
+
255
+ // 2. Schedule prefetch for background loading
256
+ function schedulePrefetch() {
257
+ for (var groupName in groupConfig) {
258
+ var config = groupConfig[groupName];
259
+ if (config.prefetch === true && !loadedGroups[groupName] && config.preload !== true) {
260
+ if (isDev) {
261
+ console.log('[i18n-group:prefetch]', groupName, 'scheduling background load');
262
+ }
263
+ loadI18nGroup(groupName, 'prefetch').catch(function(err) {
264
+ if (isDev) {
265
+ console.error('[i18n-group:prefetch] Failed to prefetch', groupName, ':', err);
266
+ }
267
+ });
268
+ }
269
+ }
270
+ }
271
+
272
+ // Use requestIdleCallback for prefetch if available, otherwise setTimeout
273
+ if (window.requestIdleCallback) {
274
+ window.requestIdleCallback(schedulePrefetch, { timeout: 5000 });
275
+ } else {
276
+ setTimeout(schedulePrefetch, 100);
277
+ }
278
+
279
+ // 3. Check current URL for immediate loading
280
+ checkAndLoadGroupFromUrl();
323
281
  }
282
+
283
+ // Initialize loading mechanisms
284
+ initializeGroupLoading();
324
285
  })();
325
286
  `;
326
287
  }
@@ -1,23 +1,30 @@
1
1
  "use strict";
2
2
 
3
- const HtmlWebpackPlugin = require('html-webpack-plugin');
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.I18nNumericIndexHtmlInjectorPlugin = void 0;
4
7
 
5
- const path = require('path');
8
+ var _htmlWebpackPlugin = _interopRequireDefault(require("html-webpack-plugin"));
9
+
10
+ var _path = _interopRequireDefault(require("path"));
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
6
13
 
7
14
  const pluginName = 'I18nNumericIndexHtmlInjectorPlugin';
15
+ const assetStoreKey = Symbol.for('I18nNumericIndexPluginAssets');
8
16
 
9
17
  class I18nNumericIndexHtmlInjectorPlugin {
10
18
  constructor(options) {
11
19
  this.options = { ...options,
12
- injectI18nUrlInIndex: options.injectI18nUrlInIndex !== undefined ? options.injectI18nUrlInIndex : true // Default to true
13
-
20
+ injectI18nUrlInIndex: options.injectI18nUrlInIndex !== undefined ? options.injectI18nUrlInIndex : true,
21
+ includeContentHash: options.includeContentHash || false
14
22
  };
15
23
  }
16
24
 
17
25
  apply(compiler) {
18
26
  compiler.hooks.thisCompilation.tap(pluginName, compilation => {
19
- HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tapAsync(pluginName, (hookData, cb) => {
20
- // Skip HTML injection if injectI18nUrlInIndex is false
27
+ _htmlWebpackPlugin.default.getHooks(compilation).beforeAssetTagGeneration.tapAsync(pluginName, (hookData, cb) => {
21
28
  if (!this.options.injectI18nUrlInIndex) {
22
29
  return cb(null, hookData);
23
30
  }
@@ -26,7 +33,7 @@ class I18nNumericIndexHtmlInjectorPlugin {
26
33
  assets
27
34
  } = hookData;
28
35
  const {
29
- outputFolder,
36
+ outputFolder = 'i18n-chunk',
30
37
  numericFilenameTemplate,
31
38
  dynamicFilenameTemplate,
32
39
  singleFileTemplate,
@@ -34,47 +41,55 @@ class I18nNumericIndexHtmlInjectorPlugin {
34
41
  singleFile,
35
42
  i18nAssetsPublicPathPrefix = ''
36
43
  } = this.options;
37
- const newI18nAssetUrlsToAdd = []; // Construct full paths using outputFolder
38
-
39
- const constructFullPath = (template, isSingleFile = false) => {
40
- if (!template) return null; // Replace locale placeholder
41
-
42
- let filePath = template.replace(/\[locale\]/g, htmlTemplateLabel); // Remove [contenthash] placeholder for HTML injection
43
- // The actual hash will be determined at build time
44
-
45
- filePath = filePath.replace(/\.\[contenthash\]/g, ''); // If template already contains outputFolder or starts with a path separator, use as-is
44
+ const newI18nAssetUrlsToAdd = [];
45
+ const emittedAssetNames = compilation.getAssets().map(asset => asset.name);
46
+ const recordedAssets = compilation[assetStoreKey] || [];
47
+
48
+ const resolveAssetPath = (template, fileType) => {
49
+ if (!template) return null;
50
+ const recorded = recordedAssets.find(asset => {
51
+ if (fileType === 'single') return !asset.fileType;
52
+ return asset.fileType === fileType;
53
+ });
54
+
55
+ if (recorded) {
56
+ const assetPath = recorded.outputPath.replace(recorded.locale, htmlTemplateLabel);
57
+ return i18nAssetsPublicPathPrefix + assetPath;
58
+ }
46
59
 
47
- if (filePath.includes(outputFolder) || filePath.startsWith('/')) {
48
- return filePath.replace(/\\/g, '/');
49
- } // For single-file mode with a simple template like '[locale].js',
50
- // put it directly in outputFolder without subdirectories
60
+ const filePath = template.replace(/\[locale\]/g, htmlTemplateLabel);
61
+ const fullPath = filePath.includes(outputFolder) || filePath.startsWith('/') ? filePath : _path.default.join(outputFolder, filePath);
51
62
 
63
+ if (emittedAssetNames.includes(fullPath)) {
64
+ return i18nAssetsPublicPathPrefix + fullPath;
65
+ }
52
66
 
53
- if (isSingleFile && !filePath.includes('/')) {
54
- return path.join(outputFolder || 'i18n-chunk', filePath).replace(/\\/g, '/');
55
- } // For other cases, preserve subdirectories
67
+ if (fullPath.includes('[contenthash]')) {
68
+ const pattern = fullPath.replace('[contenthash]', '*');
69
+ const matchingAsset = emittedAssetNames.find(name => name.startsWith(pattern.split('*')[0]) && name.endsWith(pattern.split('*')[1]));
56
70
 
71
+ if (matchingAsset) {
72
+ return i18nAssetsPublicPathPrefix + matchingAsset;
73
+ }
74
+ }
57
75
 
58
- return path.join(outputFolder || 'i18n-chunk', filePath).replace(/\\/g, '/');
76
+ return i18nAssetsPublicPathPrefix + fullPath;
59
77
  };
60
78
 
61
79
  if (singleFile) {
62
- // In single file mode, use singleFileTemplate
63
- const singleTemplate = singleFileTemplate || '[locale].js';
64
- const combinedFilename = constructFullPath(singleTemplate, true);
80
+ const combinedFilename = resolveAssetPath(singleFileTemplate, 'single');
65
81
 
66
82
  if (combinedFilename) {
67
83
  newI18nAssetUrlsToAdd.push(combinedFilename);
68
84
  }
69
85
  } else {
70
- // Add both numeric and dynamic files
71
- const numericFilename = constructFullPath(numericFilenameTemplate);
86
+ const numericFilename = resolveAssetPath(numericFilenameTemplate, 'numeric');
72
87
 
73
88
  if (numericFilename) {
74
89
  newI18nAssetUrlsToAdd.push(numericFilename);
75
90
  }
76
91
 
77
- const dynamicFilename = constructFullPath(dynamicFilenameTemplate);
92
+ const dynamicFilename = resolveAssetPath(dynamicFilenameTemplate, 'dynamic');
78
93
 
79
94
  if (dynamicFilename) {
80
95
  newI18nAssetUrlsToAdd.push(dynamicFilename);
@@ -82,17 +97,14 @@ class I18nNumericIndexHtmlInjectorPlugin {
82
97
  }
83
98
 
84
99
  if (newI18nAssetUrlsToAdd.length > 0) {
85
- // Add i18n assets to the beginning of JS assets for early loading
86
100
  assets.js = [...newI18nAssetUrlsToAdd, ...assets.js];
87
101
  }
88
102
 
89
- cb(null, hookData);
103
+ return cb(null, hookData);
90
104
  });
91
105
  });
92
106
  }
93
107
 
94
108
  }
95
109
 
96
- module.exports = {
97
- I18nNumericIndexHtmlInjectorPlugin
98
- };
110
+ exports.I18nNumericIndexHtmlInjectorPlugin = I18nNumericIndexHtmlInjectorPlugin;