@plaudit/webpack-extensions 3.16.0 → 3.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.17.0] - 2026-08-18
9
+ ### Added
10
+ - A port of WordPress's Dependency Extraction Webpack Plugin because they keep breaking it
11
+ - This comes from version `2.96.0`
12
+ - Warnings and additional info for entrypoints that are lazy-loaded and assigned to actual locations
13
+ - This comes from version `2.96.0`
14
+ - An `externalize` that is not a string, an array, an object, or false is now rejected rather than silently ignored
15
+ - This matches with what webpack's `output.library` config supports
16
+
17
+ ### Changed
18
+ - `handle` callbacks are now passed the un-prefixed nice name rather than the fully-prefixed handle
19
+ - The `{basename}` token in the string form has always substituted the un-prefixed name, so the two spellings of the option disagreed. A callback like ``name => `acme.cb-${name}` `` was producing `acme.cb-my-theme/thing`
20
+ - Nice names taken from a filename are now kebab-cased, the way the basename-derived handle they replace already was
21
+ - `view.MyThing.ts` is `<prefix>/my-thing` rather than `<prefix>/MyThing`
22
+ - This is for web-safety
23
+ - `pathQueryParameters` to be an explicitly internal property instead of just asking people to not set it directly
24
+ - This fixes a few potential "bugs" that could happen if somebody set it anyway
25
+
26
+ ### Fixed
27
+ - `targetNamespace` being derived eagerly for every config, which failed any build run from a directory with no adjacent `composer.json` *or* `style.css`
28
+ - Only the `lazyLoader` emitters read it, so it now falls back to an empty namespace (this matches the pre-`3.10.0` behavior)
29
+ - A missing `style.css` also no longer surfaces as a raw `ENOENT`
30
+
31
+ ### Removed
32
+ - `processTranslationConfigs` because it should not be used and didn't actually do anything
33
+ - This comes from version `2.96.2`
34
+
35
+ ### Internals
36
+ - Added more integration tests
37
+
8
38
  ## [3.16.0] - 2026-08-04
9
39
  ### Added
10
40
  - Logic so that files and directories with names equal to "example" or "examples" or that include "example" as a name segment are skipped
@@ -230,6 +260,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
230
260
  - Legacy PostCSS features that have been integrated into modern CSS
231
261
  - `@extends` support
232
262
 
263
+ ## [2.96.3] - 2026-08-11
264
+ ### Added
265
+ - A few more validation checks
266
+
267
+ ## [2.96.2] - 2026-08-11
268
+ ### Removed
269
+ - `processTranslationConfigs` because it should not be used and didn't actually do anything
270
+
271
+ ### Internals
272
+ - Added more integration tests
273
+
274
+ ## [2.96.1] - 2026-08-10
275
+ ### Fixed
276
+ - An error in how externalized dependencies were resolved that caused jquery to never be emitted as a dependency
277
+
278
+ ## [2.96.0] - 2026-08-07
279
+ ### Added
280
+ - A port of WordPress's Dependency Extraction Webpack Plugin because they keep breaking it
281
+ - Warnings and additional info for entrypoints that are lazy-loaded and assigned to actual locations
282
+
283
+ ### Removed
284
+ - "combineAssetMetadata" - it has never actually been a valid prop
285
+
286
+ ### Fixed
287
+ - Path-query handle handling
288
+ - Double emission of CSS from entrypoint.json files when module processing is enabled
289
+ - A bug that could result in writes outside the webpack context root
290
+
291
+ ### Changed
292
+ - Backported the hook_name fix from the 3.x branch
293
+
233
294
  ## [2.95.0] - 2026-08-04
234
295
  ### Added
235
296
  - Logic so that files and directories with names equal to "example" or "examples" or that include "example" as a name segment are skipped
@@ -465,7 +526,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
465
526
 
466
527
  ## [2.72.1] - 2025-10-29
467
528
  ### Fixed
468
- - The wrapper being unable to find the `DependencyExtractionWebpackPlugin` due to version desyncs
529
+ - The wrapper being unable to find the `EnhancedDependencyExtractionWebpackPlugin` due to version desyncs
469
530
  - This isn't so much a "fix" as it is a "mitigation" - version desyncs are not fixable at the library level
470
531
 
471
532
  ## [2.72.0] - 2025-10-13
package/USER-GUIDE.md CHANGED
@@ -109,7 +109,7 @@ However, if you need to do something unusual or just want to know what everythin
109
109
  - All file names are informational placeholders. They can be whatever you want provided that they are web-safe (basically, don't do things like calling the email address block "✉️" and you'll be fine)
110
110
 
111
111
  ### Examples
112
- - Any uses of `acme-my-plugin` should be replaced with your plugin or theme's kebab-case name (ex: `acme-my-plugin.wp-admin` => `plaudit-base.wp-admin`)
112
+ - Any uses of `acme-my-plugin` should be replaced with your plugin or theme's kebab-case name (ex: `acme-my-plugin/wp-admin` => `plaudit-base/wp-admin`)
113
113
 
114
114
  ---
115
115
 
@@ -205,8 +205,11 @@ After building, each asset gets a handle you can reference in PHP.
205
205
 
206
206
  ### Handle Format
207
207
 
