@plaudit/webpack-extensions 2.85.1 → 2.86.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 +13 -0
- package/USER-GUIDE.md +102 -81
- package/build/plugins/EnhancedBlockJSONPlugin.js +4 -7
- package/build/plugins/PlainEntrypointsConfigFileGeneratorPlugin.js +2 -1
- package/build/shared.d.ts +14 -5
- package/build/shared.js +14 -2
- package/build/utils/common-config-helpers.d.ts +1 -1
- package/build/utils/common-config-helpers.js +63 -6
- package/build/utils/location-encoding-filename-parser.d.ts +25 -0
- package/build/utils/location-encoding-filename-parser.js +114 -0
- package/build/utils/path-query-and-related-helpers.d.ts +12 -8
- package/build/utils/path-query-and-related-helpers.js +45 -66
- package/build/wordpress-scripts-wrapper.js +75 -7
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,19 @@ 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
|
+
## [2.86.0] - 2026-03-16
|
|
9
|
+
### Added
|
|
10
|
+
- Support for `Location-Encoding Filenames`
|
|
11
|
+
- Support for standardized flag sets
|
|
12
|
+
|
|
13
|
+
## [2.85.3] - 2026-03-06
|
|
14
|
+
### Fixed
|
|
15
|
+
- `defer` and `async` not being supported strategies in some pipelines
|
|
16
|
+
|
|
17
|
+
## [2.85.2] - 2026-03-06
|
|
18
|
+
### Fixed
|
|
19
|
+
- Issues caused by trying to save a couple of cycles by using `hasAnyKeys` in place of checking the actual keys
|
|
20
|
+
|
|
8
21
|
## [2.85.1] - 2026-03-06
|
|
9
22
|
### Fixed
|
|
10
23
|
- Inlined scripts without any other path query parameters not being placed in the footer by default
|
package/USER-GUIDE.md
CHANGED
|
@@ -28,7 +28,13 @@
|
|
|
28
28
|
* [Pattern 4: Block Editor Styles](#pattern-4-block-editor-styles)
|
|
29
29
|
* [Reference](#reference)
|
|
30
30
|
* [Root Options](#root-options)
|
|
31
|
+
* [Standard Flag Sets](#standard-flag-sets)
|
|
32
|
+
* [Location-Encoding Filenames](#location-encoding-filenames)
|
|
33
|
+
* [Enqueuing Location](#enqueuing-location)
|
|
34
|
+
* [Examples](#examples-1)
|
|
35
|
+
* [Block- and Plain-compatible](#block--and-plain-compatible)
|
|
31
36
|
* [Per-Entrypoint Options](#per-entrypoint-options)
|
|
37
|
+
* [Path Queries](#path-queries)
|
|
32
38
|
* [Boolean-form](#boolean-form)
|
|
33
39
|
* [String-form](#string-form)
|
|
34
40
|
* [Object-form](#object-form)
|
|
@@ -137,85 +143,26 @@ The config tells webpack **what** to build and **where** to load it in WordPress
|
|
|
137
143
|
|
|
138
144
|
```javascript
|
|
139
145
|
module.exports = require("@plaudit/webpack-extensions/wordpress-scripts-wrapper")({
|
|
140
|
-
|
|
141
|
-
// Build all blocks in src/blocks/
|
|
142
|
-
"blocks": true,
|
|
143
|
-
|
|
144
|
-
// Build block extensions from src/extensions/
|
|
145
|
-
"extensions": {directoryLayout: 'extensions'},
|
|
146
|
-
|
|
147
|
-
// Auto-load in the head on frontend
|
|
148
|
-
"site/index-header.ts": {
|
|
149
|
-
locations: {
|
|
150
|
-
clientView: true,
|
|
151
|
-
registerScriptArgs: false
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
// Auto-load at the bottom of the body on frontend
|
|
156
|
-
"site/index-footer.ts": {
|
|
157
|
-
locations: {
|
|
158
|
-
clientView: true,
|
|
159
|
-
registerScriptArgs: 'lazy'
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
// Auto-load in admin
|
|
163
|
-
"site/wp-admin.ts": {
|
|
164
|
-
locations: {
|
|
165
|
-
admin: true
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
// Auto-load in admin
|
|
169
|
-
"site/wp-admin.pcss": {
|
|
170
|
-
locations: {
|
|
171
|
-
admin: true
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
// Auto-load in the block editor
|
|
175
|
-
"site/block-editor.pcss": {
|
|
176
|
-
locations: {
|
|
177
|
-
clientEditor: true
|
|
178
|
-
}
|
|
179
|
-
},
|
|
180
|
-
// Auto-load in the head on frontend
|
|
181
|
-
"site/public.pcss": {
|
|
182
|
-
locations: {
|
|
183
|
-
clientView: true
|
|
184
|
-
}
|
|
185
|
-
},
|
|
186
|
-
// A script that can be enqueued via its handle, but is not autoloaded
|
|
187
|
-
"site/manually-loaded.ts": {
|
|
188
|
-
locations: "plaudit-theme/manually-loaded-script"
|
|
189
|
-
},
|
|
190
|
-
// A script that will be inlined into the footer
|
|
191
|
-
"site/inlined-script.ts?inline=true": {
|
|
192
|
-
locations: "plaudit-theme/inlined-script"
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
useWebpackResourceFiltering: true, // Always use this!
|
|
196
|
-
extensionsVersion: 3,
|
|
197
|
-
plainEntrypointsVersion: 2,
|
|
198
|
-
srcDir: "src", // Always use this!
|
|
199
|
-
outputDir: "dist", // Always use this!
|
|
200
|
-
useUnifiedLoader: true, // Always use this!
|
|
146
|
+
standard: '2026-03-16',
|
|
201
147
|
variables: {
|
|
202
148
|
font_size: 16 // Required for pxAsRem to work; replace the 16 with your site's base font size
|
|
203
149
|
}
|
|
204
150
|
});
|
|
205
151
|
```
|
|
152
|
+
The `standard` key is shorthand to the standard set of flags as of the given date. See the [Standard Flag Sets](#standard-flag-sets) section for details.
|
|
206
153
|
|
|
207
154
|
### 2. Set Up Your File Structure
|
|
208
155
|
|
|
209
156
|
**Blocks** (subdirectories with block.json):
|
|
210
|
-
- **Config:** `
|
|
157
|
+
- **Config:** optional so long as the directory name is `blocks`; `'<dirname>': true` otherwise
|
|
211
158
|
- **File Structure:** [See Here](#file-structure)
|
|
212
159
|
|
|
213
160
|
**Extensions** (flat files that modify existing blocks):
|
|
214
|
-
- **Config:** `
|
|
161
|
+
- **Config:** optional so long as the directory name is `extensions`; `'<dirname>': {directoryLayout: 'extensions'}` otherwise
|
|
215
162
|
- **File Structure:** [See Here](#file-structure-1)
|
|
216
163
|
|
|
217
164
|
**Other Files** (scripts, styles):
|
|
218
|
-
- **Config:** List each file
|
|
165
|
+
- **Config:** Optional so long as you are using [Location-Encoding Filenames](#location-encoding-filenames); List each file that does not encode its own location in `src` object
|
|
219
166
|
- **File Structure:** [See Here](#file-structure-2)
|
|
220
167
|
|
|
221
168
|
### 3. Include unified-loader.php in Your Plugin
|
|
@@ -269,7 +216,7 @@ After building, each asset gets a handle you can reference in PHP.
|
|
|
269
216
|
**Best way:** Check the generated loader files after building:
|
|
270
217
|
- `dist/blocks/blocks-loader.php`
|
|
271
218
|
- `dist/extensions/extensions-loader.php`
|
|
272
|
-
- The first argument of the `wp_register_script` and `wp_register_style` calls in `dist/plain-entrypoints-loader.php`
|
|
219
|
+
- The first argument of the `wp_register_script` and `wp_register_style` calls in `dist/plain-entrypoints-loader.php`
|
|
273
220
|
|
|
274
221
|
### Example: Manual Enqueue with Localization
|
|
275
222
|
|
|
@@ -356,21 +303,93 @@ src: {
|
|
|
356
303
|
# Reference
|
|
357
304
|
|
|
358
305
|
## Root Options
|
|
359
|
-
| Option | Type | Default
|
|
360
|
-
|
|
361
|
-
| `
|
|
362
|
-
| `
|
|
363
|
-
| `
|
|
364
|
-
| `
|
|
365
|
-
| `
|
|
366
|
-
| `
|
|
367
|
-
| `
|
|
368
|
-
| `
|
|
369
|
-
| `
|
|
370
|
-
| `
|
|
371
|
-
| `
|
|
372
|
-
| `
|
|
373
|
-
| `
|
|
306
|
+
| Option | Type | Default | Description |
|
|
307
|
+
|------------------------------------|-----------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
308
|
+
| `standard` | `enum` | - | An identifier for the standard set of flags as of a given date. See the [Standards Flag Sets](#standard-flag-sets) section for values |
|
|
309
|
+
| `src` | `object` | `{}` | Files/directories to process (see the next section for what you can put in here) |
|
|
310
|
+
| `srcDir` | `string` | `""` | Source directory (**Required** on new sites) |
|
|
311
|
+
| `outputDir` | `string` | `""` | Output directory (**Required** on new sites) |
|
|
312
|
+
| `useUnifiedLoader` | `boolean` | `false` | Generate unified-loader.php (always set to `true` on new sites!) |
|
|
313
|
+
| `useWebpackResourceFiltering` | `boolean` | `false` | Generates versioned copies of images, fonts, etc (always set to `true` on new sites!) |
|
|
314
|
+
| `plainEntrypointsVersion` | `1\|2` | `1` | Use 2 for new sites |
|
|
315
|
+
| `extensionsVersion` | `1\|2\|3` | `1` | Use 3 for new sites |
|
|
316
|
+
| `verbose` | `boolean` | `false` | Verbose logging |
|
|
317
|
+
| `variables` | `object` | Auto | CSS/JS variables. If a variables.js file is present, this will automatically load from that file |
|
|
318
|
+
| `onlyRunPostCSSOnPCSS` | `boolean` | `false` | If true, the PostCSS processor will not be run on CSS files. This is true for all new sites and can be safely enabled on most sites if desired. |
|
|
319
|
+
| `assumeGlobalizedPlauditLibraries` | `boolean` | `true` | **[Advanced]** When `false`, normally-externalized plaudit libraries will be included.<br>**DO NOT USE THIS. IF YOU SEE IT BEING USED, CONTACT JOSH** |
|
|
320
|
+
| `externals` | `object` | - | **[Advanced]** Allows dependencies to be marked as external. This prevents them from being included in the bundle under the assumption that they will be provided via an alternate mechanism |
|
|
321
|
+
| `targetHandlePrefix` | `string` | Auto | **[Legacy]** Prefix for handles. Auto-detected from composer.json if omitted. Do not set this unless absolutely necessary |
|
|
322
|
+
|
|
323
|
+
### Standard Flag Sets
|
|
324
|
+
Each flag set is identified by the date that it was added to the standards set. Individual values can be overridden by specifying them in the config file
|
|
325
|
+
|
|
326
|
+
**2026-03-13**
|
|
327
|
+
```javascript
|
|
328
|
+
{
|
|
329
|
+
useWebpackResourceFiltering: true,
|
|
330
|
+
extensionsVersion: 3,
|
|
331
|
+
plainEntrypointsVersion: 2,
|
|
332
|
+
srcDir: "src",
|
|
333
|
+
outputDir: "dist",
|
|
334
|
+
useUnifiedLoader: true,
|
|
335
|
+
onlyRunPostCSSOnPCSS: true,
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Location-Encoding Filenames
|
|
342
|
+
This section covers how asset emission locations can be encoded in filenames.
|
|
343
|
+
While every common flag is accounted for in this schema, there are some things that cannot be encoded in filenames that will require enumeration in the `webpack.config.js` file's `src` object.
|
|
344
|
+
|
|
345
|
+
Location-encoding filenames are composed of two or more `.`-separated segments (the file extension being one of those segments).
|
|
346
|
+
The following is a brief list of notes followed by a breakdown of the individual segments:
|
|
347
|
+
- The only required segments are the location and type segments (the type segment is the file extension).
|
|
348
|
+
- So long as there is at least one location and type segment (the type segment MUST be last), "invalid" segments are allowed (this is for the purposes of giving human-readable names to files)
|
|
349
|
+
- Each file can enumerate any combination enqueuing locations
|
|
350
|
+
- The first item is special in that, if it encodes a location, in can optionally be suffixed with a type override (see the [Enqueuing Location](#enqueuing-location) section for more details)
|
|
351
|
+
|
|
352
|
+
Notes on how to read the following table:
|
|
353
|
+
- Brackets in the token column mean "optional section"
|
|
354
|
+
- `(-|=)` means "this can be either a dash or an equal sign"
|
|
355
|
+
- Pipe-separated items in parentheses means "any one of these items can go here"
|
|
356
|
+
|
|
357
|
+
| Name | Token | Usage |
|
|
358
|
+
|--------------------|-------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
359
|
+
| Enqueuing Location | `(enqueuing-location)[(-\|=)priority]` | This is a special section that is actually a collection of values. See the [Enqueuing Location](#enqueuing-location) section for more details |
|
|
360
|
+
| Type Override | `script`, `style`, `script-module` | Can be used to override the detected of the asset. Must be the first token in the filename; if used directly, it is shorthand for `both-(Type Override)` |
|
|
361
|
+
| Inline | `inline[(-\|=)position]`, `strategy(-\|=)inline[-position]` | Indicates that the script should be inlined. `position` can be either `before` or `after` |
|
|
362
|
+
| Strategy | `lazy\|eager`, `strategy(-\|=)(lazy\|eager\|defer\|async)` | Controls the loading strategy. Lazy and eager have shorthand while the remaining values must be prefixed with `strategy` |
|
|
363
|
+
| Fetch Priority | `fetchpriority(-\|=)(low\|high\|auto)` | Controls the fetchpriority property; `auto` is the default |
|
|
364
|
+
| In Footer | `in-footer`, `in_footer` | Sets the `in_footer` value to `true`; incompatible with `in-header` |
|
|
365
|
+
| In Header | `in-header`, `in_header` | Sets the `in_footer` value to `false`; incompatible with `in-footer` |
|
|
366
|
+
| Extension | `([ps]?c\|sa)ss`, `m?[jt]sx?` | This determines the type unless it is overridden. This **MUST** be the last token in the name (it is the file extension) |
|
|
367
|
+
|
|
368
|
+
### Enqueuing Location
|
|
369
|
+
If this is the first token, it can be suffixed with `-script`, `-style`, or `-script-module` to override the type.
|
|
370
|
+
Specifying the type override alone is interpreted as `both-(Type Override)` for compatibility with how blocks expect assets to be named.
|
|
371
|
+
|
|
372
|
+
Blocks do not support anything other than `view`, `editor`, and `both` (typically written as `script` or `style`).
|
|
373
|
+
|
|
374
|
+
**Valid Values**:
|
|
375
|
+
|
|
376
|
+
| Token | Meaning |
|
|
377
|
+
|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
|
|
378
|
+
| `view`, `client-view`, `clientView` | Enqueue the asset on the frontend (the part of the site seen by visitors) |
|
|
379
|
+
| `editor`, `client-editor`, `clientEditor` | Enqueue the asset in the *display* portion of the block editor |
|
|
380
|
+
| `both` | Shorthand for `view.editor` |
|
|
381
|
+
| `block-assets`, `block-assets` | Enqueue the asset in the *wrapper* portion of the block editor |
|
|
382
|
+
| `admin` | Enqueue the asset in the admin area |
|
|
383
|
+
| `login` | Enqueue the asset on the standard login page |
|
|
384
|
+
| `customizer` | Enqueue the asset in the legacy customizer interface |
|
|
385
|
+
| `analytics` | Enqueue the asset when analytics scripts have been accepted by the visitor (this "location" is unique to Plaudit's systems) |
|
|
386
|
+
| `register` | Register the asset *without* enqueuing it anywhere (this is primarily useful when localizing the asset) |
|
|
387
|
+
|
|
388
|
+
### Examples
|
|
389
|
+
#### Block- and Plain-compatible
|
|
390
|
+
- **A view script**: `view.ts`
|
|
391
|
+
- **An editor script**: `editor.ts`
|
|
392
|
+
- **A view and editor script**: `script.ts`
|
|
374
393
|
|
|
375
394
|
---
|
|
376
395
|
|
|
@@ -379,6 +398,7 @@ This section covers the shared options for entrypoints. See the [Entrypoint Type
|
|
|
379
398
|
|
|
380
399
|
### Path Queries
|
|
381
400
|
- These are URL-style queries added to the end of entrypoint *source* paths and are used to set entrypoint-specific properties in Plain and Block contexts.
|
|
401
|
+
- If you find yourself using these, consider switching to [Location-Encoding Filenames](#location-encoding-filenames)
|
|
382
402
|
- At present, this is only being used to configure inlining, but expansion to other systems is being considered
|
|
383
403
|
- The available options are: `strategy`, `inline`, `in_footer`, `fetchpriority`, and `position`
|
|
384
404
|
|
|
@@ -468,7 +488,8 @@ src/blocks/
|
|
|
468
488
|
#### Notes
|
|
469
489
|
- Blocks **should** be created with `pnpm @plaudit/scaffold create block`
|
|
470
490
|
- template.php and setup.php files are automatically loaded; however, they can be manually specified if desired
|
|
471
|
-
- Script and Style files **must** be specified using the `file:./<path here
|
|
491
|
+
- Script and Style files **must** be specified using the `file:./<path here>[?path-query-here]` syntax in the appropriate keys. See [WordPress' `block.json` reference](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/) for further details
|
|
492
|
+
- The `[?path-query-here]` component is something that we added. You can see more details in its section [here](#path-queries)
|
|
472
493
|
|
|
473
494
|
#### Per-Entrypoint Options
|
|
474
495
|
The `blocks` entrypoint type doesn't have any.
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.EnhancedBlockJSONPlugin = void 0;
|
|
7
7
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
|
-
const promises_1 =
|
|
8
|
+
const promises_1 = require("node:fs/promises");
|
|
9
9
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
11
|
const AbstractBiPhasicGroupAndEntryPlugin_1 = require("./AbstractBiPhasicGroupAndEntryPlugin");
|
|
@@ -37,8 +37,7 @@ class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.Abst
|
|
|
37
37
|
if (asset) {
|
|
38
38
|
const epBlockJson = entrypoint.name + ".json";
|
|
39
39
|
if (!applicableBlockJsonFiles[epBlockJson]) {
|
|
40
|
-
const blockJsonText = EnhancedBlockJSONPlugin.extractAssetSource(compilation, epBlockJson)
|
|
41
|
-
?? await promises_1.default.readFile(srcPath, 'utf-8');
|
|
40
|
+
const blockJsonText = EnhancedBlockJSONPlugin.extractAssetSource(compilation, epBlockJson) ?? await (0, promises_1.readFile)(srcPath, 'utf-8');
|
|
42
41
|
if (!blockJsonText) {
|
|
43
42
|
compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`Unable to extract the source for ${epBlockJson}`, srcPath));
|
|
44
43
|
continue;
|
|
@@ -66,10 +65,8 @@ class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.Abst
|
|
|
66
65
|
.map(file => [file, (0, shared_1.scriptOrStyleTest)(file, shared_1.scriptExtension)])
|
|
67
66
|
.filter((item) => item[1] !== '')
|
|
68
67
|
.map(([file, assetType]) => {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
: undefined;
|
|
72
|
-
const { scriptArgsObject, inlinedAsset } = (0, path_query_and_related_helpers_1.parseScriptArgsObjectFromPathQueryParameters)(compilation, file, pathQueryParameters);
|
|
68
|
+
const enqueuingFlags = (0, path_query_and_related_helpers_1.mergeTwoScriptEnqueuingControlFlagSets)(file, metadata.enqueuingFlags, this.dest.enqueuingFlags);
|
|
69
|
+
const { scriptArgsObject, inlinedAsset } = (0, path_query_and_related_helpers_1.convertEnqueuingControlFlagsToScriptArgsObject)(compilation, file, enqueuingFlags);
|
|
73
70
|
const wasOriginallyAStyleField = (0, shared_1.isStyleField)(metadata.entrypointField);
|
|
74
71
|
const outputPath = this.stripOffBlocksDestPrefix(file);
|
|
75
72
|
if (wasOriginallyAStyleField !== (assetType === "style")) { // This means that the file is extracted
|
|
@@ -302,7 +302,8 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
|
|
|
302
302
|
const isScript = type !== 'style';
|
|
303
303
|
const dependencies = isScript === entrypointChunkIsScript ? assetData.dependencies : [];
|
|
304
304
|
const { lazyLoader, locations } = this.dest;
|
|
305
|
-
const {
|
|
305
|
+
const { flags } = (0, path_query_and_related_helpers_1.unpackEnqueuingControlFlagsFromPathQueryParameters)(typeof locations.registerScriptArgs === 'object' ? locations.registerScriptArgs : { strategy: locations.registerScriptArgs }, file, "registerScriptArgs");
|
|
306
|
+
const { inlinedAsset, scriptArgsObject } = (0, path_query_and_related_helpers_1.convertEnqueuingControlFlagsToScriptArgsObject)(compilation, file, (0, path_query_and_related_helpers_1.mergeTwoScriptEnqueuingControlFlagSets)(file, flags, this.dest.enqueuingFlags));
|
|
306
307
|
const rest = isScript && scriptArgsObject !== undefined ? [dependencies, assetData.version, scriptArgsObject] : [dependencies, assetData.version];
|
|
307
308
|
const destPath = node_path_1.default.join(compilation.outputOptions.path, file);
|
|
308
309
|
handles.push({
|
package/build/shared.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PHPWriter } from "@plaudit/php-writer";
|
|
2
2
|
import type { Options as PostcssFunctionsOptions } from "postcss-functions";
|
|
3
3
|
import { AssetInfo, Compilation, Configuration, Entrypoint, WebpackError, Compiler } from "webpack";
|
|
4
|
+
import type { NormalizedEnqueuingControlFlags } from "./utils/path-query-and-related-helpers";
|
|
4
5
|
export type ParsedAssetsJson = Record<string, {
|
|
5
6
|
dependencies: string[];
|
|
6
7
|
version: string;
|
|
@@ -54,16 +55,19 @@ export type StandardLocationNameMeta = {
|
|
|
54
55
|
};
|
|
55
56
|
};
|
|
56
57
|
export type StandardLocationNames = keyof typeof standardLocationNamesMeta;
|
|
58
|
+
export declare function isStandardLocationName(name: string): name is StandardLocationNames;
|
|
57
59
|
type LocationWithHookNameSupport = boolean | number | string | string[] | {
|
|
58
60
|
hook_name?: string | string[];
|
|
59
61
|
priority?: number;
|
|
60
62
|
};
|
|
61
63
|
type InputRegisterScriptArgs = ScriptArgsObject | boolean | 'lazy' | 'eager' | 'inline';
|
|
62
|
-
export
|
|
64
|
+
export declare function isRegisterScriptArgsShorthandName(name: string): name is Extract<InputRegisterScriptArgs, string>;
|
|
65
|
+
export type RealUsageLocations = {
|
|
63
66
|
[K in StandardLocationNames]?: typeof standardLocationNamesMeta[K] extends {
|
|
64
67
|
supports_hook_name: true;
|
|
65
68
|
} ? LocationWithHookNameSupport : boolean | number;
|
|
66
|
-
}
|
|
69
|
+
};
|
|
70
|
+
export type UsageLocations = RealUsageLocations & {
|
|
67
71
|
register?: boolean | number;
|
|
68
72
|
inline?: number;
|
|
69
73
|
handle?: string | ((generatedHandle: string) => string);
|
|
@@ -74,7 +78,7 @@ export type NormalizedUsageLocations = Omit<UsageLocations, 'registerScriptArgs'
|
|
|
74
78
|
};
|
|
75
79
|
export declare function isNormalizedUsageLocations(usageLocations: UsageLocations): usageLocations is NormalizedUsageLocations;
|
|
76
80
|
export declare function constantKeys<K extends string, V>(object: {
|
|
77
|
-
[k in K]
|
|
81
|
+
[k in K]?: V;
|
|
78
82
|
}): K[];
|
|
79
83
|
export declare function constantEntries<K extends string, V>(object: {
|
|
80
84
|
[k in K]: V;
|
|
@@ -84,6 +88,7 @@ export declare const enum SourceType {
|
|
|
84
88
|
extensions = "extensions",
|
|
85
89
|
plain = "plain"
|
|
86
90
|
}
|
|
91
|
+
export declare function isSourceType(str: string): str is SourceType;
|
|
87
92
|
export declare function determineCurrentSourceType(dest: string | AdvancedOutputConfig, srcIsDirectory: boolean): SourceType;
|
|
88
93
|
export interface WebpackPlugin {
|
|
89
94
|
apply(compiler: Compiler): void;
|
|
@@ -107,17 +112,20 @@ export type AdvancedOutputConfig = {
|
|
|
107
112
|
locations?: UsageLocations | UsageLocations['handle'];
|
|
108
113
|
lazyLoader?: string;
|
|
109
114
|
pathQueryParameters?: PathQueryParameters;
|
|
115
|
+
enqueuingFlags?: NormalizedEnqueuingControlFlags;
|
|
110
116
|
};
|
|
111
117
|
type OptionalCfgFields = 'directoryLayout' | 'externalize' | 'lazyLoader' | 'pathQueryParameters';
|
|
112
|
-
export type VerifiedAdvancedOutputConfig = Required<Omit<AdvancedOutputConfig, 'locations' | OptionalCfgFields>> & Pick<AdvancedOutputConfig, OptionalCfgFields> & {
|
|
118
|
+
export type VerifiedAdvancedOutputConfig = Required<Omit<AdvancedOutputConfig, 'locations' | 'enqueuingFlags' | OptionalCfgFields>> & Pick<AdvancedOutputConfig, OptionalCfgFields> & {
|
|
119
|
+
enqueuingFlags: NormalizedEnqueuingControlFlags | undefined;
|
|
113
120
|
locations: NormalizedUsageLocations;
|
|
114
121
|
};
|
|
115
122
|
export type SourcesObject = Record<string, string | AdvancedOutputConfig | boolean>;
|
|
116
123
|
export type PlauditWordpressWebpackConfig = {
|
|
124
|
+
standard?: '2026-03-13';
|
|
117
125
|
standaloneBlocks?: boolean;
|
|
118
126
|
variables?: Record<string, any>;
|
|
119
127
|
verbose?: boolean;
|
|
120
|
-
src
|
|
128
|
+
src?: string[] | SourcesObject;
|
|
121
129
|
stats?: Configuration['stats'];
|
|
122
130
|
postcss?: {
|
|
123
131
|
functions?: (variables: (name: string) => unknown) => PostcssFunctionsOptions['functions'];
|
|
@@ -148,6 +156,7 @@ export type FileSegmentBlockEntrypointInfo = {
|
|
|
148
156
|
dest: VerifiedAdvancedOutputConfig;
|
|
149
157
|
absoluteSrc: string;
|
|
150
158
|
pathQueryParameters: PathQueryParameters | undefined;
|
|
159
|
+
enqueuingFlags: NormalizedEnqueuingControlFlags | undefined;
|
|
151
160
|
};
|
|
152
161
|
export type PathQueryParameters = Record<string, unknown | [unknown, ...unknown[]]>;
|
|
153
162
|
export type BlockEntrypointInfo = FileSegmentBlockEntrypointInfo | {
|
package/build/shared.js
CHANGED
|
@@ -5,9 +5,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.styleExtension = exports.scriptWithModuleExtension = exports.scriptWithoutModuleExtension = exports.scriptExtension = exports.entrypointFields = exports.standardLocationNamesMeta = void 0;
|
|
7
7
|
exports.isParsedAssetsJson = isParsedAssetsJson;
|
|
8
|
+
exports.isStandardLocationName = isStandardLocationName;
|
|
9
|
+
exports.isRegisterScriptArgsShorthandName = isRegisterScriptArgsShorthandName;
|
|
8
10
|
exports.isNormalizedUsageLocations = isNormalizedUsageLocations;
|
|
9
11
|
exports.constantKeys = constantKeys;
|
|
10
12
|
exports.constantEntries = constantEntries;
|
|
13
|
+
exports.isSourceType = isSourceType;
|
|
11
14
|
exports.determineCurrentSourceType = determineCurrentSourceType;
|
|
12
15
|
exports.convertUsageLocationsHandleToEmittableHandle = convertUsageLocationsHandleToEmittableHandle;
|
|
13
16
|
exports.makeEmittableConfigPHP = makeEmittableConfigPHP;
|
|
@@ -30,13 +33,13 @@ exports.emitPHPWriterAsAsset = emitPHPWriterAsAsset;
|
|
|
30
33
|
exports.dedent = dedent;
|
|
31
34
|
exports.resolveLegacyBlockScriptsInFolder = resolveLegacyBlockScriptsInFolder;
|
|
32
35
|
exports.appendAddInlineAssetCall = appendAddInlineAssetCall;
|
|
36
|
+
const node_crypto_1 = require("node:crypto");
|
|
33
37
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
34
38
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
35
39
|
const node_path_1 = __importDefault(require("node:path"));
|
|
36
40
|
const php_writer_1 = require("@plaudit/php-writer");
|
|
37
41
|
const expressions_1 = require("@plaudit/php-writer/expressions");
|
|
38
42
|
const webpack_1 = require("webpack");
|
|
39
|
-
const node_crypto_1 = require("node:crypto");
|
|
40
43
|
function isParsedAssetsJson(thing) {
|
|
41
44
|
if (!thing || typeof thing !== 'object') {
|
|
42
45
|
return false;
|
|
@@ -59,6 +62,12 @@ exports.standardLocationNamesMeta = {
|
|
|
59
62
|
customizer: { action: "customize_controls_enqueue_scripts" },
|
|
60
63
|
analytics: { action: "plaudit_enqueue_analytics" },
|
|
61
64
|
};
|
|
65
|
+
function isStandardLocationName(name) {
|
|
66
|
+
return name in exports.standardLocationNamesMeta;
|
|
67
|
+
}
|
|
68
|
+
function isRegisterScriptArgsShorthandName(name) {
|
|
69
|
+
return ['lazy', 'eager', 'inline'].includes(name);
|
|
70
|
+
}
|
|
62
71
|
function isNormalizedUsageLocations(usageLocations) {
|
|
63
72
|
return typeof usageLocations.registerScriptArgs !== 'string';
|
|
64
73
|
}
|
|
@@ -68,6 +77,9 @@ function constantKeys(object) {
|
|
|
68
77
|
function constantEntries(object) {
|
|
69
78
|
return Object.entries(object);
|
|
70
79
|
}
|
|
80
|
+
function isSourceType(str) {
|
|
81
|
+
return str === "blocks" /* SourceType.blocks */ || str === "extensions" /* SourceType.extensions */ || str === "plain" /* SourceType.plain */;
|
|
82
|
+
}
|
|
71
83
|
function determineCurrentSourceType(dest, srcIsDirectory) {
|
|
72
84
|
if (typeof dest === 'string') {
|
|
73
85
|
return srcIsDirectory ? "blocks" /* SourceType.blocks */ : "plain" /* SourceType.plain */;
|
|
@@ -107,7 +119,7 @@ function leadingSlashIt(pathOrSomething) {
|
|
|
107
119
|
exports.scriptExtension = /(?<filename>.+)(?<extension>\.m?[jt]sx?)$/i;
|
|
108
120
|
exports.scriptWithoutModuleExtension = /(?<filename>.+)(?<extension>\.[jt]sx?)($|\?)/i;
|
|
109
121
|
exports.scriptWithModuleExtension = /(?<filename>.+)(?<extension>\.m[jt]sx?)($|\?)/i;
|
|
110
|
-
exports.styleExtension = /(?<filename>.+)(?<extension>\.(
|
|
122
|
+
exports.styleExtension = /(?<filename>.+)(?<extension>\.([ps]?c|sa)ss)($|\?)/i;
|
|
111
123
|
function scriptOrStyleTest(entryPath, scriptExtension) {
|
|
112
124
|
return scriptExtension.test(entryPath) ? "script" : (exports.styleExtension.test(entryPath) ? "style" : "");
|
|
113
125
|
}
|
|
@@ -3,7 +3,7 @@ import type { AdditionalDependencyInjectorPlugin } from "../plugins/AdditionalDe
|
|
|
3
3
|
import { EntrypointFields, PlauditWordpressWebpackConfig, BlockEntrypointInfo, VerifiedAdvancedOutputConfig, MinimumViableMetadata, WebpackPlugin } from "../shared";
|
|
4
4
|
import type { Compiler, Configuration, DynamicEntryPlugin, WebpackPluginInstance } from "webpack";
|
|
5
5
|
import type WebpackRemoveEmptyScriptsPlugin from "webpack-remove-empty-scripts";
|
|
6
|
-
export type VerifiedPlauditWordpressWebpackConfig = Required<Omit<PlauditWordpressWebpackConfig, 'variables' | 'src' | 'externals'>> & {
|
|
6
|
+
export type VerifiedPlauditWordpressWebpackConfig = Required<Omit<PlauditWordpressWebpackConfig, 'variables' | 'src' | 'externals' | 'standard'>> & {
|
|
7
7
|
variablesFilePath?: string;
|
|
8
8
|
currentVariables: Record<string, any>;
|
|
9
9
|
} & Pick<PlauditWordpressWebpackConfig, 'externals'>;
|
|
@@ -10,6 +10,7 @@ exports.commonMakeWebpackConfig = commonMakeWebpackConfig;
|
|
|
10
10
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
11
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
12
12
|
const node_path_1 = __importDefault(require("node:path"));
|
|
13
|
+
const location_encoding_filename_parser_1 = require("./location-encoding-filename-parser");
|
|
13
14
|
const path_query_and_related_helpers_1 = require("./path-query-and-related-helpers");
|
|
14
15
|
const shared_1 = require("../shared");
|
|
15
16
|
const css_minimizer_webpack_plugin_1 = __importDefault(require("css-minimizer-webpack-plugin"));
|
|
@@ -36,9 +37,10 @@ function mapToRealEntrypoints(entrypoint, dir, supportedExtensions, args) {
|
|
|
36
37
|
.map(ep => joinPossiblyAbsolutePaths(dir, mapper(ep)))
|
|
37
38
|
.filter(ep => supportedExtensions(ep) && node_fs_1.default.statSync(ep, { throwIfNoEntry: false })?.isFile())
|
|
38
39
|
.map(path_query_and_related_helpers_1.unpackPotentiallyPrefixedFilePath)
|
|
39
|
-
.map(([ep,
|
|
40
|
+
.map(([ep, rawPathQueryParameters]) => {
|
|
40
41
|
const parsedEntrypoint = node_path_1.default.parse(ep);
|
|
41
42
|
const entrypointField = shared_1.styleExtension.test(ep) ? 'style' : shared_1.scriptWithModuleExtension.test(ep) ? 'viewScriptModule' : 'script';
|
|
43
|
+
const { flags: enqueuingFlags, remainder: pathQueryParameters } = (0, path_query_and_related_helpers_1.unpackEnqueuingControlFlagsFromPathQueryParameters)(rawPathQueryParameters, ep, 'path query parameters');
|
|
42
44
|
const fakeEntrypointInfo = {
|
|
43
45
|
blockJsonOrigin: args.entrypointJsonOrigin,
|
|
44
46
|
entrypointField,
|
|
@@ -48,7 +50,8 @@ function mapToRealEntrypoints(entrypoint, dir, supportedExtensions, args) {
|
|
|
48
50
|
handleGroup: (0, shared_1.getHandleGroup)(entrypointField),
|
|
49
51
|
dest,
|
|
50
52
|
absoluteSrc: ep,
|
|
51
|
-
pathQueryParameters
|
|
53
|
+
pathQueryParameters,
|
|
54
|
+
enqueuingFlags,
|
|
52
55
|
};
|
|
53
56
|
return [joinPossiblyAbsolutePaths(dest.destination, node_path_1.default.basename(parsedEntrypoint.dir), parsedEntrypoint.name),
|
|
54
57
|
{ import: [ep], plauditMetadata: fakeEntrypointInfo }];
|
|
@@ -133,6 +136,7 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
|
|
|
133
136
|
const blockJsonOrigin = node_path_1.default.join(dir, 'block.json');
|
|
134
137
|
const blockJson = JSON.parse(await promises_1.default.readFile(blockJsonOrigin, 'utf8'));
|
|
135
138
|
const blockJsonChunkName = node_path_1.default.join(dest.destination, node_path_1.default.relative(srcRoot, dir), "block");
|
|
139
|
+
const filesRegisteredByJson = [];
|
|
136
140
|
const presentEntrypoints = (await Promise.all(entrypointFields
|
|
137
141
|
.filter(entrypointField => entrypointField in blockJson)
|
|
138
142
|
.flatMap(entrypointField => {
|
|
@@ -140,16 +144,19 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
|
|
|
140
144
|
.filter(originalValue => typeof originalValue === 'string')
|
|
141
145
|
.filter(originalValue => originalValue?.startsWith("file:"))
|
|
142
146
|
.map(originalValue => {
|
|
143
|
-
const [entrypointPath,
|
|
147
|
+
const [entrypointPath, rawLocalPathQueryParameters] = (0, path_query_and_related_helpers_1.unpackPotentiallyPrefixedFilePath)(originalValue);
|
|
144
148
|
const absoluteSrc = node_path_1.default.normalize(node_path_1.default.join(dir, entrypointPath));
|
|
145
|
-
|
|
149
|
+
filesRegisteredByJson.push(absoluteSrc);
|
|
150
|
+
const { flags: localEnqueuingFlags, remainder: localPathQueryParameters } = (0, path_query_and_related_helpers_1.unpackEnqueuingControlFlagsFromPathQueryParameters)(rawLocalPathQueryParameters, absoluteSrc, "path query parameters");
|
|
151
|
+
const enqueuingFlags = (0, path_query_and_related_helpers_1.mergeTwoScriptEnqueuingControlFlagSets)(absoluteSrc, localEnqueuingFlags, dest.enqueuingFlags);
|
|
152
|
+
const pathQueryParameters = { ...dest.pathQueryParameters, ...localPathQueryParameters };
|
|
146
153
|
return promises_1.default.stat(absoluteSrc)
|
|
147
154
|
.then(stats => {
|
|
148
155
|
if (stats.isFile()) {
|
|
149
156
|
const parsedEntrypoint = node_path_1.default.parse(node_path_1.default.normalize(node_path_1.default.join(dest.destination, node_path_1.default.relative(srcRoot, dir), entrypointPath)));
|
|
150
157
|
const extensionlessExpectedSrc = node_path_1.default.normalize(node_path_1.default.join(parsedEntrypoint.dir, parsedEntrypoint.name));
|
|
151
158
|
const entrypointName = node_path_1.default.normalize(joinPossiblyAbsolutePaths(parsedEntrypoint.dir, parsedEntrypoint.name));
|
|
152
|
-
return { entrypointField, originalValue, entrypointName, extensionlessExpectedSrc, absoluteSrc, pathQueryParameters };
|
|
159
|
+
return { entrypointField, originalValue, entrypointName, extensionlessExpectedSrc, absoluteSrc, pathQueryParameters, enqueuingFlags };
|
|
153
160
|
}
|
|
154
161
|
else {
|
|
155
162
|
return undefined;
|
|
@@ -157,6 +164,56 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
|
|
|
157
164
|
}, () => undefined);
|
|
158
165
|
});
|
|
159
166
|
}))).filter(pe => pe !== undefined);
|
|
167
|
+
for await (const dirent of await promises_1.default.opendir(dir)) {
|
|
168
|
+
if (!dirent.isFile()) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const absoluteSrc = node_path_1.default.normalize(node_path_1.default.join(dir, dirent.name));
|
|
172
|
+
if (filesRegisteredByJson.includes(absoluteSrc)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const parsedFilename = (0, location_encoding_filename_parser_1.parseLocationEncodingFilenameForBlock)(absoluteSrc);
|
|
176
|
+
if (!parsedFilename) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const { type, locations, flags } = parsedFilename;
|
|
180
|
+
let entrypointField;
|
|
181
|
+
if (Object.keys(locations).length === 2) {
|
|
182
|
+
if (type === 'script-module') {
|
|
183
|
+
console.error(`Blocks cannot have script modules enqueued in editor mode. Found one enqueued in both editor and view in ${dirent.parentPath}. It will be enqueued in view alone.`);
|
|
184
|
+
entrypointField = 'viewScriptModule';
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
entrypointField = type;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
const location = (0, shared_1.constantKeys)(locations)[0];
|
|
192
|
+
if (type === 'script-module') {
|
|
193
|
+
if (location !== 'clientView') {
|
|
194
|
+
console.error(`Blocks cannot have script modules enqueued in editor mode. Found one in ${dirent.parentPath}. It will be ignored`);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
entrypointField = 'viewScriptModule';
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
entrypointField = (location.substring(6).toLowerCase() + type.substring(0, 1).toUpperCase() + type.substring(1));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const parsedEntrypoint = node_path_1.default.parse(node_path_1.default.normalize(node_path_1.default.join(dest.destination, node_path_1.default.relative(srcRoot, dir), `./${dirent.name}`)));
|
|
204
|
+
const extensionlessExpectedSrc = node_path_1.default.normalize(node_path_1.default.join(parsedEntrypoint.dir, parsedEntrypoint.name));
|
|
205
|
+
const entrypointName = node_path_1.default.normalize(joinPossiblyAbsolutePaths(parsedEntrypoint.dir, parsedEntrypoint.name));
|
|
206
|
+
const enqueuingFlags = (0, path_query_and_related_helpers_1.mergeTwoScriptEnqueuingControlFlagSets)(absoluteSrc, flags, dest.enqueuingFlags);
|
|
207
|
+
presentEntrypoints.push({
|
|
208
|
+
entrypointField,
|
|
209
|
+
originalValue: dirent.name,
|
|
210
|
+
entrypointName,
|
|
211
|
+
extensionlessExpectedSrc,
|
|
212
|
+
absoluteSrc,
|
|
213
|
+
pathQueryParameters: dest.pathQueryParameters,
|
|
214
|
+
enqueuingFlags
|
|
215
|
+
});
|
|
216
|
+
}
|
|
160
217
|
const entrypointNamesWithEffectiveDuplicates = presentEntrypoints
|
|
161
218
|
.reduce((a, entry) => {
|
|
162
219
|
// If it's undefined, then this is the first instance, otherwise, it's not the first instance and, therefore, is expected to be a duplicate
|
|
@@ -201,7 +258,7 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
|
|
|
201
258
|
}
|
|
202
259
|
];
|
|
203
260
|
}));
|
|
204
|
-
rawEntrypoints.push([blockJsonChunkName, { import: [blockJsonOrigin], plauditMetadata: { purpose: "block-json-inclusion-assurance", dest, absoluteSrc: blockJsonOrigin
|
|
261
|
+
rawEntrypoints.push([blockJsonChunkName, { import: [blockJsonOrigin], plauditMetadata: { purpose: "block-json-inclusion-assurance", dest, absoluteSrc: blockJsonOrigin } }]);
|
|
205
262
|
wpmlFiles.push(node_path_1.default.join(dir, 'block.json'));
|
|
206
263
|
}
|
|
207
264
|
catch (e) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { RealUsageLocations } from "../shared";
|
|
2
|
+
import { NormalizedEnqueuingControlFlags } from "./path-query-and-related-helpers";
|
|
3
|
+
export type ParsedLocationEncodingFilename = {
|
|
4
|
+
type: 'script' | 'style' | 'script-module';
|
|
5
|
+
locations: RealUsageLocations & {
|
|
6
|
+
register?: boolean | number;
|
|
7
|
+
};
|
|
8
|
+
flags: NormalizedEnqueuingControlFlags;
|
|
9
|
+
};
|
|
10
|
+
export declare function parseLocationEncodingFilename(filename: string): ParsedLocationEncodingFilename | undefined;
|
|
11
|
+
export declare function parseLocationEncodingFilenameForBlock(filename: string): Omit<ParsedLocationEncodingFilename, 'locations'> & {
|
|
12
|
+
locations: Pick<RealUsageLocations, 'clientEditor' | 'clientView'>;
|
|
13
|
+
} | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* This handles detecting all keys of standardLocationNamesMeta as well as "view", "client-view", "editor", "client-editor", and "block-assets".
|
|
16
|
+
* It MUST be kept in sync with standardLocationNamesMeta
|
|
17
|
+
* @param segment
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractLocationFromPropertyEncodingFilenameSegment(segment: string): {
|
|
20
|
+
readonly locationName: "clientView" | "clientEditor" | "blockAssets" | "admin" | "login" | "customizer" | "analytics" | "register";
|
|
21
|
+
readonly priority: number | true;
|
|
22
|
+
} | {
|
|
23
|
+
readonly locationName: false;
|
|
24
|
+
readonly priority?: undefined;
|
|
25
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseLocationEncodingFilename = parseLocationEncodingFilename;
|
|
4
|
+
exports.parseLocationEncodingFilenameForBlock = parseLocationEncodingFilenameForBlock;
|
|
5
|
+
exports.extractLocationFromPropertyEncodingFilenameSegment = extractLocationFromPropertyEncodingFilenameSegment;
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const shared_1 = require("../shared");
|
|
8
|
+
function parseLocationEncodingFilename(filename) {
|
|
9
|
+
const { name, ext } = (0, node_path_1.parse)(filename);
|
|
10
|
+
if (name.startsWith("~")) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
let type = /^\.(?:s[ac]|p?c)ss$/i.test(ext) ? 'style' : /^\.m[jt]sx?/i.test(ext) ? 'script-module' : /^\.[jt]sx?/i.test(ext) ? 'script' : false;
|
|
14
|
+
if (type === false) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const locations = {};
|
|
18
|
+
const flags = {};
|
|
19
|
+
const nameSegments = name.split("."); //Split always returns at least one string
|
|
20
|
+
const typeOverrideMatch = /^(?<enqueuePosition>.+)-(?<typeOverride>script|style|script-module)$|^(?<typeOverride>script|style|script-module)$/.exec(nameSegments[0]);
|
|
21
|
+
if (typeOverrideMatch) {
|
|
22
|
+
nameSegments[0] = typeOverrideMatch.groups?.["enqueuePosition"] ?? "both"; // We override the first segment with the version without
|
|
23
|
+
type = typeOverrideMatch.groups?.["typeOverride"];
|
|
24
|
+
}
|
|
25
|
+
const inlinePattern = /^(?<inline>inline)(?:[-=](?<position>before|after))?$|^strategy[-=](?<inline>inline)(?:-(?<position>before|after))?$/;
|
|
26
|
+
const strategyPattern = /^strategy[-=](?<strategy>eager|lazy|defer|async)$|^(?<strategy>lazy|eager)$/;
|
|
27
|
+
const fetchpriorityPattern = /^fetchpriority[-=](auto|low|high)$/;
|
|
28
|
+
const bothViewAndEditorLocationPattern = /^(?:client-)?(?<both>both)(?:[-=](?<priority>-?\d+))?$/;
|
|
29
|
+
for (const segment of nameSegments) {
|
|
30
|
+
const { locationName, priority } = extractLocationFromPropertyEncodingFilenameSegment(segment);
|
|
31
|
+
if (locationName) {
|
|
32
|
+
locations[locationName] = priority;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const lcSegment = segment.toLowerCase();
|
|
36
|
+
const { both, priority: bothPriority } = bothViewAndEditorLocationPattern.exec(lcSegment)?.groups ?? {};
|
|
37
|
+
if (both) {
|
|
38
|
+
const priority = bothPriority !== undefined ? parseInt(bothPriority) : true;
|
|
39
|
+
locations.clientView = priority;
|
|
40
|
+
locations.clientEditor = priority;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const { inline, position: inlinePosition } = (inlinePattern.exec(lcSegment)?.groups ?? {});
|
|
44
|
+
if (inline) {
|
|
45
|
+
flags.inline = true;
|
|
46
|
+
flags.position = inlinePosition;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const strategy = strategyPattern.exec(lcSegment)?.groups?.['strategy']?.toLowerCase();
|
|
50
|
+
if (strategy) {
|
|
51
|
+
flags.strategy = strategy;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const fetchpriority = fetchpriorityPattern.exec(lcSegment)?.[1];
|
|
55
|
+
if (fetchpriority !== undefined) {
|
|
56
|
+
flags.fetchpriority = fetchpriority;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
switch (segment.toLowerCase()) {
|
|
60
|
+
// Loading flags
|
|
61
|
+
case "in-footer":
|
|
62
|
+
case "in_footer":
|
|
63
|
+
flags.in_footer = true;
|
|
64
|
+
break;
|
|
65
|
+
case "in-header":
|
|
66
|
+
case "in_header":
|
|
67
|
+
flags.in_footer = false;
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// This means that it wasn't a location-encoding filename
|
|
74
|
+
if (Object.values(locations).length === 0) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return { type, locations, flags };
|
|
78
|
+
}
|
|
79
|
+
function parseLocationEncodingFilenameForBlock(filename) {
|
|
80
|
+
const parsedFilename = parseLocationEncodingFilename(filename);
|
|
81
|
+
if (parsedFilename !== undefined) {
|
|
82
|
+
if ((0, shared_1.constantKeys)(parsedFilename.locations).some(value => value !== 'clientView' && value !== 'clientEditor')) {
|
|
83
|
+
throw (0, shared_1.newWebpackErrorForFile)(`Block assets cannot be enqueued anywhere other than view, editor, or both. Saw: ${(0, shared_1.constantKeys)(parsedFilename).join(", ")}`, filename);
|
|
84
|
+
}
|
|
85
|
+
if (Object.values(parsedFilename.locations).some(value => typeof value === 'number')) {
|
|
86
|
+
throw (0, shared_1.newWebpackErrorForFile)(`Block assets cannot be enqueued with a priority`, filename);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return parsedFilename;
|
|
90
|
+
}
|
|
91
|
+
const standardLocationNamesAndPriorityPatternInFilenameSegment = /^(?:(?<view>clientView|client-view|view)|(?<editor>clientEditor|client-editor|editor)|(?<blockAssets>blockAssets|block-assets)|(?<locationName>admin|login|customizer|analytics|register))(?:[-=](?<priority>-?\d+))?$/;
|
|
92
|
+
/**
|
|
93
|
+
* This handles detecting all keys of standardLocationNamesMeta as well as "view", "client-view", "editor", "client-editor", and "block-assets".
|
|
94
|
+
* It MUST be kept in sync with standardLocationNamesMeta
|
|
95
|
+
* @param segment
|
|
96
|
+
*/
|
|
97
|
+
function extractLocationFromPropertyEncodingFilenameSegment(segment) {
|
|
98
|
+
const { view, editor, blockAssets, locationName, priority: rawPriority } = standardLocationNamesAndPriorityPatternInFilenameSegment.exec(segment)
|
|
99
|
+
?.groups ?? {};
|
|
100
|
+
const priority = rawPriority !== undefined ? parseInt(rawPriority) : true;
|
|
101
|
+
if (view) {
|
|
102
|
+
return { locationName: "clientView", priority };
|
|
103
|
+
}
|
|
104
|
+
if (editor) {
|
|
105
|
+
return { locationName: "clientEditor", priority };
|
|
106
|
+
}
|
|
107
|
+
if (blockAssets) {
|
|
108
|
+
return { locationName: "blockAssets", priority };
|
|
109
|
+
}
|
|
110
|
+
if (locationName) {
|
|
111
|
+
return { locationName, priority };
|
|
112
|
+
}
|
|
113
|
+
return { locationName: false };
|
|
114
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Compilation } from "webpack";
|
|
2
|
-
import { InlinedAsset, PathQueryParameters, ScriptArgsObject
|
|
1
|
+
import type { Compilation } from "webpack";
|
|
2
|
+
import { InlinedAsset, PathQueryParameters, ScriptArgsObject } from "../shared";
|
|
3
3
|
export declare function getAssetFileContents(compilation: Compilation, name: string): string;
|
|
4
4
|
export declare function unpackPotentiallyPrefixedFilePath(filePath: string): [string, PathQueryParameters | undefined];
|
|
5
5
|
/**
|
|
@@ -26,28 +26,32 @@ export declare function newInvalidFetchPriorityError(fetchpriority: unknown, fil
|
|
|
26
26
|
export type PositionForInlineStrategy = 'before' | 'after';
|
|
27
27
|
export declare function isValidPositionForInlineStrategy(position: unknown): position is PositionForInlineStrategy;
|
|
28
28
|
export declare function newInvalidPositionForInlineStrategyError(position: unknown, file: string): import("webpack").WebpackError;
|
|
29
|
-
export declare function mergeInPathQueryParameters(file: string, registerScriptArgs: UsageLocations['registerScriptArgs'], pathQueryParameters: PathQueryParameters | undefined): NormalizedScriptEnqueuingControlFlags | undefined;
|
|
30
29
|
/**
|
|
31
30
|
* This function ensures that the passed pathQueryParameters are normalized for the config-loading step, NOT the emission step
|
|
32
31
|
*/
|
|
33
|
-
export type
|
|
32
|
+
export type NormalizedEnqueuingControlFlags = {
|
|
34
33
|
strategy?: Exclude<LoadingStrategy, 'inline'>;
|
|
35
34
|
in_footer?: InFooter;
|
|
36
35
|
inline?: boolean;
|
|
37
36
|
fetchpriority?: FetchPriority;
|
|
38
37
|
position?: 'before' | 'after';
|
|
39
38
|
};
|
|
39
|
+
export declare function mergeTwoScriptEnqueuingControlFlagSets(file: string, baseArgs: NormalizedEnqueuingControlFlags | undefined, ancestorArgs: NormalizedEnqueuingControlFlags | undefined): NormalizedEnqueuingControlFlags | undefined;
|
|
40
|
+
export declare function unpackEnqueuingControlFlagsFromPathQueryParameters(pathQueryParameters: PathQueryParameters | undefined, file: string, sourceType: 'registerScriptArgs' | 'path query parameters'): {
|
|
41
|
+
flags?: NormalizedEnqueuingControlFlags;
|
|
42
|
+
remainder?: PathQueryParameters;
|
|
43
|
+
};
|
|
40
44
|
/**
|
|
41
45
|
* This function does a few things:
|
|
42
46
|
* <ol>
|
|
43
|
-
* <li>It
|
|
44
|
-
* <li>If
|
|
47
|
+
* <li>It converts the strategy, in_footer, and fetchpriority flags into a valid script args object</li>
|
|
48
|
+
* <li>If inline is true, it records the contents of the asset and the value of the position flag for later injection and removes the asset from the compilation output</li>
|
|
45
49
|
* </ol>
|
|
46
50
|
* @param compilation
|
|
47
51
|
* @param file
|
|
48
|
-
* @param
|
|
52
|
+
* @param flags
|
|
49
53
|
*/
|
|
50
|
-
export declare function
|
|
54
|
+
export declare function convertEnqueuingControlFlagsToScriptArgsObject(compilation: Compilation, file: string, flags: NormalizedEnqueuingControlFlags | undefined): {
|
|
51
55
|
scriptArgsObject?: ScriptArgsObject;
|
|
52
56
|
inlinedAsset?: InlinedAsset;
|
|
53
57
|
};
|
|
@@ -11,10 +11,11 @@ exports.isValidFetchPriority = isValidFetchPriority;
|
|
|
11
11
|
exports.newInvalidFetchPriorityError = newInvalidFetchPriorityError;
|
|
12
12
|
exports.isValidPositionForInlineStrategy = isValidPositionForInlineStrategy;
|
|
13
13
|
exports.newInvalidPositionForInlineStrategyError = newInvalidPositionForInlineStrategyError;
|
|
14
|
-
exports.
|
|
15
|
-
exports.
|
|
16
|
-
|
|
14
|
+
exports.mergeTwoScriptEnqueuingControlFlagSets = mergeTwoScriptEnqueuingControlFlagSets;
|
|
15
|
+
exports.unpackEnqueuingControlFlagsFromPathQueryParameters = unpackEnqueuingControlFlagsFromPathQueryParameters;
|
|
16
|
+
exports.convertEnqueuingControlFlagsToScriptArgsObject = convertEnqueuingControlFlagsToScriptArgsObject;
|
|
17
17
|
const node_path_1 = require("node:path");
|
|
18
|
+
const shared_1 = require("../shared");
|
|
18
19
|
function getAssetFileContents(compilation, name) {
|
|
19
20
|
const asset = compilation.getAsset(name);
|
|
20
21
|
if (!asset) {
|
|
@@ -101,127 +102,112 @@ function isValidPositionForInlineStrategy(position) {
|
|
|
101
102
|
function newInvalidPositionForInlineStrategyError(position, file) {
|
|
102
103
|
return (0, shared_1.newWebpackErrorForFile)(`The position value for the inlined asset was invalid. Received: ${position}, Expected: undefined|'before'|'after'`, file);
|
|
103
104
|
}
|
|
104
|
-
function
|
|
105
|
-
const baseArgs = unpackRegisterScriptArgsFromPathQueryParameters(typeof registerScriptArgs === 'object' ? registerScriptArgs : { strategy: registerScriptArgs }, file, 'registerScriptArgs');
|
|
106
|
-
const pathQueryArgs = unpackRegisterScriptArgsFromPathQueryParameters(pathQueryParameters, file, 'path query parameters');
|
|
105
|
+
function mergeTwoScriptEnqueuingControlFlagSets(file, baseArgs, ancestorArgs) {
|
|
107
106
|
if (baseArgs === undefined) {
|
|
108
|
-
return
|
|
107
|
+
return ancestorArgs;
|
|
109
108
|
}
|
|
110
|
-
if (
|
|
109
|
+
if (ancestorArgs === undefined) {
|
|
111
110
|
return baseArgs;
|
|
112
111
|
}
|
|
112
|
+
// This must be kept in sync with NormalizedScriptEnqueuingControlFlags
|
|
113
113
|
for (const key of ['strategy', 'in_footer', 'fetchpriority', 'inline', 'position']) {
|
|
114
114
|
if (key in baseArgs) {
|
|
115
|
-
if (key in
|
|
115
|
+
if (key in ancestorArgs && ancestorArgs[key] !== baseArgs[key]) {
|
|
116
116
|
throw (0, shared_1.newWebpackErrorForFile)(`The ${key} values in the registerScriptArgs and the pathQueryParameters for the file conflict`, file);
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
else if (key in
|
|
120
|
-
baseArgs[key] =
|
|
119
|
+
else if (key in ancestorArgs) {
|
|
120
|
+
baseArgs[key] = ancestorArgs[key];
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
return baseArgs;
|
|
124
124
|
}
|
|
125
|
-
function
|
|
125
|
+
function unpackEnqueuingControlFlagsFromPathQueryParameters(pathQueryParameters, file, sourceType) {
|
|
126
126
|
if (pathQueryParameters === undefined) {
|
|
127
|
-
return
|
|
127
|
+
return {};
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
let
|
|
131
|
-
const strategy = pathQueryParameters['strategy'];
|
|
129
|
+
const { strategy, in_footer: normalizedInFooter, 'in-footer': alternateInFooter, fetchpriority, position, ...remainder } = pathQueryParameters;
|
|
130
|
+
let flags;
|
|
132
131
|
switch (strategy) {
|
|
132
|
+
case 'defer':
|
|
133
|
+
case 'async':
|
|
134
|
+
flags = { strategy };
|
|
135
|
+
break;
|
|
133
136
|
case 'eager':
|
|
134
|
-
|
|
135
|
-
baseArgs = { strategy: 'eager' };
|
|
137
|
+
flags = { strategy: 'eager' };
|
|
136
138
|
break;
|
|
137
139
|
case 'lazy':
|
|
138
|
-
|
|
139
|
-
baseArgs = { strategy: 'defer', in_footer: true };
|
|
140
|
+
flags = { strategy: 'defer', in_footer: true };
|
|
140
141
|
break;
|
|
141
142
|
case 'inline':
|
|
142
|
-
|
|
143
|
-
baseArgs = { inline: true };
|
|
143
|
+
flags = { inline: true };
|
|
144
144
|
break;
|
|
145
145
|
case true:
|
|
146
146
|
case false:
|
|
147
|
-
|
|
148
|
-
baseArgs = { in_footer: strategy };
|
|
147
|
+
flags = { in_footer: strategy };
|
|
149
148
|
break;
|
|
150
149
|
case null:
|
|
151
150
|
case undefined:
|
|
152
|
-
|
|
151
|
+
flags = {};
|
|
153
152
|
break;
|
|
154
153
|
default:
|
|
155
154
|
throw newInvalidLoadingStrategyError(strategy, file);
|
|
156
155
|
}
|
|
157
|
-
if (
|
|
158
|
-
|
|
156
|
+
if (flags.inline === undefined && pathQueryParameters['inline'] !== undefined) {
|
|
157
|
+
flags.inline = !!pathQueryParameters['inline'];
|
|
159
158
|
}
|
|
160
|
-
const in_footer =
|
|
159
|
+
const in_footer = normalizedInFooter ?? alternateInFooter;
|
|
161
160
|
if (in_footer !== undefined) {
|
|
162
161
|
if (!isValidInFooter(in_footer)) {
|
|
163
162
|
throw newInvalidInFooterError(in_footer, file);
|
|
164
163
|
}
|
|
165
|
-
|
|
166
|
-
baseArgs.in_footer = in_footer;
|
|
164
|
+
flags.in_footer = in_footer;
|
|
167
165
|
}
|
|
168
166
|
if (pathQueryParameters['fetchpriority'] !== undefined) {
|
|
169
167
|
if (!isValidFetchPriority(pathQueryParameters['fetchpriority'])) {
|
|
170
168
|
throw newInvalidFetchPriorityError(pathQueryParameters['fetchpriority'], file);
|
|
171
169
|
}
|
|
172
|
-
if (
|
|
170
|
+
if (flags.fetchpriority !== undefined && flags.fetchpriority !== pathQueryParameters['fetchpriority']) {
|
|
173
171
|
throw (0, shared_1.newWebpackErrorForFile)(`The strategy and fetchpriority values in the ${sourceType} for the file conflict. Got ${strategy} and ${pathQueryParameters['fetchpriority']}`, file);
|
|
174
172
|
}
|
|
175
|
-
|
|
176
|
-
baseArgs.fetchpriority = pathQueryParameters['fetchpriority'];
|
|
173
|
+
flags.fetchpriority = pathQueryParameters['fetchpriority'];
|
|
177
174
|
}
|
|
178
|
-
if (pathQueryParameters['
|
|
175
|
+
if (flags.inline && (pathQueryParameters['position'] === 'before' || pathQueryParameters['position'] === 'after')) {
|
|
176
|
+
flags.position = pathQueryParameters['position'];
|
|
179
177
|
}
|
|
180
|
-
return
|
|
178
|
+
return Object.keys(flags).length > 0 ? { flags, remainder } : { remainder };
|
|
181
179
|
}
|
|
182
180
|
/**
|
|
183
181
|
* This function does a few things:
|
|
184
182
|
* <ol>
|
|
185
|
-
* <li>It
|
|
186
|
-
* <li>If
|
|
183
|
+
* <li>It converts the strategy, in_footer, and fetchpriority flags into a valid script args object</li>
|
|
184
|
+
* <li>If inline is true, it records the contents of the asset and the value of the position flag for later injection and removes the asset from the compilation output</li>
|
|
187
185
|
* </ol>
|
|
188
186
|
* @param compilation
|
|
189
187
|
* @param file
|
|
190
|
-
* @param
|
|
188
|
+
* @param flags
|
|
191
189
|
*/
|
|
192
|
-
function
|
|
193
|
-
if (
|
|
190
|
+
function convertEnqueuingControlFlagsToScriptArgsObject(compilation, file, flags) {
|
|
191
|
+
if (flags === undefined) {
|
|
194
192
|
return {};
|
|
195
193
|
}
|
|
194
|
+
const { strategy, in_footer, inline, position, fetchpriority } = flags;
|
|
196
195
|
const scriptArgsObject = {};
|
|
197
196
|
let inlinedAsset = undefined;
|
|
198
|
-
let hasAnyKeys = false;
|
|
199
|
-
const strategy = pathQueryParameters['strategy'];
|
|
200
197
|
switch (strategy) {
|
|
201
198
|
case 'async':
|
|
202
199
|
case 'defer':
|
|
203
|
-
hasAnyKeys = true;
|
|
204
200
|
scriptArgsObject.strategy = strategy;
|
|
205
201
|
break;
|
|
206
202
|
case 'eager':
|
|
207
|
-
hasAnyKeys = true;
|
|
208
203
|
scriptArgsObject.in_footer = false;
|
|
209
204
|
break;
|
|
210
205
|
case 'lazy':
|
|
211
|
-
hasAnyKeys = true;
|
|
212
206
|
scriptArgsObject.strategy = 'defer';
|
|
213
207
|
scriptArgsObject.in_footer = true;
|
|
214
208
|
break;
|
|
215
|
-
case 'inline':
|
|
216
|
-
inlinedAsset = { contents: getAssetFileContents(compilation, file) };
|
|
217
|
-
removeFileAndAssetPHP(compilation, file);
|
|
218
|
-
if ('inline' in pathQueryParameters) {
|
|
219
|
-
compilation.warnings.push((0, shared_1.newWebpackErrorForFile)("The inline parameter should not be set when setting strategy to 'inline'", file));
|
|
220
|
-
}
|
|
221
|
-
break;
|
|
222
209
|
case true:
|
|
223
210
|
case false:
|
|
224
|
-
hasAnyKeys = true;
|
|
225
211
|
scriptArgsObject.in_footer = strategy;
|
|
226
212
|
break;
|
|
227
213
|
case null:
|
|
@@ -231,34 +217,28 @@ function parseScriptArgsObjectFromPathQueryParameters(compilation, file, pathQue
|
|
|
231
217
|
default:
|
|
232
218
|
throw newInvalidLoadingStrategyError(strategy, file);
|
|
233
219
|
}
|
|
234
|
-
const in_footer = pathQueryParameters['in_footer'] ?? pathQueryParameters['in-footer'];
|
|
235
220
|
if (in_footer !== undefined) {
|
|
236
221
|
if (!isValidInFooter(in_footer)) {
|
|
237
222
|
throw newInvalidInFooterError(in_footer, file);
|
|
238
223
|
}
|
|
239
|
-
hasAnyKeys = true;
|
|
240
224
|
scriptArgsObject.in_footer = in_footer;
|
|
241
225
|
}
|
|
242
|
-
if (
|
|
226
|
+
if (inline) {
|
|
243
227
|
inlinedAsset = { contents: getAssetFileContents(compilation, file) };
|
|
244
228
|
removeFileAndAssetPHP(compilation, file);
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (!isValidPositionForInlineStrategy(pathQueryParameters['position'])) {
|
|
249
|
-
throw newInvalidPositionForInlineStrategyError(pathQueryParameters['position'], file);
|
|
229
|
+
if (position !== undefined) {
|
|
230
|
+
if (!isValidPositionForInlineStrategy(position)) {
|
|
231
|
+
throw newInvalidPositionForInlineStrategyError(position, file);
|
|
250
232
|
}
|
|
251
|
-
inlinedAsset.position =
|
|
233
|
+
inlinedAsset.position = position;
|
|
252
234
|
}
|
|
253
235
|
if (inlinedAsset.position !== 'before' && scriptArgsObject.strategy !== undefined) {
|
|
254
236
|
compilation.warnings.push((0, shared_1.newWebpackErrorForFile)("Deferred and async scripts that have inlined JS attached in the 'after' position will cause WordPress to convert all of their dependencies to eager scripts at runtime", file));
|
|
255
237
|
}
|
|
256
238
|
if (scriptArgsObject.in_footer === undefined) {
|
|
257
|
-
hasAnyKeys = true;
|
|
258
239
|
scriptArgsObject.in_footer = true;
|
|
259
240
|
}
|
|
260
241
|
}
|
|
261
|
-
const fetchpriority = pathQueryParameters['fetchpriority'];
|
|
262
242
|
if (fetchpriority !== undefined) {
|
|
263
243
|
if (!isValidFetchPriority(fetchpriority)) {
|
|
264
244
|
throw newInvalidFetchPriorityError(fetchpriority, file);
|
|
@@ -266,10 +246,9 @@ function parseScriptArgsObjectFromPathQueryParameters(compilation, file, pathQue
|
|
|
266
246
|
if (inlinedAsset !== undefined) {
|
|
267
247
|
compilation.warnings.push((0, shared_1.newWebpackErrorForFile)("Fetchpriority has no effect on inlined assets", file));
|
|
268
248
|
}
|
|
269
|
-
hasAnyKeys = true;
|
|
270
249
|
scriptArgsObject.fetchpriority = fetchpriority;
|
|
271
250
|
}
|
|
272
|
-
return
|
|
251
|
+
return Object.keys(scriptArgsObject).length > 0 ? { scriptArgsObject, inlinedAsset } : { inlinedAsset };
|
|
273
252
|
}
|
|
274
253
|
function removeFileAndAssetPHP(compilation, file) {
|
|
275
254
|
const pathParts = (0, node_path_1.parse)(file);
|
|
@@ -7,6 +7,8 @@ const promises_1 = require("node:fs/promises");
|
|
|
7
7
|
const node_path_1 = require("node:path");
|
|
8
8
|
const shared_1 = require("./shared");
|
|
9
9
|
const common_config_helpers_1 = require("./utils/common-config-helpers");
|
|
10
|
+
const location_encoding_filename_parser_1 = require("./utils/location-encoding-filename-parser");
|
|
11
|
+
const path_query_and_related_helpers_1 = require("./utils/path-query-and-related-helpers");
|
|
10
12
|
const AdditionalDependencyInjectorPlugin_1 = require("./plugins/AdditionalDependencyInjectorPlugin");
|
|
11
13
|
const BrowserSyncPlugin_1 = require("./plugins/BrowserSyncPlugin");
|
|
12
14
|
const dependency_extraction_webpack_plugin_config_builder_1 = require("./plugins/dependency-extraction-webpack-plugin-config-builder");
|
|
@@ -25,7 +27,6 @@ const UnifiedLoaderGenerator_1 = require("./plugins/UnifiedLoaderGenerator");
|
|
|
25
27
|
const copy_webpack_plugin_1 = __importDefault(require("copy-webpack-plugin"));
|
|
26
28
|
const fork_ts_checker_webpack_plugin_1 = __importDefault(require("fork-ts-checker-webpack-plugin"));
|
|
27
29
|
const webpack_remove_empty_scripts_1 = __importDefault(require("webpack-remove-empty-scripts"));
|
|
28
|
-
const path_query_and_related_helpers_1 = require("./utils/path-query-and-related-helpers");
|
|
29
30
|
function testForDuplicatedEntryPaths(sources) {
|
|
30
31
|
const seenPaths = (0, common_config_helpers_1.groupEntrypointsByAssetFile)(Array.isArray(sources)
|
|
31
32
|
? sources.map(s => typeof s === 'string' ? s : s[1].destination)
|
|
@@ -164,6 +165,7 @@ function injectSupportForInliningSVGsAsStrings(rules) {
|
|
|
164
165
|
});
|
|
165
166
|
}
|
|
166
167
|
function buildVerifiedConfig(config) {
|
|
168
|
+
config = applyStandards(config);
|
|
167
169
|
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 } = config;
|
|
168
170
|
let outputDir = config.outputDir ?? "";
|
|
169
171
|
if (outputDir && useUnifiedLoader && !omitDistDev && (process.env['SERVER_MODE'] ?? 'development') === 'development') {
|
|
@@ -200,12 +202,57 @@ function buildVerifiedConfig(config) {
|
|
|
200
202
|
}
|
|
201
203
|
return [src, { ...dest, pathQueryParameters }];
|
|
202
204
|
};
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
let rawSources;
|
|
206
|
+
if (Array.isArray(config.src)) {
|
|
207
|
+
rawSources = config.src.map(s => normalizeSrcAndDestination([s, { destination: s }]));
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
const configSrc = config.src ?? {};
|
|
211
|
+
// We check for files with location-encoding filenames and add the pertinent ones to the sources
|
|
212
|
+
const dynamicallyIncludedEntrypoints = [];
|
|
213
|
+
if (srcDir) { // This will only work if we have a unified src root
|
|
214
|
+
const dynamicallyIncludedEntrypointsRoot = (0, node_path_1.isAbsolute)(srcDir) ? srcDir : (0, node_path_1.join)(process.cwd(), srcDir);
|
|
215
|
+
using dir = (0, node_fs_1.opendirSync)(dynamicallyIncludedEntrypointsRoot);
|
|
216
|
+
for (let dirent; (dirent = dir.readSync()) !== null;) {
|
|
217
|
+
if (dirent.name in configSrc || `./${dirent.name}` in configSrc) {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (dirent.isDirectory()) {
|
|
221
|
+
// If it's a directory that does not have an existing config entry, but does correspond to one of the non-plain SourceTypes, assume that it matches that source type
|
|
222
|
+
if ((0, shared_1.isSourceType)(dirent.name) && dirent.name !== "plain" /* SourceType.plain */) {
|
|
223
|
+
dynamicallyIncludedEntrypoints.push([dirent.name, { directoryLayout: dirent.name }]);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
using nestedDir = (0, node_fs_1.opendirSync)((0, node_path_1.join)(dynamicallyIncludedEntrypointsRoot, dirent.name));
|
|
227
|
+
for (let nestedDirent; (nestedDirent = nestedDir.readSync()) !== null;) {
|
|
228
|
+
if (!nestedDirent.isFile()) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
const cfgName = (0, node_path_1.join)(dirent.name, nestedDirent.name);
|
|
232
|
+
if (cfgName in configSrc || `./${cfgName}` in configSrc) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const parsedFilename = (0, location_encoding_filename_parser_1.parseLocationEncodingFilename)(cfgName);
|
|
236
|
+
if (parsedFilename === undefined) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
dynamicallyIncludedEntrypoints.push([cfgName, { locations: parsedFilename.locations, enqueuingFlags: parsedFilename.flags }]);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else if (dirent.isFile()) {
|
|
243
|
+
const parsedFilename = (0, location_encoding_filename_parser_1.parseLocationEncodingFilename)(dirent.name);
|
|
244
|
+
if (parsedFilename === undefined) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
dynamicallyIncludedEntrypoints.push([dirent.name, { locations: parsedFilename.locations, enqueuingFlags: parsedFilename.flags }]);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
rawSources = [...Object.entries(configSrc), ...dynamicallyIncludedEntrypoints]
|
|
206
252
|
.map(([k, v]) => {
|
|
207
253
|
return normalizeSrcAndDestination([k, typeof v === 'boolean' ? {} : (typeof v === 'string' ? { destination: v } : v)]);
|
|
208
254
|
});
|
|
255
|
+
}
|
|
209
256
|
let variablesFilePath = undefined;
|
|
210
257
|
const currentVariables = rawVariables ?? {};
|
|
211
258
|
if (!rawVariables) {
|
|
@@ -223,7 +270,9 @@ function buildVerifiedConfig(config) {
|
|
|
223
270
|
// Destination -> source map
|
|
224
271
|
const allocatedDestinations = {};
|
|
225
272
|
const partiallyVerifiedSources = rawSources.map(rawSource => {
|
|
226
|
-
const { destination, additionalDependencies = [], assumeGlobalizedPlauditLibraries = cfg.assumeGlobalizedPlauditLibraries, bundleAnalyzer = false, directoryLayout, externalize, withLegacyBlocksIn = false, lazyLoader, pathQueryParameters } = rawSource[1];
|
|
273
|
+
const { destination, additionalDependencies = [], assumeGlobalizedPlauditLibraries = cfg.assumeGlobalizedPlauditLibraries, bundleAnalyzer = false, directoryLayout, externalize, withLegacyBlocksIn = false, lazyLoader, pathQueryParameters: rawPathQueryParameters, enqueuingFlags: rawEnqueuingFlags } = rawSource[1];
|
|
274
|
+
const { flags: queryEnqueuingFlags, remainder: pathQueryParameters } = (0, path_query_and_related_helpers_1.unpackEnqueuingControlFlagsFromPathQueryParameters)(rawPathQueryParameters, rawSource[0], 'path query parameters');
|
|
275
|
+
const enqueuingFlags = (0, path_query_and_related_helpers_1.mergeTwoScriptEnqueuingControlFlagSets)(rawSource[0], rawEnqueuingFlags, queryEnqueuingFlags);
|
|
227
276
|
const normalizedParts = { additionalDependencies, assumeGlobalizedPlauditLibraries, bundleAnalyzer, directoryLayout, externalize, withLegacyBlocksIn, lazyLoader };
|
|
228
277
|
const locations = typeof rawSource[1].locations === 'string' || typeof rawSource[1].locations === 'function'
|
|
229
278
|
? { handle: rawSource[1].locations } : rawSource[1].locations ?? {};
|
|
@@ -233,12 +282,12 @@ function buildVerifiedConfig(config) {
|
|
|
233
282
|
if (destination !== undefined) {
|
|
234
283
|
const effectiveDestination = toEffectiveWebpackDestination(destination);
|
|
235
284
|
allocatedDestinations[effectiveDestination] = rawSource[0]; // We need to pre-populate the allocatedDestinations map with statically declared destinations
|
|
236
|
-
return [rawSource[0], { ...normalizedParts, locations, destination, effectiveDestination, staticallyDeclaredDestination: true, pathQueryParameters }];
|
|
285
|
+
return [rawSource[0], { ...normalizedParts, locations, destination, effectiveDestination, staticallyDeclaredDestination: true, pathQueryParameters, enqueuingFlags }];
|
|
237
286
|
}
|
|
238
287
|
else {
|
|
239
288
|
const naiveDestination = deriveNaiveDestinationFromUnverifiedSourceEntry(rawSource, srcPrefixes);
|
|
240
289
|
const effectiveDestination = toEffectiveWebpackDestination(naiveDestination);
|
|
241
|
-
return [rawSource[0], { ...normalizedParts, locations, destination: naiveDestination, effectiveDestination, staticallyDeclaredDestination: false, pathQueryParameters }];
|
|
290
|
+
return [rawSource[0], { ...normalizedParts, locations, destination: naiveDestination, effectiveDestination, staticallyDeclaredDestination: false, pathQueryParameters, enqueuingFlags }];
|
|
242
291
|
}
|
|
243
292
|
});
|
|
244
293
|
const dynamicEffectiveDestinationsWithExpectedNaiveDuplicates = partiallyVerifiedSources
|
|
@@ -253,6 +302,25 @@ function buildVerifiedConfig(config) {
|
|
|
253
302
|
testForDuplicatedEntryPaths(sources);
|
|
254
303
|
return cfg.outputDir ? { cfg, sources } : withDerivedOutputDir(cfg, sources);
|
|
255
304
|
}
|
|
305
|
+
function applyStandards(config) {
|
|
306
|
+
switch (config.standard) {
|
|
307
|
+
case '2026-03-13':
|
|
308
|
+
return {
|
|
309
|
+
useWebpackResourceFiltering: true,
|
|
310
|
+
extensionsVersion: 3,
|
|
311
|
+
plainEntrypointsVersion: 2,
|
|
312
|
+
srcDir: "src",
|
|
313
|
+
outputDir: "dist",
|
|
314
|
+
useUnifiedLoader: true,
|
|
315
|
+
onlyRunPostCSSOnPCSS: true,
|
|
316
|
+
...config
|
|
317
|
+
};
|
|
318
|
+
case undefined:
|
|
319
|
+
return config;
|
|
320
|
+
default:
|
|
321
|
+
throw `Invalid standard: ${config.standard}`;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
256
324
|
function toEffectiveWebpackDestination(destination) {
|
|
257
325
|
const pathParts = (0, node_path_1.parse)(destination);
|
|
258
326
|
return (0, node_path_1.join)(pathParts.dir, pathParts.name);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plaudit/webpack-extensions",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.86.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
5
5
|
"files": [
|
|
6
6
|
"/build",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@plaudit/gutenberg-api-extensions": "^2.87.0",
|
|
28
28
|
"@types/browser-sync-webpack-plugin": "^2.2.5",
|
|
29
|
-
"@types/node": "^25.
|
|
29
|
+
"@types/node": "^25.5.0",
|
|
30
30
|
"@types/postcss-functions": "^4.0.4",
|
|
31
31
|
"@types/tapable": "^2.3.0",
|
|
32
32
|
"@types/webpack-sources": "^3.2.3",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"postcss-url": "^10.1.3",
|
|
66
66
|
"webpack": "^5.105.4",
|
|
67
67
|
"webpack-remove-empty-scripts": "^1.1.1",
|
|
68
|
-
"xml-formatter": "^3.
|
|
68
|
+
"xml-formatter": "^3.7.0"
|
|
69
69
|
},
|
|
70
70
|
"engines": {
|
|
71
71
|
"node": ">=20"
|