@epublishing/grunt-epublishing 1.2.10 → 1.2.11

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.
@@ -139,26 +139,65 @@ function createWebpackConfig(config, options = {}) {
139
139
  compiler.hooks.compilation.tap('ResolveRelativeModuleIds', (compilation) => {
140
140
  compilation.hooks.beforeModuleIds.tap('ResolveRelativeModuleIds', (modules) => {
141
141
  let fallbackId = 0;
142
-
142
+ const usedIds = new Set();
143
+
144
+ // Loader-chain disambiguator. The same .css resource produces two
145
+ // distinct modules (style-loader+css-loader injector, and css-loader-only
146
+ // source). Both have identical `module.resource`, so without a suffix
147
+ // they collide on a single ID and the injector ends up importing
148
+ // itself — which surfaces as `ReferenceError: can't access lexical
149
+ // declaration 'A' before initialization` because `n.d(e,{default:()=>A})`
150
+ // returns the in-progress module's own (still-uninitialized) const.
151
+ // Bake a stable, readable suffix derived from the loader chain so the
152
+ // two modules always get different IDs.
153
+ const loaderSuffix = (m) => {
154
+ const loaders = m.loaders || [];
155
+ if (loaders.length === 0) return '';
156
+ const names = loaders
157
+ .map((l) => {
158
+ const match = l.loader && l.loader.match(/[\\/]([^\\/]+-loader)[\\/]/);
159
+ return match ? match[1] : null;
160
+ })
161
+ .filter(Boolean);
162
+ if (names.length === 0) return '';
163
+ // Style-loader presence is the decisive signal for the CSS pair,
164
+ // but include the full chain for any other multi-loader case.
165
+ return '?' + names.join('!');
166
+ };
167
+
168
+ const assignId = (m, baseId) => {
169
+ const suffix = loaderSuffix(m);
170
+ let id = baseId + suffix;
171
+ // Final safety net: if a collision still slipped through, append
172
+ // a numeric tiebreaker rather than silently sharing an ID.
173
+ if (usedIds.has(id)) {
174
+ let n = 2;
175
+ while (usedIds.has(`${id}#${n}`)) n++;
176
+ id = `${id}#${n}`;
177
+ }
178
+ usedIds.add(id);
179
+ compilation.chunkGraph.setModuleId(m, id);
180
+ };
181
+
143
182
  for (const module of modules) {
144
183
  if (module.id !== null) continue; // Already has an ID
145
-
184
+
146
185
  // Handle external modules
147
186
  if (module.constructor.name === 'ExternalModule') {
148
187
  const request = module.request || module.userRequest || `external-${fallbackId++}`;
149
- compilation.chunkGraph.setModuleId(module, request);
188
+ assignId(module, request);
150
189
  continue;
151
190
  }
152
-
191
+
153
192
  if (!module.resource) {
154
193
  // Assign numeric ID for modules without resources
155
- compilation.chunkGraph.setModuleId(module, fallbackId++);
194
+ assignId(module, String(fallbackId++));
156
195
  continue;
157
196
  }
158
197
 
159
198
  const resource = module.resource;
160
199
  let foundRelative = false;
161
-
200
+
162
201
  // Try to find a relative path from one of the resolve.modules paths
163
202
  for (const searchPath of modulePaths) {
164
203
  const absoluteSearchPath = path.resolve(cwd, searchPath);
@@ -168,17 +207,16 @@ function createWebpackConfig(config, options = {}) {
168
207
  .substring(absoluteSearchPath.length + 1)
169
208
  .replace(/\\/g, '/') // Normalize to forward slashes
170
209
  .replace(/\.(js|jsx|ts|tsx)$/, ''); // Remove extension
171
-
172
- // Set the module ID to the relative path
173
- compilation.chunkGraph.setModuleId(module, relativeId);
210
+
211
+ assignId(module, relativeId);
174
212
  foundRelative = true;
175
213
  break;
176
214
  }
177
215
  }
178
-
216
+
179
217
  // Fallback: use numeric ID if no relative path found
180
218
  if (!foundRelative) {
181
- compilation.chunkGraph.setModuleId(module, fallbackId++);
219
+ assignId(module, String(fallbackId++));
182
220
  }
183
221
  }
184
222
  });
@@ -326,16 +364,6 @@ function createWebpackConfig(config, options = {}) {
326
364
  moduleIds: false, // Disable default, we'll set IDs manually
327
365
  // Don't split runtime - keep it in entries for UMD compatibility
328
366
  runtimeChunk: false,
329
- // Disable scope hoisting (ModuleConcatenationPlugin) so each ESM
330
- // module keeps its own factory scope. With hoisting on, webpack 5
331
- // inlines jade-engine, jadechild and the site entry into one IIFE,
332
- // and css-loader 7's `n.d(e, {A: () => a})` getter (where `a` is a
333
- // `const` initialized at the end of the css module body) can be read
334
- // by a sibling export before its initializer line runs — surfacing as
335
- // `ReferenceError: can't access lexical declaration 'A' before
336
- // initialization` in main.bundle.js. Per-module factories close that
337
- // shared TDZ window for a small (~2 KB) bundle-size cost.
338
- concatenateModules: false,
339
367
  },
340
368
 
341
369
  devtool: isProduction ? 'cheap-source-map' : 'source-map',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@epublishing/grunt-epublishing",
3
3
  "description": "Modern front-end build tools for ePublishing Jade and client sites.",
4
- "version": "1.2.10",
4
+ "version": "1.2.11",
5
5
  "homepage": "https://www.epublishing.com",
6
6
  "contributors": [
7
7
  {