208
- **Plain:** `{prefix}.{filename}`
209
- - Example: `acme-my-plugin.admin-editor`
208
+ **Plain:** `{prefix}/{filename}`
209
+ - Example: `acme-my-plugin/admin-editor`
210
+ - If the filename carries a nice-name segment, that segment *replaces* the location-derived name rather than being appended to it, and it is kebab-cased on the way in
211
+ - `view.MyThing.ts` is `acme-my-plugin/my-thing`, not `acme-my-plugin/view-my-thing`
212
+ - Because the location is dropped, two files that differ only by location cannot share a nice name
210
213
 
211
214
  **Blocks:** `{prefix}_blocks_{block-name}-{type}`
212
215
  - Example: `acme-my-plugin_blocks_hero-banner-editor-script`
@@ -231,14 +234,14 @@ After building, each asset gets a handle you can reference in PHP.
231
234
  add_action('admin_enqueue_scripts', function($hook) {
232
235
  if ($hook === 'post.php') {
233
236
  // Localize data first (optional)
234
- wp_localize_script('acme-my-plugin.admin-editor', 'myData', [
237
+ wp_localize_script('acme-my-plugin/admin-editor', 'myData', [
235
238
  'ajaxUrl' => admin_url('admin-ajax.php'),
236
239
  'nonce' => wp_create_nonce('my_ajax_action'),
237
240
  ]);
238
241
 
239
242
  // Then enqueue
240
- wp_enqueue_script('acme-my-plugin.admin-editor');
241
- wp_enqueue_style('acme-my-plugin.admin-editor');
243
+ wp_enqueue_script('acme-my-plugin/admin-editor');
244
+ wp_enqueue_style('acme-my-plugin/admin-editor');
242
245
  }
243
246
  });
244
247
  ```
@@ -277,7 +280,7 @@ src: {
277
280
  // In your plugin
278
281
  add_action('admin_enqueue_scripts', function($hook) {
279
282
  if ($hook === 'post.php') {
280
- wp_enqueue_script('acme-my-plugin.post-editor');
283
+ wp_enqueue_script('acme-my-plugin/post-editor');
281
284
  }
282
285
  });
283
286
  ```
@@ -315,7 +318,7 @@ src: {
315
318
  | `srcDir` | `string` | `""` | Source directory (**Required** on new sites) |
316
319
  | `outputDir` | `string` | `""` | Output directory (**Required** on new sites) |
317
320
  | `useUnifiedLoader` | `boolean` | `false` | Generate unified-loader.php (always set to `true` on new sites!) |
318
- | `useWebpackResourceFiltering` | `boolean` | `false` | Generates versioned copies of images, fonts, etc (always set to `true` on new sites!) |
321
+ | `useWebpackResourceFiltering` | `boolean` | `true` | Generates versioned copies of images, fonts, etc (always set to `true` on new sites!) |
319
322
  | `plainEntrypointsVersion` | `1\|2` | `1` | Use 2 for new sites |
320
323
  | `extensionsVersion` | `1\|2\|3` | `1` | Use 3 for new sites |
321
324
  | `verbose` | `boolean` | `false` | Verbose logging |
@@ -571,11 +574,11 @@ This is the form that *should* be used. It has two categories of keys: control f
571
574
 
572
575
  **Control Flags:**
573
576
 
574
- | Key | Type | Default | Description |
575
- |----------------------|--------------------------------------------------------------------------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------|
576
- | `handle` | `string \| fn(string) => string` | Auto | The handle by which the entrypoint will be referenced. The function form is passed the default handle for manual tweaking |
577
- | `register` | `boolean \| number` | `true` | **[Advanced]** Whether the entrypoint should be registered at all or, if a number, the priority of the hook in which the registration will occur |
578
- | `registerScriptArgs` | `boolean` \| `'lazy'` \| [`WordPressScriptArgs`](#wordpress-script-args) | Auto | The loading flags (strategy, in_footer, and fetchpriority) for the script.<br>'lazy' is an alias for `{strategy: 'defer', in_footer: true}` |
577
+ | Key | Type | Default | Description |
578
+ |----------------------|--------------------------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
579
+ | `handle` | `string \| fn(string) => string` | Auto | The handle by which the entrypoint will be referenced. The function form is passed the default handle for manual tweaking, and may return nothing to accept the default |
580
+ | `register` | `boolean \| number` | `true` | **[Advanced]** Whether the entrypoint should be registered at all or, if a number, the priority of the hook in which the registration will occur |
581
+ | `registerScriptArgs` | `boolean` \| `'lazy'` \| [`WordPressScriptArgs`](#wordpress-script-args) | Auto | The loading flags (strategy, in_footer, and fetchpriority) for the script.<br>'lazy' is an alias for `{strategy: 'defer', in_footer: true}` |
579
582
 
580
583
  **Location Identifiers:**
581
584
 
@@ -2,7 +2,7 @@ import { MinimumViableMetadata, ParsedAssetJsonProvider, ParsedAssetsJson } from
2
2
  import type { ExtensibleEntryObject, VerifiedPlauditWordpressWebpackConfig } from "../utils/common-config-helpers";
3
3
  import { PseudoSemaphore } from "../utils/pseduo-semaphore";
4
4
  import { AbstractBiPhasicGroupPlugin } from "./AbstractBiPhasicGroupPlugin";
5
- import { Compilation, Compiler, Entrypoint } from "webpack";
5
+ import { type Compilation, type Compiler, type Entrypoint } from "webpack";
6
6
  export type EntryProvider<M extends MinimumViableMetadata = MinimumViableMetadata> = () => ExtensibleEntryObject<M> | Promise<ExtensibleEntryObject<M>>;
7
7
  export declare abstract class AbstractBiPhasicGroupAndEntryPlugin<M extends MinimumViableMetadata = MinimumViableMetadata> extends AbstractBiPhasicGroupPlugin {
8
8
  private readonly context;
@@ -24,6 +24,7 @@ export declare class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEnt
24
24
  constructor(config: VerifiedPlauditWordpressWebpackConfig, dest: VerifiedAdvancedOutputConfig, webpackRemoveEmptyScriptsPlugin: WebpackRemoveEmptyScriptsPlugin, context: string, entry: EntryProvider<BlockEntrypointInfo>);
25
25
  protected processAssets(compilation: Compilation, parsedAssetJsonProvider: ParsedAssetJsonProvider): Promise<void>;
26
26
  private emitBlockLoaderFile;
27
+ private static readonly THEME_JSON_FLAG_PROPS;
27
28
  private static pickOutFlagPropsFromBlockSupports;
28
29
  private callRegisterFunction;
29
30
  private transformBlocks;
@@ -226,37 +226,48 @@ class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.Abst
226
226
  compilation.emitAsset((0, node_path_1.join)(this.dest.destination, "blockdir.config.php"), new webpack_1.sources.RawSource((0, shared_1.makeEmittableConfigPHP)(blockDirConfig, true)));
227
227
  }
228
228
  }
229
- // This isn't strictly necessary, but it allows us to trivially eliminate commonly-used block supports flags that aren't used in theme.json
230
- // private static readonly IGNORED_THEME_JSON_FLAG_PROPS = ['align', 'alignWide', 'anchor', 'contentRole', 'inserter', 'interactivity', 'listView', 'plaudit'];
229
+ /*
230
+ * The block supports that have a boolean counterpart under theme.json's settings, as
231
+ * `settings key -> {support prop: settings prop}`. This is an allow-list rather than an ignore-list
232
+ * because most supports (align, alignWide, anchor, contentRole, inserter, interactivity, listView,
233
+ * plaudit, ...) have no theme.json settings equivalent at all, and the ones that do don't always
234
+ * share a name: typography's fontSize is settings.typography.customFontSize, and Gutenberg still
235
+ * ships several of these under an __experimental prefix.
236
+ */
237
+ static THEME_JSON_FLAG_PROPS = {
238
+ color: { background: 'background', link: 'link', text: 'text' },
239
+ dimensions: { aspectRatio: 'aspectRatio', minHeight: 'minHeight' },
240
+ spacing: { blockGap: 'blockGap', margin: 'margin', padding: 'padding' },
241
+ typography: {
242
+ fontSize: 'customFontSize',
243
+ lineHeight: 'lineHeight',
244
+ textAlign: 'textAlign',
245
+ fontStyle: 'fontStyle', __experimentalFontStyle: 'fontStyle',
246
+ fontWeight: 'fontWeight', __experimentalFontWeight: 'fontWeight',
247
+ letterSpacing: 'letterSpacing', __experimentalLetterSpacing: 'letterSpacing',
248
+ textDecoration: 'textDecoration', __experimentalTextDecoration: 'textDecoration',
249
+ textTransform: 'textTransform', __experimentalTextTransform: 'textTransform',
250
+ writingMode: 'writingMode', __experimentalWritingMode: 'writingMode'
251
+ }
252
+ };
231
253
  static pickOutFlagPropsFromBlockSupports(supports) {
232
254
  function isRecord(value) {
233
255
  return typeof value === 'object' && !!value && !Array.isArray(value);
234
256
  }
235
257
  let addedProp = false;
236
258
  const res = {};
237
- if ('color' in supports) {
238
- const color = supports.color;
239
- if (isRecord(color)) {
240
- const colorFlags = {};
241
- for (const prop of ['background', 'link', 'text']) {
242
- if (supports[prop]) {
243
- colorFlags[prop] = true;
244
- res.color = colorFlags;
245
- addedProp = true;
246
- }
247
- }
259
+ for (const [settingsKey, props] of Object.entries(EnhancedBlockJSONPlugin.THEME_JSON_FLAG_PROPS)) {
260
+ const support = supports[settingsKey];
261
+ if (!isRecord(support)) {
262
+ continue;
248
263
  }
249
- }
250
- if ('dimensions' in supports) {
251
- const dimensions = supports.dimensions;
252
- if (isRecord(dimensions)) {
253
- const dimensionsFlags = {};
254
- for (const prop of ['aspectRatio']) {
255
- if (supports[prop]) {
256
- dimensionsFlags[prop] = true;
257
- res.color = dimensionsFlags;
258
- addedProp = true;
259
- }
264
+ const flags = {};
265
+ for (const [supportProp, settingsProp] of Object.entries(props)) {
266
+ // A sided support such as `"margin": ["top", "bottom"]` is still just "on" as far as theme.json is concerned
267
+ if (support[supportProp]) {
268
+ flags[settingsProp] = true;
269
+ res[settingsKey] = flags;
270
+ addedProp = true;
260
271
  }
261
272
  }
262
273
  }
@@ -536,7 +547,7 @@ class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.Abst
536
547
  }
537
548
  delete blockJson[invalidTemplateLocation];
538
549
  if (renderTemplate.length > 1) {
539
- compilation.warnings.push((0, shared_1.newWebpackErrorForFile)("Encountered a block with multiple possible render files. Please set the render key in block.json to the proper one", (0, node_path_1.join)(sourceDir, 'block.json')));
550
+ compilation.warnings.push((0, shared_1.newWebpackErrorForFile)("Encountered a block with multiple possible render files. Please set the render key in block.json to the intended one", (0, node_path_1.join)(sourceDir, 'block.json')));
540
551
  blockJson[validTemplateLocation] = renderTemplate.find(p => p.endsWith(".php")) ?? renderTemplate[0];
541
552
  }
542
553
  else {
@@ -41,20 +41,20 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
41
41
  for (let count = 0; finalHandleName in handleNameMap && handleNameMap[finalHandleName] !== src;) {
42
42
  finalHandleName = `${baseFinalHandleName}-${++count}`;
43
43
  }
44
- if (typeof handleName === 'string' || typeof handleName === 'function' || (handleName && 'niceName' in handleName)) {
44
+ if (handleName !== undefined) {
45
45
  finalHandleName = (0, shared_1.convertUsageLocationsHandleToEmittableHandle)(handleName, handlePrefix, finalHandleName.substring(handlePrefix.length + 1));
46
46
  }
47
47
  handleNameMap[finalHandleName] = src;
48
48
  plainEntrypointsConfig[`${type}Handles`][finalHandleName] = { src, rest, locations, type, lazyLoader, ...otherProps };
49
49
  }
50
50
  }
51
- PlainEntrypointsConfigFileGeneratorPlugin.addHandlesToHandleLists('script', Object.entries(plainEntrypointsConfig.scriptHandles)
51
+ PlainEntrypointsConfigFileGeneratorPlugin.addHandlesToHandleLists(compilation, 'script', Object.entries(plainEntrypointsConfig.scriptHandles)
52
52
  .toSorted(([a], [b]) => a.localeCompare(b)), handleLists);
53
- PlainEntrypointsConfigFileGeneratorPlugin.addHandlesToHandleLists('script_module', Object.entries(plainEntrypointsConfig.script_moduleHandles)
53
+ PlainEntrypointsConfigFileGeneratorPlugin.addHandlesToHandleLists(compilation, 'script_module', Object.entries(plainEntrypointsConfig.script_moduleHandles)
54
54
  .toSorted(([a], [b]) => a.localeCompare(b)), handleLists);
55
55
  const sortedStyleHandles = Object.entries(plainEntrypointsConfig.styleHandles)
56
56
  .toSorted(([a], [b]) => a.localeCompare(b));
57
- PlainEntrypointsConfigFileGeneratorPlugin.addHandlesToHandleLists('style', sortedStyleHandles, handleLists);
57
+ PlainEntrypointsConfigFileGeneratorPlugin.addHandlesToHandleLists(compilation, 'style', sortedStyleHandles, handleLists);
58
58
  const callItemSorter = (a, b) => a.handle.localeCompare(b.handle);
59
59
  for (const list of Object.values(handleLists)) {
60
60
  list.sort(callItemSorter);
@@ -113,8 +113,10 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
113
113
  writer.return(editorSettings);
114
114
  }, { functionArgParameters: [editorSettings], accountForAlreadyDoing: false });
115
115
  }
116
- const lazyLoadedHandles = Object.values(handleLists)
117
- .flatMap(handleList => handleList.map(handle => [handle.data.lazyLoader, handle]))
116
+ // Only the register and inline lists, which are mutually exclusive, so each handle is collected
117
+ // exactly once. Flattening every list instead would collect a handle once per location it declares.
118
+ const lazyLoadedHandles = [...handleLists.register, ...handleLists.inline]
119
+ .map(handle => [handle.data.lazyLoader, handle])
118
120
  .filter((entry) => entry[0] !== undefined)
119
121
  .sort((a, b) => a[0].localeCompare(b[0]) || a[1].priority - b[1].priority);
120
122
  if (lazyLoadedHandles.length > 0) {
@@ -134,7 +136,7 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
134
136
  }
135
137
  (0, shared_1.emitPHPWriterAsAsset)(file, compilation, "plain-entrypoints-loader.php");
136
138
  }
137
- static addHandlesToHandleLists(type, handles, handleLists) {
139
+ static addHandlesToHandleLists(compilation, type, handles, handleLists) {
138
140
  const defaultPriority = 10;
139
141
  for (const [handle, data] of handles) {
140
142
  if (data.locations.register !== false) {
@@ -143,6 +145,19 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
143
145
  else if (data.inlinedAsset !== undefined) {
144
146
  handleLists.inline.push({ handle, type, data, priority: typeof data.locations.inline === 'number' ? data.locations.inline : 10 });
145
147
  }
148
+ if (data.lazyLoader !== undefined) {
149
+ // A lazily loaded handle is enqueued by its generated function and never by an action, so it
150
+ // is deliberately kept out of the location lists. Those lists are also what the lazy function
151
+ // is built from, and a handle present in several of them would be enqueued once per list.
152
+ const declaredLocations = (0, shared_1.constantKeys)(shared_1.standardLocationNamesMeta)
153
+ .filter(location => data.locations[location] || typeof data.locations[location] === 'number');
154
+ if (declaredLocations.length > 0) {
155
+ const locText = declaredLocations.length === 1 ? "location" : "locations";
156
+ compilation.warnings.push((0, shared_1.newWebpackErrorForFile)(`The handle "${handle}" declares both a lazyLoader (${data.lazyLoader}) and the ${declaredLocations.join(", ")} ${locText}.`
157
+ + ` It will only be enqueued by ${data.lazyLoader}(); remove either the ${locText} or the lazyLoader.`, data.src));
158
+ }
159
+ continue;
160
+ }
146
161
  for (const location of (0, shared_1.constantKeys)(shared_1.standardLocationNamesMeta)) {
147
162
  let priority, hook_name;
148
163
  const dataLocation = data.locations[location];
@@ -186,7 +201,6 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
186
201
  }
187
202
  }
188
203
  static appendEnqueuingHandleLists(writer, handleLists) {
189
- const lazyLoadableHandles = {};
190
204
  for (const [sln, { action, supports_hook_name, additional_action_code }] of (0, shared_1.constantEntries)(shared_1.standardLocationNamesMeta)) {
191
205
  const handleList = handleLists[sln];
192
206
  if (handleList.length > 0) {
@@ -226,7 +240,6 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
226
240
  }
227
241
  }
228
242
  }
229
- return lazyLoadableHandles;
230
243
  }
231
244
  static separateHandleListByPriority(handleItems) {
232
245
  const lists = new Map();
@@ -1,7 +1,4 @@
1
- import DependencyExtractionWebpackPlugin from "@wordpress/dependency-extraction-webpack-plugin";
2
- import { Externals } from "../shared";
1
+ import type { Externals } from "../shared";
2
+ import { EnhancedDependencyExtractionWebpackPlugin } from "../wordpress-ports/dependency-extraction-webpack-plugin";
3
3
  import type { Configuration } from "webpack";
4
- export declare function makeDependencyExtractionPlugin(externals: Externals | undefined, assumeGlobalizedPlauditLibraries: boolean, wantsGroupedDepData: boolean, externalizing: Required<Configuration>['output']['library']): {
5
- instance: DependencyExtractionWebpackPlugin;
6
- addExternalizedDep: (dep: string) => void;
7
- };
4
+ export declare function makeDependencyExtractionPlugin(externals: Externals | undefined, assumeGlobalizedPlauditLibraries: boolean, externalizing: Required<Configuration>['output']['library']): EnhancedDependencyExtractionWebpackPlugin;
@@ -1,19 +1,10 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.makeDependencyExtractionPlugin = makeDependencyExtractionPlugin;
7
- const dependency_extraction_webpack_plugin_1 = __importDefault(require("@wordpress/dependency-extraction-webpack-plugin"));
8
- function makeDependencyExtractionPlugin(externals, assumeGlobalizedPlauditLibraries, wantsGroupedDepData, externalizing) {
9
- const baseProps = makeDependencyExtractionPluginProps(externals, assumeGlobalizedPlauditLibraries, externalizing);
10
- const instance = new dependency_extraction_webpack_plugin_1.default(wantsGroupedDepData ? { ...baseProps, outputFormat: "json", combineAssets: true } : baseProps);
11
- return {
12
- instance,
13
- addExternalizedDep: (dep) => {
14
- instance.externalizedDeps.add(dep);
15
- }
16
- };
4
+ const dependency_extraction_webpack_plugin_1 = require("../wordpress-ports/dependency-extraction-webpack-plugin");
5
+ const util_1 = require("../wordpress-ports/dependency-extraction-webpack-plugin/util");
6
+ function makeDependencyExtractionPlugin(externals, assumeGlobalizedPlauditLibraries, externalizing) {
7
+ return new dependency_extraction_webpack_plugin_1.EnhancedDependencyExtractionWebpackPlugin(makeDependencyExtractionPluginProps(externals, assumeGlobalizedPlauditLibraries, externalizing));
17
8
  }
18
9
  function makeDependencyExtractionPluginProps(externals, assumeGlobalizedPlauditLibraries, externalizing) {
19
10
  if (!externals) {
@@ -93,7 +84,7 @@ const EXTERNALIZABLE_PLAUDIT_LIBRARIES = {
93
84
  ...Object.fromEntries(['@plaudit/frontend-apis', '@plaudit/library-extensions', '@plaudit/block-supports', '@plaudit/gutenberg-api-extensions']
94
85
  .map(req => {
95
86
  return [req, {
96
- import: ['plaudit', camelCaseDash(req.substring(PLAUDIT_NAMESPACE.length))],
87
+ import: ['plaudit', (0, util_1.camelCaseDash)(req.substring(PLAUDIT_NAMESPACE.length))],
97
88
  handle: `plaudit-${req.substring(PLAUDIT_NAMESPACE.length)}`
98
89
  }];
99
90
  })),
@@ -116,12 +107,6 @@ function normalizeRequest(request) {
116
107
  function curryRequestHandlers(primary, secondary) {
117
108
  return (...args) => primary(...args) ?? secondary(...args);
118
109
  }
119
- /**
120
- * Copied from @wordpress/dependency-extraction-webpack-plugin for consistency
121
- */
122
- function camelCaseDash(string) {
123
- return string.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
124
- }
125
110
  function handleExternalizingEqualsPossibleExternal(possibleExternal, ext) {
126
111
  if (!ext || !possibleExternal) {
127
112
  return possibleExternal;
@@ -151,7 +136,9 @@ function handleExternalizingEqualsPossibleExternal(possibleExternal, ext) {
151
136
  }
152
137
  else {
153
138
  for (const key of ['amd', 'commonjs', 'root']) {
154
- if (key in ext && handleExternalizingEqualsPossibleExternal(possibleExternal, ext[key])) {
139
+ // The recursion returns the external when it should be kept and undefined when it matched, so
140
+ // only an undefined result means this umd name is the thing being built and must not externalize.
141
+ if (key in ext && handleExternalizingEqualsPossibleExternal(possibleExternal, ext[key]) === undefined) {
155
142
  return undefined;
156
143
  }
157
144
  }
package/dist/shared.d.ts CHANGED
@@ -5,17 +5,20 @@ import { type AssetInfo, type Compilation, type Configuration, type Entrypoint,
5
5
  import { SourceType } from "./utils/entrypoint-resolution-logic";
6
6
  import type { NormalizedEnqueuingControlFlags } from "./utils/path-query-and-related-helpers";
7
7
  export * from "./utils/entrypoint-resolution-logic";
8
- export type WPModuleDependency = {
8
+ export type WPModuleDependency = string | {
9
9
  id: string;
10
10
  import?: string;
11
11
  };
12
- export type ParsedAssetsJson = Record<string, {
13
- dependencies: string[];
12
+ export type ParsedAssetJson = {
13
+ dependencies: WPModuleDependency[];
14
+ module_dependencies?: WPModuleDependency[];
14
15
  version: string;
15
- module_dependencies?: (string | WPModuleDependency)[];
16
- }>;
16
+ type?: 'module';
17
+ handle?: string;
18
+ };
19
+ export type ParsedAssetsJson = Record<string, ParsedAssetJson>;
17
20
  export declare function isParsedAssetsJson(thing: any): thing is ParsedAssetsJson;
18
- type BaseRestType = [/* dependencies: */ string[], /* version: */ string];
21
+ type BaseRestType = [/* dependencies: */ WPModuleDependency[], /* version: */ string];
19
22
  export type AssetMetaSegment = {
20
23
  inlinedAsset: InlinedAsset;
21
24
  assetContents: string;
@@ -28,7 +31,7 @@ export type ScriptArgsObject = {
28
31
  strategy?: 'defer' | 'async';
29
32
  in_footer?: boolean;
30
33
  fetchpriority?: 'auto' | 'low' | 'high';
31
- module_dependencies?: (string | WPModuleDependency)[];
34
+ module_dependencies?: WPModuleDependency[];
32
35
  };
33
36
  export type InlinedAsset = {
34
37
  position?: 'before' | 'after';
@@ -120,16 +123,16 @@ export type AdvancedOutputConfig = {
120
123
  directoryLayout?: SourceType;
121
124
  assumeGlobalizedPlauditLibraries?: boolean;
122
125
  externalize?: Required<Configuration>['output']['library'];
123
- bundleAnalyzer?: boolean;
126
+ bundleAnalyzer?: boolean | 'no-auto-open';
124
127
  locations?: UsageLocations | UsageLocations['handle'];
125
128
  lazyLoader?: string;
126
- pathQueryParameters?: PathQueryParameters;
127
129
  enqueuingFlags?: NormalizedEnqueuingControlFlags;
128
130
  };
129
- type OptionalCfgFields = 'directoryLayout' | 'externalize' | 'lazyLoader' | 'pathQueryParameters';
131
+ type OptionalCfgFields = 'directoryLayout' | 'externalize' | 'lazyLoader';
130
132
  export type VerifiedAdvancedOutputConfig = Required<Omit<AdvancedOutputConfig, 'locations' | 'enqueuingFlags' | OptionalCfgFields>> & Pick<AdvancedOutputConfig, OptionalCfgFields> & {
131
133
  enqueuingFlags: NormalizedEnqueuingControlFlags | undefined;
132
134
  locations: NormalizedUsageLocations;
135
+ pathQueryParameters?: PathQueryParameters;
133
136
  };
134
137
  export type SourcesObject = Record<string, string | AdvancedOutputConfig | boolean>;
135
138
  export type PlauditWordpressWebpackConfig = {
@@ -144,8 +147,6 @@ export type PlauditWordpressWebpackConfig = {
144
147
  };
145
148
  externals?: Externals;
146
149
  assumeGlobalizedPlauditLibraries?: boolean;
147
- processTranslationConfigs?: boolean;
148
- combineAssetMetadata?: boolean;
149
150
  useWebpackResourceFiltering?: boolean;
150
151
  outputDir?: string;
151
152
  extensionsVersion?: 1 | 2 | 3;
@@ -172,8 +173,6 @@ export declare function applyStandards(config: PlauditWordpressWebpackConfig): {
172
173
  };
173
174
  readonly externals?: Externals;
174
175
  readonly assumeGlobalizedPlauditLibraries?: boolean;
175
- readonly processTranslationConfigs?: boolean;
176
- readonly combineAssetMetadata?: boolean;
177
176
  useWebpackResourceFiltering?: boolean;
178
177
  outputDir?: string;
179
178
  extensionsVersion?: 1 | 2 | 3;
@@ -219,8 +218,7 @@ export type MinimumViableMetadata = {
219
218
  dest: VerifiedAdvancedOutputConfig;
220
219
  absoluteSrc: string;
221
220
  };
222
- export declare function convertUsageLocationsHandleToEmittableHandle(handle: UsageLocations['handle'], handlePrefix: string, generatedNiceName: string): string;
223
- export declare function convertUsageLocationsHandleToEmittableHandleSuffix(handle: UsageLocations['handle'], generatedNiceName: string): string;
221
+ export declare function convertUsageLocationsHandleToEmittableHandle(handle: UsageLocations['handle'], handlePrefix: string, handleSuffix: string): string;
224
222
  export declare function makeEmittableConfigPHP(data: any, asFullFile: boolean, parentIndent?: string): string;
225
223
  export declare const entrypointFields: readonly ["editorStyle", "viewStyle", "style", "editorScript", "viewScript", "script", "viewScriptModule"];
226
224
  export type EntrypointFields = (typeof entrypointFields[number])[];
@@ -233,7 +231,7 @@ export declare const styleExtension: RegExp;
233
231
  export declare function scriptOrStyleTest(entryPath: string, scriptExtension: RegExp): "script" | "style" | "";
234
232
  export declare function isStyleField(field: string): field is 'style' | 'viewStyle' | 'editorStyle';
235
233
  export declare function isScriptModuleField(field: string): field is 'viewScriptModule';
236
- export declare function mergeModuleDependencyArrays(a: (string | WPModuleDependency)[] | undefined, b: (string | WPModuleDependency)[] | undefined): (string | WPModuleDependency)[] | undefined;
234
+ export declare function mergeModuleDependencyArrays(a: WPModuleDependency[] | undefined, b: WPModuleDependency[] | undefined): WPModuleDependency[] | undefined;
237
235
  export declare function getHandleGroup(field: string): 'styleHandles' | 'scriptHandles' | 'scriptModuleHandles';
238
236
  export type StripFirstTwoItems<A extends any[]> = A extends [any, any, ...rest: infer R] ? R : never;
239
237
  export declare function hasAtLeastOneItem<T>(list: T[]): list is [T, ...T[]];
@@ -260,7 +258,7 @@ export declare function getParsedAssetsJsonDataForEntrypoint(compilation: Compil
260
258
  assetData: ParsedAssetsJson[string];
261
259
  } | undefined;
262
260
  export declare function emitPHPWriterAsAsset(writer: PHPWriter | PHPFile, compilation: Compilation, file: string, assetInfo?: AssetInfo): void;
263
- export declare function dedent(text: TemplateStringsArray): string;
261
+ export declare function dedent(text: TemplateStringsArray, ...values: unknown[]): string;
264
262
  export declare function resolveLegacyBlockScriptsInFolder(folder: string): string[];
265
263
  /**
266
264
  * @param compilation
package/dist/shared.js CHANGED
@@ -28,7 +28,6 @@ exports.determineCurrentSourceType = determineCurrentSourceType;
28
28
  exports.applyStandards = applyStandards;
29
29
  exports.resolveStandard = resolveStandard;
30
30
  exports.convertUsageLocationsHandleToEmittableHandle = convertUsageLocationsHandleToEmittableHandle;
31
- exports.convertUsageLocationsHandleToEmittableHandleSuffix = convertUsageLocationsHandleToEmittableHandleSuffix;
32
31
  exports.makeEmittableConfigPHP = makeEmittableConfigPHP;
33
32
  exports.convertEntrypointFieldForAssetType = convertEntrypointFieldForAssetType;
34
33
  exports.leadingSlashIt = leadingSlashIt;
@@ -87,7 +86,7 @@ exports.standardLocationNamesMeta = {
87
86
  analytics: { action: "plaudit_enqueue_analytics" },
88
87
  };
89
88
  function isStandardLocationName(name) {
90
- return name in exports.standardLocationNamesMeta;
89
+ return Object.hasOwn(exports.standardLocationNamesMeta, name);
91
90
  }
92
91
  function isRegisterScriptArgsShorthandName(name) {
93
92
  return ['lazy', 'eager', 'inline'].includes(name);
@@ -146,37 +145,23 @@ function resolveStandard(standard) {
146
145
  return undefined;
147
146
  }
148
147
  }
149
- function convertUsageLocationsHandleToEmittableHandle(handle, handlePrefix, generatedNiceName) {
148
+ function convertUsageLocationsHandleToEmittableHandle(handle, handlePrefix, handleSuffix) {
149
+ const generatedHandle = `${handlePrefix}/${handleSuffix}`;
150
150
  let emittableHandle;
151
151
  if (!handle) {
152
- return `${handlePrefix}/${generatedNiceName}`;
152
+ return generatedHandle;
153
153
  }
154
154
  if (typeof handle === 'string') {
155
155
  emittableHandle = handle;
156
156
  }
157
157
  else if (typeof handle === 'function') {
158
- emittableHandle = handle(`${handlePrefix}/${generatedNiceName}`);
158
+ emittableHandle = handle(generatedHandle);
159
159
  }
160
160
  else {
161
- emittableHandle = `${handlePrefix}/${handle.niceName}`;
161
+ emittableHandle = handle.niceName && `${handlePrefix}/${handle.niceName}`;
162
162
  }
163
- return emittableHandle.replaceAll("{basename}", generatedNiceName);
164
- }
165
- function convertUsageLocationsHandleToEmittableHandleSuffix(handle, generatedNiceName) {
166
- let emittableHandle;
167
- if (!handle) {
168
- return generatedNiceName;
169
- }
170
- if (typeof handle === 'string') {
171
- emittableHandle = handle;
172
- }
173
- else if (typeof handle === 'function') {
174
- emittableHandle = handle(generatedNiceName);
175
- }
176
- else {
177
- emittableHandle = handle.niceName;
178
- }
179
- return emittableHandle.replaceAll("{basename}", generatedNiceName);
163
+ // A callback is free to return nothing, which means "use the handle you would have generated"
164
+ return emittableHandle ? emittableHandle.replaceAll("{basename}", handleSuffix) : generatedHandle;
180
165
  }
181
166
  function makeEmittableConfigPHP(data, asFullFile, parentIndent = "") {
182
167
  const prettyPrintedMetadata = php_writer_1.json2php.make({ indent: "\t", linebreak: "\n", shortArraySyntax: true })(data, parentIndent)
@@ -313,18 +298,10 @@ function emitResolveBaseUriFunction(writer) {
313
298
  }
314
299
  function getAssetsJson(compilation) {
315
300
  const asset = compilation.getAsset("assets.json");
316
- if (!asset) {
317
- throw new Error("assets.json is unexpectedly missing");
318
- }
319
- if (isParsedAssetsJson(asset.info["parsed-assets-json"])) {
301
+ if (asset && isParsedAssetsJson(asset.info["parsed-assets-json"])) {
320
302
  return asset.info["parsed-assets-json"];
321
303
  }
322
- const parsedAssetJson = JSON.parse(asset.source.source().toString('utf-8'));
323
- if (!isParsedAssetsJson(parsedAssetJson)) {
324
- throw new Error("assets.json is does not match the RawAssetData format");
325
- }
326
- compilation.updateAsset("assets.json", s => s, a => ({ ...a, "parsed-assets-json": parsedAssetJson }));
327
- return parsedAssetJson;
304
+ throw new Error("assets.json is unexpectedly missing");
328
305
  }
329
306
  function getParsedAssetsJsonDataForEntrypoint(compilation, entrypoint, metadata) {
330
307
  const dest = metadata.dest;
@@ -364,13 +341,24 @@ function emitPHPWriterAsAsset(writer, compilation, file, assetInfo) {
364
341
  const contents = writer.toString() + "\n";
365
342
  compilation[file in compilation.assets ? 'updateAsset' : 'emitAsset'](file, new webpack_1.sources.RawSource(contents), { size: Buffer.byteLength(contents), ...assetInfo });
366
343
  }
367
- function dedent(text) {
368
- const actualText = text.join("\n");
369
- const firstLineIndent = actualText.split("\r?\n").find(line => line.length > 0)?.match(/^\s+/)?.[0];
370
- if (!firstLineIndent) {
371
- return actualText;
372
- }
373
- return actualText.replaceAll(new RegExp("^" + firstLineIndent, 'mg'), "").replace(/\n{2}$/, "\n");
344
+ function dedent(text, ...values) {
345
+ const lines = text.reduce((result, part, i) => result + String(values[i - 1]) + part).split(/\r?\n/);
346
+ // A template that opens and closes on its own line frames the content with two throwaway lines
347
+ if (lines[0]?.trim() === "") {
348
+ lines.shift();
349
+ }
350
+ if (lines.length > 1 && lines.at(-1)?.trim() === "") {
351
+ lines.pop();
352
+ }
353
+ // Only the lines with content get a say in the indent, and a line break must never count as one
354
+ const indent = lines.filter(line => line.trim() !== "")
355
+ .reduce((shortest, line) => {
356
+ const lineIndent = /^[ \t]*/.exec(line)?.[0] ?? "";
357
+ return shortest === undefined || lineIndent.length < shortest.length ? lineIndent : shortest;
358
+ }, undefined);
359
+ return indent
360
+ ? lines.map(line => line.startsWith(indent) ? line.substring(indent.length) : line).join("\n")
361
+ : lines.join("\n");
374
362
  }
375
363
  function resolveLegacyBlockScriptsInFolder(folder) {
376
364
  const blockScriptEntrypoints = [];