@plaudit/webpack-extensions 3.16.0 → 3.18.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.
Files changed (32) hide show
  1. package/CHANGELOG.md +88 -1
  2. package/README.md +22 -2
  3. package/USER-GUIDE.md +21 -16
  4. package/dist/plugins/AbstractBiPhasicGroupAndEntryPlugin.d.ts +1 -1
  5. package/dist/plugins/AbstractBiPhasicGroupPlugin.d.ts +3 -3
  6. package/dist/plugins/EnhancedBlockJSONPlugin.d.ts +1 -0
  7. package/dist/plugins/EnhancedBlockJSONPlugin.js +36 -25
  8. package/dist/plugins/MiniCSSExtractPluginErrorCleaner.d.ts +2 -3
  9. package/dist/plugins/PackageConfigSanityChecker.d.ts +2 -3
  10. package/dist/plugins/PlainEntrypointsConfigFileGeneratorPlugin.js +22 -9
  11. package/dist/plugins/VariablesJSMonitorPlugin.d.ts +2 -3
  12. package/dist/plugins/WPMLConfigBuilder.d.ts +2 -3
  13. package/dist/plugins/dependency-extraction-webpack-plugin-config-builder.d.ts +3 -6
  14. package/dist/plugins/dependency-extraction-webpack-plugin-config-builder.js +8 -21
  15. package/dist/shared.d.ts +24 -24
  16. package/dist/shared.js +41 -54
  17. package/dist/utils/common-config-helpers.d.ts +2 -2
  18. package/dist/utils/common-config-helpers.js +21 -13
  19. package/dist/utils/css-writer.js +3 -3
  20. package/dist/utils/entrypoint-resolution-logic.d.ts +5 -2
  21. package/dist/utils/location-encoding-filename-parser.d.ts +0 -1
  22. package/dist/utils/location-encoding-filename-parser.js +4 -3
  23. package/dist/utils/path-query-and-related-helpers.d.ts +0 -1
  24. package/dist/utils/path-query-and-related-helpers.js +0 -4
  25. package/dist/wordpress-ports/dependency-extraction-webpack-plugin/index.d.ts +72 -0
  26. package/dist/wordpress-ports/dependency-extraction-webpack-plugin/index.js +522 -0
  27. package/dist/wordpress-ports/dependency-extraction-webpack-plugin/util.d.ts +56 -0
  28. package/dist/wordpress-ports/dependency-extraction-webpack-plugin/util.js +150 -0
  29. package/dist/wordpress-scripts-wrapper.js +151 -89
  30. package/package.json +32 -8
  31. package/dist/plugins/BrowserSyncPlugin.d.ts +0 -25
  32. package/dist/plugins/BrowserSyncPlugin.js +0 -212
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultRequestToExternal = defaultRequestToExternal;
4
+ exports.defaultRequestToExternalModule = defaultRequestToExternalModule;
5
+ exports.defaultRequestToHandle = defaultRequestToHandle;
6
+ exports.camelCaseDash = camelCaseDash;
7
+ exports.isConcatenatedModule = isConcatenatedModule;
8
+ exports.isEntrypoint = isEntrypoint;
9
+ const WORDPRESS_NAMESPACE = '@wordpress/';
10
+ const BUNDLED_PACKAGES = [
11
+ '@wordpress/admin-ui',
12
+ '@wordpress/dataviews',
13
+ '@wordpress/dataviews/wp',
14
+ '@wordpress/fields',
15
+ '@wordpress/grid',
16
+ '@wordpress/icons',
17
+ '@wordpress/interface',
18
+ '@wordpress/style-runtime',
19
+ '@wordpress/ui',
20
+ '@wordpress/undo-manager',
21
+ '@wordpress/views',
22
+ ];
23
+ /**
24
+ * Default request to global transformation
25
+ *
26
+ * Transform @wordpress dependencies:
27
+ * - request `@wordpress/api-fetch` becomes `[ 'wp', 'apiFetch' ]`
28
+ * - request `@wordpress/i18n` becomes `[ 'wp', 'i18n' ]`
29
+ *
30
+ * @param {string} request Module request (the module name in `import from`) to be transformed
31
+ * @return {string|string[]|undefined} The resulting external definition. Return `undefined`
32
+ * to ignore the request. Return `string|string[]` to map the request to an external.
33
+ */
34
+ function defaultRequestToExternal(request) {
35
+ switch (request) {
36
+ case 'moment':
37
+ return request;
38
+ case '@babel/runtime/regenerator':
39
+ return 'regeneratorRuntime';
40
+ case 'lodash':
41
+ case 'lodash-es':
42
+ return 'lodash';
43
+ case 'jquery':
44
+ return 'jQuery';
45
+ case 'react':
46
+ return 'React';
47
+ case 'react-dom':
48
+ case 'react-dom/client':
49
+ return 'ReactDOM';
50
+ case 'react/jsx-runtime':
51
+ case 'react/jsx-dev-runtime':
52
+ return 'ReactJSXRuntime';
53
+ }
54
+ if (request.includes('react-refresh/runtime')) {
55
+ return 'ReactRefreshRuntime';
56
+ }
57
+ if (BUNDLED_PACKAGES.includes(request)) {
58
+ return undefined;
59
+ }
60
+ if (request.startsWith(WORDPRESS_NAMESPACE)) {
61
+ return [
62
+ 'wp',
63
+ camelCaseDash(request.substring(WORDPRESS_NAMESPACE.length)),
64
+ ];
65
+ }
66
+ return undefined;
67
+ }
68
+ /**
69
+ * Default request to external module transformation
70
+ *
71
+ * Currently only @wordpress/interactivity and `@wordpress/interactivity-router`
72
+ * are supported.
73
+ *
74
+ * Do not use the boolean shorthand here, it's only handled for the
75
+ * `requestToExternalModule` option.
76
+ *
77
+ * @param {string} request Module request (the module name in `import from`) to be transformed
78
+ * @return {string|undefined} The resulting external definition.
79
+ * - Return `undefined` to ignore the request (do not externalize).
80
+ * - Return `string` to map the request to an external.
81
+ * - Return `Error` to emit an error.
82
+ */
83
+ function defaultRequestToExternalModule(request) {
84
+ if (request === '@wordpress/interactivity') {
85
+ // This is a special case. Interactivity does not support dynamic imports at
86
+ // this time. We add the external "module" type to indicate that webpack
87
+ // should externalize this as a module (instead of our default `import()`
88
+ // external type) which forces @wordpress/interactivity imports to be
89
+ // hoisted to static imports.
90
+ return `module ${request}`;
91
+ }
92
+ switch (request) {
93
+ case '@wordpress/interactivity-router':
94
+ case '@wordpress/a11y':
95
+ return `import ${request}`;
96
+ }
97
+ const isWordPressScript = Boolean(defaultRequestToExternal(request));
98
+ if (isWordPressScript) {
99
+ throw new Error(`Attempted to use WordPress script in a module: ${request}, which is not supported yet.`);
100
+ }
101
+ return undefined;
102
+ }
103
+ /**
104
+ * Default request to WordPress script handle transformation
105
+ *
106
+ * Transform @wordpress dependencies:
107
+ * - request `@wordpress/i18n` becomes `wp-i18n`
108
+ * - request `@wordpress/escape-html` becomes `wp-escape-html`
109
+ *
110
+ * @param {string} request Module request (the module name in `import from`) to be transformed
111
+ * @return {string|undefined} WordPress script handle to map the request to. Return `undefined`
112
+ * to use the same name as the module.
113
+ */
114
+ function defaultRequestToHandle(request) {
115
+ switch (request) {
116
+ case '@babel/runtime/regenerator':
117
+ return 'regenerator-runtime';
118
+ case 'lodash-es':
119
+ return 'lodash';
120
+ case 'react-dom/client':
121
+ return 'react-dom';
122
+ case 'react/jsx-runtime':
123
+ return 'react-jsx-runtime';
124
+ }
125
+ if (request.includes('react-refresh/runtime')) {
126
+ return 'wp-react-refresh-runtime';
127
+ }
128
+ if (request.startsWith(WORDPRESS_NAMESPACE)) {
129
+ return 'wp-' + request.substring(WORDPRESS_NAMESPACE.length);
130
+ }
131
+ return undefined;
132
+ }
133
+ /**
134
+ * Given a string, returns a new string with dash separators converted to
135
+ * camelCase equivalent. This is not as aggressive as `_.camelCase` in
136
+ * converting to uppercase, where Lodash will also capitalize letters
137
+ * following numbers.
138
+ *
139
+ * @param {string} string Input dash-delimited string.
140
+ * @return {string} Camel-cased string.
141
+ */
142
+ function camelCaseDash(string) {
143
+ return string.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
144
+ }
145
+ function isConcatenatedModule(module) {
146
+ return 'modules' in module && Array.isArray(module.modules);
147
+ }
148
+ function isEntrypoint(group) {
149
+ return !!group && group.constructor.name === 'Entrypoint';
150
+ }
@@ -10,7 +10,6 @@ const entrypoint_resolution_logic_1 = require("./utils/entrypoint-resolution-log
10
10
  const common_config_helpers_1 = require("./utils/common-config-helpers");
11
11
  const path_query_and_related_helpers_1 = require("./utils/path-query-and-related-helpers");
12
12
  const AdditionalDependencyInjectorPlugin_1 = require("./plugins/AdditionalDependencyInjectorPlugin");
13
- const BrowserSyncPlugin_1 = require("./plugins/BrowserSyncPlugin");
14
13
  const dependency_extraction_webpack_plugin_config_builder_1 = require("./plugins/dependency-extraction-webpack-plugin-config-builder");
15
14
  const EnhancedDynamicEntryPlugin_1 = require("./plugins/EnhancedDynamicEntryPlugin");
16
15
  const ExtensionsConfigFileGeneratorPlugin_1 = require("./plugins/ExtensionsConfigFileGeneratorPlugin");
@@ -90,7 +89,7 @@ function replaceDefaultURLProcessing(useWebpackResourceFiltering) {
90
89
  }
91
90
  function injectPostcssConfigOverrides(rules, config, variables, postcssFunctionsConfig) {
92
91
  const postcssConfig = (0, static_configs_1.postcssConfigBuilder)(name => variables(name) ?? (name === 'ENV' ? '' : undefined), postcssFunctionsConfig);
93
- return recursivelyAddParentDirectoryStepToImagesAndFonts(rules.map(rule => {
92
+ return rules.map(rule => {
94
93
  if (rule && typeof rule === 'object') {
95
94
  if (Array.isArray(rule.use)) {
96
95
  for (const useItem of rule.use) {
@@ -130,26 +129,6 @@ function injectPostcssConfigOverrides(rules, config, variables, postcssFunctions
130
129
  }
131
130
  }
132
131
  return rule;
133
- }), config);
134
- }
135
- function recursivelyAddParentDirectoryStepToImagesAndFonts(rules, config) {
136
- if (config.outputDir) {
137
- return rules;
138
- }
139
- return rules.map(rule => {
140
- if (rule && typeof rule === 'object') {
141
- if (typeof rule.generator === 'object') {
142
- const ruleGeneratorFilename = rule.generator["filename"];
143
- if (typeof ruleGeneratorFilename === 'string' && (ruleGeneratorFilename.startsWith("images/") || ruleGeneratorFilename.startsWith("fonts/"))) {
144
- rule.generator["filename"] = `../${ruleGeneratorFilename}`;
145
- rule = { ...rule, generator: { ...rule.generator, filename: `../${ruleGeneratorFilename}` } };
146
- }
147
- }
148
- if (rule.oneOf) {
149
- rule = { ...rule, oneOf: recursivelyAddParentDirectoryStepToImagesAndFonts(rule.oneOf, config) };
150
- }
151
- }
152
- return rule;
153
132
  });
154
133
  }
155
134
  function injectSupportForInliningSVGsAsStrings(rules) {
@@ -167,9 +146,9 @@ function injectSupportForInliningSVGsAsStrings(rules) {
167
146
  }
168
147
  function buildVerifiedConfig(config) {
169
148
  config = (0, shared_1.applyStandards)(config);
170
- const { standaloneBlocks = false, stats = 'errors-warnings', variables: rawVariables, verbose = process.argv.includes('--verbose') || process.env['VERBOSE'] === 'true', postcss = {}, externals, assumeGlobalizedPlauditLibraries = true, processTranslationConfigs = true, combineAssetMetadata = true, useWebpackResourceFiltering = true, plainEntrypointsVersion = 1, srcDir = "", useUnifiedLoader = false, includePostInitFallback = false, omitDistDev = false, onlyRunPostCSSOnPCSS = false, useBlockSupportsAsThemeJsonDefaults = true, } = config;
149
+ const { standaloneBlocks = false, stats = 'errors-warnings', variables: rawVariables, verbose = process.argv.includes('--verbose') || process.env['VERBOSE'] === 'true', postcss = {}, externals, assumeGlobalizedPlauditLibraries = true, useWebpackResourceFiltering = true, plainEntrypointsVersion = 1, srcDir = "", useUnifiedLoader = false, includePostInitFallback = false, omitDistDev = false, onlyRunPostCSSOnPCSS = false, useBlockSupportsAsThemeJsonDefaults = true, } = config;
171
150
  let outputDir = config.outputDir ?? "";
172
- if (outputDir && useUnifiedLoader && !omitDistDev && (process.env['SERVER_MODE'] ?? 'development') === 'development') {
151
+ if ((0, shared_1.shouldWriteDistDev)({ outputDir, useUnifiedLoader, omitDistDev })) {
173
152
  outputDir += "-dev";
174
153
  }
175
154
  let srcPrefixes;
@@ -183,7 +162,7 @@ function buildVerifiedConfig(config) {
183
162
  let targetHandlePrefix = config.targetHandlePrefix ?? config.plainEntrypointsHandlePrefix ?? "";
184
163
  if (plainEntrypointsVersion > 1) {
185
164
  if (!targetHandlePrefix) {
186
- targetHandlePrefix = deriveDefaultHandlePrefixFromComposerJsonOrThemeName(shared_1.kebabCase);
165
+ targetHandlePrefix = deriveDefaultHandlePrefixFromComposerJsonOrThemeName(shared_1.kebabCase) ?? "";
187
166
  if (!targetHandlePrefix) {
188
167
  throw new Error("Plain Entrypoints V2 and higher require either 'targetHandlePrefix' to be set or an adjacent composer.json or style.css file to be present");
189
168
  }
@@ -192,7 +171,9 @@ function buildVerifiedConfig(config) {
192
171
  throw new Error("Plain Entrypoints V2 and higher require 'outputDir' to be set");
193
172
  }
194
173
  }
195
- const targetNamespace = config.targetNamespace || deriveDefaultHandlePrefixFromComposerJsonOrThemeName(shared_1.camelCaseForPHPLabels, true);
174
+ // Only the lazyLoader emitters read this, so an absence of package metadata is not worth failing a build
175
+ // over: php-writer treats an empty namespace as "emit no namespace", which is what we did before 3.10.0
176
+ const targetNamespace = config.targetNamespace || deriveDefaultHandlePrefixFromComposerJsonOrThemeName(shared_1.camelCaseForPHPLabels, true) || "";
196
177
  const { staticEntrypoints, dynamicEntrypoints } = (0, entrypoint_resolution_logic_1.resolveAllConfigLevelEntrypoints)(config);
197
178
  const rawSources = [...staticEntrypoints, ...dynamicEntrypoints];
198
179
  let variablesFilePath = undefined;
@@ -205,31 +186,58 @@ function buildVerifiedConfig(config) {
205
186
  extensionsVersion = 3; // Version 3 is a backwards-compatible upgrade of version 2, so we can automatically upgrade everything
206
187
  }
207
188
  const cfg = {
208
- currentVariables, postcss, standaloneBlocks, stats, variablesFilePath, verbose, externals, assumeGlobalizedPlauditLibraries, processTranslationConfigs, combineAssetMetadata,
209
- useWebpackResourceFiltering, outputDir, extensionsVersion, plainEntrypointsVersion, srcDir, srcPrefixes, targetHandlePrefix, useUnifiedLoader, includePostInitFallback, omitDistDev,
210
- onlyRunPostCSSOnPCSS, targetNamespace, useBlockSupportsAsThemeJsonDefaults
189
+ currentVariables, postcss, standaloneBlocks, stats, variablesFilePath, verbose, externals, assumeGlobalizedPlauditLibraries,
190
+ useWebpackResourceFiltering, outputDir, extensionsVersion, plainEntrypointsVersion, srcDir, srcPrefixes, targetHandlePrefix,
191
+ useUnifiedLoader, includePostInitFallback, omitDistDev, onlyRunPostCSSOnPCSS, targetNamespace, useBlockSupportsAsThemeJsonDefaults
211
192
  };
212
193
  // Destination -> source map
213
194
  const allocatedDestinations = {};
214
- const partiallyVerifiedSources = rawSources.map(rawSource => {
215
- const { destination, additionalDependencies = [], assumeGlobalizedPlauditLibraries = cfg.assumeGlobalizedPlauditLibraries, bundleAnalyzer = false, directoryLayout, externalize, withLegacyBlocksIn = false, lazyLoader, pathQueryParameters: rawPathQueryParameters, enqueuingFlags: rawEnqueuingFlags } = rawSource[1];
216
- const { flags: queryEnqueuingFlags, remainder: pathQueryParameters } = (0, path_query_and_related_helpers_1.unpackEnqueuingControlFlagsFromPathQueryParameters)(rawPathQueryParameters, rawSource[0], 'path query parameters');
217
- const enqueuingFlags = (0, path_query_and_related_helpers_1.mergeTwoEnqueuingControlFlagSets)(rawSource[0], rawEnqueuingFlags, queryEnqueuingFlags);
195
+ const partiallyVerifiedSources = rawSources.map(([src, config]) => {
196
+ const { destination, additionalDependencies = [], assumeGlobalizedPlauditLibraries = cfg.assumeGlobalizedPlauditLibraries, bundleAnalyzer = false, directoryLayout, externalize, withLegacyBlocksIn = false, lazyLoader, pathQueryParameters: rawPathQueryParameters, enqueuingFlags: rawEnqueuingFlags, locations: rawSourceLocations, } = config;
197
+ // This guards against a crash later on down the line due to trying to run a spread on a boolean
198
+ if (externalize && typeof externalize !== 'string' && typeof externalize !== 'object') {
199
+ throw new TypeError(`externalize must be a string, an array or an object, but "${src}" set externalize to a ${typeof externalize}`);
200
+ }
201
+ const { flags: queryEnqueuingFlags, remainder: pathQueryParameters, handle: pathQueryHandle } = (0, path_query_and_related_helpers_1.unpackEnqueuingControlFlagsFromPathQueryParameters)(rawPathQueryParameters, src, 'path query parameters');
202
+ const enqueuingFlags = (0, path_query_and_related_helpers_1.mergeTwoEnqueuingControlFlagSets)(src, rawEnqueuingFlags, queryEnqueuingFlags);
218
203
  const normalizedParts = { additionalDependencies, assumeGlobalizedPlauditLibraries, bundleAnalyzer, directoryLayout, externalize, withLegacyBlocksIn, lazyLoader };
219
- const locations = typeof rawSource[1].locations === 'string' || typeof rawSource[1].locations === 'function' || (rawSource[1].locations && 'niceName' in rawSource[1].locations)
220
- ? { handle: rawSource[1].locations } : rawSource[1].locations ?? {};
204
+ let locations;
205
+ if (pathQueryHandle === undefined) {
206
+ locations = typeof rawSourceLocations === 'string' || typeof rawSourceLocations === 'function' || (rawSourceLocations !== undefined && 'niceName' in rawSourceLocations)
207
+ ? { handle: rawSourceLocations } : rawSourceLocations ?? {};
208
+ }
209
+ else {
210
+ const rawSourceHandle = typeof rawSourceLocations === 'string' || typeof rawSourceLocations === 'function' || (rawSourceLocations !== undefined && 'niceName' in rawSourceLocations)
211
+ ? rawSourceLocations : rawSourceLocations?.handle;
212
+ if (rawSourceHandle === undefined) {
213
+ locations = { handle: pathQueryHandle };
214
+ }
215
+ else if (typeof rawSourceHandle === 'string') {
216
+ if (rawSourceHandle !== pathQueryHandle) {
217
+ throw new ReferenceError(`Encountered mismatched handles "${rawSourceHandle}" and "${pathQueryHandle}" when preparing "${src}"`);
218
+ }
219
+ locations = { handle: pathQueryHandle };
220
+ }
221
+ else {
222
+ throw new ReferenceError(`Encountered a function handle and a path query handle when preparing "${src}"`);
223
+ }
224
+ // This is just a means of merging the new handle into the rawSourceLocations config without mutating the base config
225
+ if (rawSourceLocations !== undefined && typeof rawSourceLocations !== 'function' && typeof rawSourceLocations !== 'string') {
226
+ locations = { ...rawSourceLocations, ...locations };
227
+ }
228
+ }
221
229
  if (typeof locations.registerScriptArgs === 'string' && !['lazy', 'eager', 'inline'].includes(locations.registerScriptArgs)) {
222
230
  throw new ReferenceError("The only supported string values for registerScriptArgs are 'lazy', 'eager', and 'inline'");
223
231
  }
224
232
  if (destination !== undefined) {
225
233
  const effectiveDestination = toEffectiveWebpackDestination(destination);
226
- allocatedDestinations[effectiveDestination] = rawSource[0]; // We need to pre-populate the allocatedDestinations map with statically declared destinations
227
- return [rawSource[0], { ...normalizedParts, locations, destination, effectiveDestination, staticallyDeclaredDestination: true, pathQueryParameters, enqueuingFlags }];
234
+ allocatedDestinations[effectiveDestination] = src; // We need to pre-populate the allocatedDestinations map with statically declared destinations
235
+ return [src, { ...normalizedParts, locations, destination, effectiveDestination, staticallyDeclaredDestination: true, pathQueryParameters, enqueuingFlags }];
228
236
  }
229
237
  else {
230
- const naiveDestination = deriveNaiveDestinationFromUnverifiedSourceEntry(rawSource, srcPrefixes);
238
+ const naiveDestination = deriveNaiveDestinationFromUnverifiedSourceEntry(src, destination, srcPrefixes);
231
239
  const effectiveDestination = toEffectiveWebpackDestination(naiveDestination);
232
- return [rawSource[0], { ...normalizedParts, locations, destination: naiveDestination, effectiveDestination, staticallyDeclaredDestination: false, pathQueryParameters, enqueuingFlags }];
240
+ return [src, { ...normalizedParts, locations, destination: naiveDestination, effectiveDestination, staticallyDeclaredDestination: false, pathQueryParameters, enqueuingFlags }];
233
241
  }
234
242
  });
235
243
  const dynamicEffectiveDestinationsWithExpectedNaiveDuplicates = partiallyVerifiedSources
@@ -248,7 +256,7 @@ function toEffectiveWebpackDestination(destination) {
248
256
  const pathParts = (0, node_path_1.parse)(destination);
249
257
  return (0, node_path_1.join)(pathParts.dir, pathParts.name);
250
258
  }
251
- function deriveNaiveDestinationFromUnverifiedSourceEntry([src, { destination }], srcPrefixes) {
259
+ function deriveNaiveDestinationFromUnverifiedSourceEntry(src, destination, srcPrefixes) {
252
260
  if (destination !== undefined) {
253
261
  return destination;
254
262
  }
@@ -287,11 +295,14 @@ function finalizeEntryDestination(entry, dynamicEffectiveDestinationsWithExpecte
287
295
  allocatedDestinations[derivedDestination] = entry[0];
288
296
  return [entry[0], { ...entry[1], destination: derivedDestination }];
289
297
  }
290
- let defaultHandlePrefix = undefined;
298
+ /**
299
+ * TODO: WTF is the bot on about here?
300
+ * Derives a prefix from whichever piece of package metadata sits next to the config. Returns undefined
301
+ * when there is nothing to derive from at all — a caller that cannot proceed without one says so itself,
302
+ * because the ones that can (see `targetNamespace`) would otherwise fail builds that never needed it. A
303
+ * file that *is* present but unusable still throws, since that is a misconfiguration rather than an absence.
304
+ */
291
305
  function deriveDefaultHandlePrefixFromComposerJsonOrThemeName(stringTransformer, keepPlauditSep = false) {
292
- if (defaultHandlePrefix !== undefined) {
293
- return defaultHandlePrefix;
294
- }
295
306
  let composerJson;
296
307
  try {
297
308
  composerJson = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(process.cwd(), "composer.json"), 'utf-8'));
@@ -306,7 +317,12 @@ function deriveDefaultHandlePrefixFromComposerJsonOrThemeName(stringTransformer,
306
317
  return stringTransformer(keepPlauditSep ? composerJson.name.replace(/plaudit\/plaudit-/, 'plaudit/') : composerJson.name.replace(/plaudit\/plaudit/, 'plaudit'));
307
318
  }
308
319
  function deriveDefaultHandlePrefixFromThemeName(stringTransformer) {
309
- const styleFileContents = (0, node_fs_1.readFileSync)((0, node_path_1.join)(process.cwd(), "style.css"), 'utf-8');
320
+ const styleFilePath = (0, node_path_1.join)(process.cwd(), "style.css");
321
+ if (!(0, node_fs_1.existsSync)(styleFilePath)) {
322
+ // Then there is no package metadata to derive anything from
323
+ return undefined;
324
+ }
325
+ const styleFileContents = (0, node_fs_1.readFileSync)(styleFilePath, 'utf-8');
310
326
  const themeName = /^\W*Theme\s*Name:\s*(.+)$/im.exec(styleFileContents)?.[1]?.trim();
311
327
  if (!themeName) {
312
328
  throw new ReferenceError("targetHandlePrefix was not set and the adjacent style.css file does not have a valid name in it");
@@ -331,34 +347,73 @@ function withDerivedOutputDir(cfg, sources) {
331
347
  })
332
348
  };
333
349
  }
350
+ let forkTsCheckerInstalled = false;
351
+ function isTypeScriptSourceFile(file) {
352
+ return /\.[cm]?tsx?$/i.test(file.split('?')[0] ?? '');
353
+ }
354
+ const prefixes = ['c', 'm', ''];
355
+ const suffixes = ['x', ''];
356
+ const tsExtensions = prefixes.map(prefix => prefix + "ts").flatMap(name => suffixes.map(suffix => name + suffix));
334
357
  function handleDisablingTSCheckerIfNecessary(srcRoot, scriptExtension, plugins) {
335
- if (process.env["NO_TS_CHECKER"] !== "true") {
336
- const include = (Array.isArray(srcRoot) ? srcRoot : [srcRoot])
337
- .filter(sr => (0, node_path_1.extname)(sr).length === 0 || (0, shared_1.scriptOrStyleTest)(sr, scriptExtension) === "script")
338
- .map(sr => (0, node_path_1.extname)(sr).length > 0 ? sr : (0, node_path_1.join)(sr, "**", "*"));
339
- if (include.length > 0) {
340
- plugins.push(new fork_ts_checker_webpack_plugin_1.default({
341
- async: true,
342
- typescript: {
343
- diagnosticOptions: {
344
- semantic: true,
345
- syntactic: true,
346
- },
347
- configOverwrite: {
348
- include,
349
- compilerOptions: {
350
- skipLibCheck: true
351
- }
352
- }
353
- },
354
- issue: {
355
- exclude(issue) {
356
- return issue.code === 'TS18003'; // This hides the "no TypeScript files found" error while still monitoring the directory
357
- }
358
- }
359
- }));
358
+ if (process.env["NO_TS_CHECKER"] === "true" || forkTsCheckerInstalled) {
359
+ return;
360
+ }
361
+ const include = [];
362
+ for (const sr of (Array.isArray(srcRoot) ? srcRoot : [srcRoot])) {
363
+ if ((0, node_path_1.extname)(sr).length === 0) {
364
+ include.push(...tsExtensions.map(tsExt => (0, node_path_1.join)(sr, "**", `*.${tsExt}`)));
365
+ }
366
+ else if ((0, shared_1.scriptOrStyleTest)(sr, scriptExtension) === "script") {
367
+ include.push(sr);
360
368
  }
361
369
  }
370
+ if (include.length === 0) {
371
+ return;
372
+ }
373
+ forkTsCheckerInstalled = true;
374
+ let logTsStatus = true;
375
+ plugins.push({
376
+ apply(compiler) {
377
+ compiler.hooks.watchRun.tap('PlauditForkTsCheckerCssQuiet', watchingCompiler => {
378
+ const changed = [
379
+ ...(watchingCompiler.modifiedFiles ?? []),
380
+ ...(watchingCompiler.removedFiles ?? [])
381
+ ];
382
+ logTsStatus = changed.length === 0 || changed.some(isTypeScriptSourceFile);
383
+ });
384
+ }
385
+ });
386
+ plugins.push(new fork_ts_checker_webpack_plugin_1.default({
387
+ async: true,
388
+ logger: {
389
+ log(message) {
390
+ if (!logTsStatus) {
391
+ return;
392
+ }
393
+ console.log(message);
394
+ },
395
+ error(message) {
396
+ console.error(message);
397
+ }
398
+ },
399
+ typescript: {
400
+ diagnosticOptions: {
401
+ semantic: true,
402
+ syntactic: true,
403
+ },
404
+ configOverwrite: {
405
+ include,
406
+ compilerOptions: {
407
+ skipLibCheck: true
408
+ }
409
+ }
410
+ },
411
+ issue: {
412
+ exclude(issue) {
413
+ return issue.code === 'TS18003';
414
+ }
415
+ }
416
+ }));
362
417
  }
363
418
  function buildCommonPluginConfig(webpackConfig, config, bundleAnalyzer, assumeGlobalizedPlauditLibraries, externalize) {
364
419
  const plugins = webpackConfig.plugins?.filter(v => !!v)
@@ -378,7 +433,7 @@ function buildCommonPluginConfig(webpackConfig, config, bundleAnalyzer, assumeGl
378
433
  ?? [];
379
434
  plugins.splice(0, 0, new PackageConfigSanityChecker_1.PackageConfigSanityChecker());
380
435
  if (bundleAnalyzer) {
381
- plugins.splice(0, 0, new (require("webpack-bundle-analyzer").BundleAnalyzerPlugin)({ analyzerMode: 'static' }));
436
+ plugins.splice(0, 0, new (require("webpack-bundle-analyzer").BundleAnalyzerPlugin)({ analyzerMode: 'static', openAnalyzer: bundleAnalyzer !== 'no-auto-open' }));
382
437
  }
383
438
  const removeEmptyScriptsPlugin = new webpack_remove_empty_scripts_1.default({
384
439
  stage: webpack_remove_empty_scripts_1.default.STAGE_AFTER_PROCESS_PLUGINS,
@@ -401,9 +456,15 @@ function buildCommonPluginConfig(webpackConfig, config, bundleAnalyzer, assumeGl
401
456
  console.error("Once those commands have finished, re-run whichever command had this error. If it still doesn't work, report the issue immediately.");
402
457
  throw new Error("Cannot apply externals when they have been disabled via CLI flag. This will greatly increase bundle size and will likely cause the build to fail");
403
458
  }
404
- const builtDependencyExtractionWebpackPlugin = (0, dependency_extraction_webpack_plugin_config_builder_1.makeDependencyExtractionPlugin)(config.externals, assumeGlobalizedPlauditLibraries, true, externalize);
405
- plugins[dependencyExtractionPluginIndex] = builtDependencyExtractionWebpackPlugin.instance;
406
- plugins.push(new BrowserSyncPlugin_1.BrowserSyncPlugin());
459
+ const builtDependencyExtractionWebpackPlugin = (0, dependency_extraction_webpack_plugin_config_builder_1.makeDependencyExtractionPlugin)(config.externals, assumeGlobalizedPlauditLibraries, externalize);
460
+ plugins[dependencyExtractionPluginIndex] = builtDependencyExtractionWebpackPlugin;
461
+ if ((0, shared_1.isDistDevOutputPath)(config.outputDir)) {
462
+ try {
463
+ const { PlauditDevPlugin } = require("@plaudit/dev-webpack-plugin");
464
+ plugins.push(new PlauditDevPlugin());
465
+ }
466
+ catch { }
467
+ }
407
468
  return {
408
469
  plugins, removeEmptyScriptsPlugin,
409
470
  makeAdditionalDependencyInjectorPlugin(referencePlugin) {
@@ -431,16 +492,14 @@ function commonConfigProcessingPrep(config, webpackConfig) {
431
492
  },
432
493
  injectSupportForInliningSVGsAsStrings
433
494
  ].reduce((r, a) => a(r), webpackConfig.module?.rules ?? []);
434
- if (config.processTranslationConfigs) {
435
- fixedRules.push({
436
- test: /wpml-config\.xml$/i,
437
- type: 'asset/resource',
438
- generator: {
439
- filename: '[name][ext]',
440
- emit: false
441
- }
442
- });
443
- }
495
+ fixedRules.push({
496
+ test: /wpml-config\.xml$/i,
497
+ type: 'asset/resource',
498
+ generator: {
499
+ filename: '[name][ext]',
500
+ emit: false
501
+ }
502
+ });
444
503
  return {
445
504
  entrypointFields, fixedRules, processingModules, scriptExtension,
446
505
  updateCurrentVariables: (value) => currentVariables = value
@@ -452,7 +511,7 @@ function destToKey(dest) {
452
511
  : dest.externalize?.toString() ?? "undefined";
453
512
  return [dest.assumeGlobalizedPlauditLibraries, dest.bundleAnalyzer, externalize].join("~");
454
513
  }
455
- function processIndividualWebpackConfig(config, webpackConfig, sources, canClean) {
514
+ function processIndividualWebpackConfig(config, webpackConfig, sources, canClean, preferNonModuleTsChecker) {
456
515
  if (webpackConfig.output?.module) {
457
516
  // This ensures that module files are emitted as module files
458
517
  webpackConfig = {
@@ -486,7 +545,9 @@ function processIndividualWebpackConfig(config, webpackConfig, sources, canClean
486
545
  return batches.map(currentBatch => {
487
546
  const { bundleAnalyzer, assumeGlobalizedPlauditLibraries, externalize } = currentBatch[0].dest;
488
547
  const { plugins, removeEmptyScriptsPlugin, makeAdditionalDependencyInjectorPlugin } = buildCommonPluginConfig(webpackConfig, config, bundleAnalyzer, assumeGlobalizedPlauditLibraries, externalize);
489
- handleDisablingTSCheckerIfNecessary(currentBatch.flatMap(a => a.srcRoots), scriptExtension, plugins);
548
+ if (!processingModules || !preferNonModuleTsChecker) {
549
+ handleDisablingTSCheckerIfNecessary(currentBatch.flatMap(a => a.srcRoots), scriptExtension, plugins);
550
+ }
490
551
  const applicableExtensionTest = (name) => {
491
552
  return commonConfig.scriptExtension.test(name) || (!processingModules && shared_1.styleExtension.test(name));
492
553
  };
@@ -500,7 +561,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources, canClean
500
561
  }
501
562
  plugin = new EnhancedBlockJSONPlugin_1.EnhancedBlockJSONPlugin(config, dest, removeEmptyScriptsPlugin, contextPath, (0, common_config_helpers_1.resolveEntryFromDirectory)(commonConfig, srcRoot, dest));
502
563
  plugins.push(plugin);
503
- if (config.processTranslationConfigs && !processingModules) {
564
+ if (!processingModules) {
504
565
  plugins.push(new WPMLConfigBuilder_1.WPMLConfigBuilderPlugin(dest.destination, plugin));
505
566
  }
506
567
  }
@@ -627,12 +688,13 @@ module.exports = function (config, webpackConfig = require("@wordpress/scripts/c
627
688
  webpackConfig = webpackConfig[0];
628
689
  }
629
690
  if (Array.isArray(webpackConfig)) {
691
+ const hasNonModuleCompiler = webpackConfig.some(cfg => !cfg.output?.module);
630
692
  return webpackConfig.toSorted((a, b) => {
631
693
  if (a.output?.module) {
632
694
  return b.output?.module ? 0 : -1;
633
695
  }
634
696
  return b.output?.module ? 1 : 0;
635
- }).flatMap(wpCfg => processIndividualWebpackConfig(cfg, wpCfg, sources, false));
697
+ }).flatMap(wpCfg => processIndividualWebpackConfig(cfg, wpCfg, sources, false, hasNonModuleCompiler));
636
698
  }
637
- return processIndividualWebpackConfig(cfg, webpackConfig, sources, true);
699
+ return processIndividualWebpackConfig(cfg, webpackConfig, sources, true, false);
638
700
  };
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@plaudit/webpack-extensions",
3
- "version": "3.16.0",
3
+ "version": "3.18.0",
4
4
  "license": "SEE LICENSE IN LICENSE.md",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/plaudit/plaudit-webpack-extensions.git"
8
+ },
5
9
  "files": [
6
10
  "/dist",
7
11
  "README.md",
@@ -28,16 +32,24 @@
28
32
  }
29
33
  },
30
34
  "devDependencies": {
31
- "@plaudit/gutenberg-api-extensions": "^2.98.0",
32
- "@types/browser-sync-webpack-plugin": "^2.2.5",
35
+ "@plaudit/dev-webpack-plugin": "^1.0.1",
36
+ "@plaudit/gutenberg-api-extensions": "^2.98.2",
33
37
  "@types/jsdom": "^28.0.3",
34
38
  "@types/node": "^25.9.5",
35
39
  "@types/postcss-functions": "^4.0.4",
36
40
  "@types/postcss-import": "^14.0.3",
37
41
  "@types/tapable": "^2.3.0",
38
42
  "@types/webpack-sources": "^3.2.3",
43
+ "atob": "^2.1.2",
44
+ "css-loader": "^6.11.0",
45
+ "glob": "^7.2.3",
46
+ "jest": "^30.4.2",
47
+ "lodash": "^4.18.1",
48
+ "mini-css-extract-plugin": "^2.10.2",
49
+ "mkdirp": "^3.0.1",
39
50
  "react": "^18.3.1",
40
51
  "react-dom": "^18.3.1",
52
+ "rimraf": "^5.0.10",
41
53
  "typescript": "^6.0.3",
42
54
  "webpack-bundle-analyzer": "^5.3.1"
43
55
  },
@@ -46,10 +58,9 @@
46
58
  "@plaudit/postcss-color-function": "^5.1.0",
47
59
  "@plaudit/postcss-strip-units": "^3.0.0",
48
60
  "@plaudit/postcss-variables": "^2.0.1",
49
- "@wordpress/dependency-extraction-webpack-plugin": "^6.51.0",
61
+ "@wordpress/dependency-extraction-webpack-plugin": "^6.53.0",
50
62
  "@wordpress/scripts": "^32.6.0",
51
63
  "autoprefixer": "^10.5.4",
52
- "browser-sync": "^3.0.4",
53
64
  "copy-webpack-plugin": "10.2.4",
54
65
  "css-minimizer-webpack-plugin": "^8.0.0",
55
66
  "cssnano": "^7.1.9",
@@ -57,20 +68,28 @@
57
68
  "http-proxy-middleware": "^3.0.7",
58
69
  "jsdom": "^29.1.1",
59
70
  "json2php": "0.0.12",
60
- "postcss": "^8.5.20",
71
+ "postcss": "^8.5.26",
61
72
  "postcss-calc": "^10.1.1",
62
73
  "postcss-functions": "^4.0.2",
63
- "postcss-import": "^16.1.1",
74
+ "postcss-import": "^16.2.0",
64
75
  "postcss-loader": "^8.2.1",
65
76
  "postcss-mixins": "^12.1.2",
66
77
  "postcss-nested": "^7.0.2",
67
78
  "postcss-property-lookup": "^3.0.0",
68
79
  "postcss-reporter": "^7.1.0",
69
80
  "postcss-url": "^10.1.4",
70
- "webpack": "^5.108.4",
81
+ "webpack": "^5.109.2",
71
82
  "webpack-remove-empty-scripts": "^1.1.1",
72
83
  "xml-formatter": "^3.7.0"
73
84
  },
85
+ "peerDependencies": {
86
+ "@plaudit/dev-webpack-plugin": "^1.0.0"
87
+ },
88
+ "peerDependenciesMeta": {
89
+ "@plaudit/dev-webpack-plugin": {
90
+ "optional": true
91
+ }
92
+ },
74
93
  "engines": {
75
94
  "node": ">=20"
76
95
  },
@@ -79,6 +98,11 @@
79
98
  "clean": "rm -rf dist",
80
99
  "build:clean": "pnpm run clean && pnpm run build",
81
100
  "watch": "tsc -w",
101
+ "test": "pnpm run build && pnpm run test:no-build",
102
+ "test:no-build": "rm -rf tests/.tmp/coverage/jest && NODE_V8_COVERAGE=tests/.tmp/coverage/jest jest",
103
+ "test:update": "pnpm run build && rm -rf tests/.tmp/coverage/jest && NODE_V8_COVERAGE=tests/.tmp/coverage/jest jest -u",
104
+ "test:paths": "pnpm run build && jest \"tests/integration-[0-9]+x/paths\"",
105
+ "test:gaps": "node tests/tools/coverage-gaps.js",
82
106
  "update": "pnpm add --config '@plaudit/pnpm-plugin-plaudit-config@*' && pnpm up"
83
107
  }
84
108
  }
@@ -1,25 +0,0 @@
1
- import { type WebpackPlugin } from "../shared";
2
- import browserSync, { type BrowserSyncInstance } from "browser-sync";
3
- import type { Compiler } from "webpack";
4
- export type PluginOptions = {
5
- reload: boolean;
6
- name: string;
7
- callback?: (err: Error, bs: BrowserSyncInstance) => any;
8
- injectCss: boolean;
9
- middlewareBuilder?: (options: browserSync.Options) => browserSync.Options['middleware'];
10
- };
11
- export declare class BrowserSyncPlugin implements WebpackPlugin {
12
- private static isBrowserSyncRunning;
13
- private static browserSyncPluginOptions?;
14
- private readonly pluginOptions;
15
- private readonly browserSyncInstance;
16
- private isWebpackWatching;
17
- private mostRecentChunkHashes;
18
- private shouldNotify;
19
- constructor(pluginOptions?: Partial<PluginOptions>);
20
- private static getBrowserSyncPluginOptions;
21
- private static findEnvFile;
22
- apply(compiler: Compiler): void;
23
- private getCssOnlyEmittedAssetsNames;
24
- private static getSiteUrls;
25
- }