@plaudit/webpack-extensions 2.84.0 → 2.85.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.
@@ -1,12 +1,14 @@
1
1
  import { AbstractBiPhasicGroupAndEntryPlugin, EntryProvider } from "./AbstractBiPhasicGroupAndEntryPlugin";
2
- import { ParsedAssetsJson, BlockEntrypointInfo, FileSegmentBlockEntrypointInfo, VerifiedAdvancedOutputConfig, ParsedAssetJsonProvider } from "../shared";
2
+ import { ParsedAssetsJson, BlockEntrypointInfo, FileSegmentBlockEntrypointInfo, VerifiedAdvancedOutputConfig, ParsedAssetJsonProvider, ScriptArgsObject, InlinedAsset } from "../shared";
3
3
  import type { VerifiedPlauditWordpressWebpackConfig } from "../utils/common-config-helpers";
4
4
  import { Compilation } from "webpack";
5
5
  import type WebpackRemoveEmptyScriptsPlugin from "webpack-remove-empty-scripts";
6
- type WorkableBlockEntrypointInfo = Omit<FileSegmentBlockEntrypointInfo, 'originalValue'> & Partial<Pick<FileSegmentBlockEntrypointInfo, 'originalValue'>> & {
6
+ type WorkableBlockEntrypointInfo = Omit<FileSegmentBlockEntrypointInfo, 'originalValue' | 'pathQueryParameters'> & Partial<Pick<FileSegmentBlockEntrypointInfo, 'originalValue'>> & {
7
7
  outputPath: string;
8
8
  assetData: ParsedAssetsJson[string];
9
9
  hash: string;
10
+ scriptArgsObject: ScriptArgsObject | undefined;
11
+ inlinedAsset: InlinedAsset | undefined;
10
12
  };
11
13
  type CollatedWorkableBlockInfo = Record<string, {
12
14
  sourcePath?: string;
@@ -13,6 +13,7 @@ const UnifiedLoaderGenerator_1 = require("./UnifiedLoaderGenerator");
13
13
  const php_writer_1 = require("@plaudit/php-writer");
14
14
  const expressions_1 = require("@plaudit/php-writer/expressions");
15
15
  const shared_1 = require("../shared");
16
+ const path_query_and_related_helpers_1 = require("../utils/path-query-and-related-helpers");
16
17
  const pseduo_semaphore_1 = require("../utils/pseduo-semaphore");
17
18
  const webpack_1 = require("webpack");
18
19
  class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.AbstractBiPhasicGroupAndEntryPlugin {
@@ -34,7 +35,6 @@ class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.Abst
34
35
  }
35
36
  const asset = [...compilation.chunkGraph.getChunkEntryModulesIterable(entrypoint.getEntrypointChunk())][0]?.originalSource();
36
37
  if (asset) {
37
- //TODO: Can we guarantee that entrypoint.name is always non-null?
38
38
  const epBlockJson = entrypoint.name + ".json";
39
39
  if (!applicableBlockJsonFiles[epBlockJson]) {
40
40
  const blockJsonText = EnhancedBlockJSONPlugin.extractAssetSource(compilation, epBlockJson)
@@ -62,20 +62,24 @@ class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.Abst
62
62
  continue;
63
63
  }
64
64
  const workableBlockEntrypointsInfo = entrypoint.getFiles()
65
- .map(file => this.stripOffBlocksDestPrefix(file))
66
- .filter(file => !this.webpackRemoveEmptyScriptsPlugin['trash'].includes(node_path_1.default.join(this.dest.destination, file)))
65
+ .filter(file => !this.webpackRemoveEmptyScriptsPlugin['trash'].includes(file))
67
66
  .map(file => [file, (0, shared_1.scriptOrStyleTest)(file, shared_1.scriptExtension)])
68
67
  .filter((item) => item[1] !== '')
69
68
  .map(([file, assetType]) => {
69
+ const pathQueryParameters = metadata.pathQueryParameters !== undefined || this.dest.pathQueryParameters !== undefined
70
+ ? { ...metadata.pathQueryParameters, ...this.dest.pathQueryParameters }
71
+ : undefined;
72
+ const { scriptArgsObject, inlinedAsset } = (0, path_query_and_related_helpers_1.parseScriptArgsObjectFromPathQueryParameters)(compilation, file, pathQueryParameters);
70
73
  const wasOriginallyAStyleField = (0, shared_1.isStyleField)(metadata.entrypointField);
74
+ const outputPath = this.stripOffBlocksDestPrefix(file);
71
75
  if (wasOriginallyAStyleField !== (assetType === "style")) { // This means that the file is extracted
72
76
  const entrypointField = (0, shared_1.convertEntrypointFieldForAssetType)(metadata.entrypointField, assetType);
73
77
  return {
74
- ...metadata, outputPath: file, assetData, originalValue: undefined, hash: entrypointChunk.hash ?? "",
75
- entrypointField, handleGroup: (0, shared_1.getHandleGroup)(entrypointField)
78
+ ...metadata, outputPath, assetData, originalValue: undefined, hash: entrypointChunk.hash ?? "",
79
+ entrypointField, handleGroup: (0, shared_1.getHandleGroup)(entrypointField), scriptArgsObject, inlinedAsset
76
80
  };
77
81
  }
78
- return ({ ...metadata, outputPath: file, assetData, hash: entrypointChunk.hash ?? "" });
82
+ return { ...metadata, outputPath, assetData, hash: entrypointChunk.hash ?? "", scriptArgsObject, inlinedAsset };
79
83
  });
80
84
  if (applicableBlockJsonFiles[epBlockJson]) {
81
85
  applicableBlockJsonFiles[epBlockJson].workableBlockEntrypointsInfo.push(...workableBlockEntrypointsInfo);
@@ -114,18 +118,54 @@ class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.Abst
114
118
  action
115
119
  } : undefined);
116
120
  }
117
- emitBlockLoaderFile(compilation, blockData) {
121
+ emitBlockLoaderFile(compilation, blockDirConfig) {
118
122
  if (this.config.useUnifiedLoader) {
119
- const metadata = blockData['__metadata'];
120
- delete blockData['__metadata'];
121
- (0, shared_1.emitPHPWriterAsAsset)(new php_writer_1.PHPWriter()
123
+ const { '__metadata': metadata, ...blockData } = blockDirConfig;
124
+ const splitOutInlinedAssets = (handles, type) => {
125
+ const registerableHandles = {};
126
+ const inlinedAssets = [];
127
+ for (const [handle, handleData] of Object.entries(handles)) {
128
+ const { inlinedAsset, ...finalizedHandle } = handleData;
129
+ if (inlinedAsset !== undefined) {
130
+ finalizedHandle.src = false;
131
+ inlinedAssets.push([handle, type, inlinedAsset, handleData, handleData.src]);
132
+ }
133
+ registerableHandles[handle] = finalizedHandle;
134
+ }
135
+ return [registerableHandles, inlinedAssets];
136
+ };
137
+ const [finalizedScriptHandles, inlinableScripts] = splitOutInlinedAssets(metadata.scriptHandles, 'script');
138
+ const [finalizedStyleHandles, inlinableStyles] = splitOutInlinedAssets(metadata.styleHandles, 'style');
139
+ const finalizedMetadata = Object.fromEntries(Object.entries(metadata)
140
+ .map(([key, value]) => {
141
+ if (key === 'scriptHandles') {
142
+ return [key, finalizedScriptHandles];
143
+ }
144
+ if (key === 'styleHandles') {
145
+ return [key, finalizedStyleHandles];
146
+ }
147
+ return [key, value];
148
+ }));
149
+ const writer = new php_writer_1.PHPWriter()
122
150
  .action("init", writer => {
123
- writer.call("\\Plaudit\\Common\\ACF\\BlockManager::autoloadSubfoldersV3", [expressions_1.Constants.__DIR__, new expressions_1.EnclosedLiteral((0, shared_1.makeEmittableConfigPHP)(blockData, false, "\t")),
124
- expressions_1.Constants.__FILE__, new expressions_1.EnclosedLiteral((0, shared_1.makeEmittableConfigPHP)(metadata, false, "\t")), null]);
125
- }, { accountForAlreadyDoing: this.config.includePostInitFallback }), compilation, node_path_1.default.join(this.dest.destination, "blockdir-loader.php"));
151
+ writer.call("\\Plaudit\\Common\\ACF\\BlockManager::autoloadSubfoldersV3", [
152
+ expressions_1.Constants.__DIR__, // string $dir
153
+ new expressions_1.EnclosedLiteral((0, shared_1.makeEmittableConfigPHP)(blockData, false, "\t")), // array $blockdirConfig
154
+ expressions_1.Constants.__FILE__, // string $blockdirConfigFile
155
+ new expressions_1.EnclosedLiteral((0, shared_1.makeEmittableConfigPHP)(finalizedMetadata, false, "\t")), // array $metadata
156
+ null // ?string $urlPrefix
157
+ ]);
158
+ for (const inlinableScript of inlinableScripts) {
159
+ (0, shared_1.appendAddInlineAssetCall)(compilation, writer, ...inlinableScript);
160
+ }
161
+ for (const inlinableStyle of inlinableStyles) {
162
+ (0, shared_1.appendAddInlineAssetCall)(compilation, writer, ...inlinableStyle);
163
+ }
164
+ }, { accountForAlreadyDoing: this.config.includePostInitFallback });
165
+ (0, shared_1.emitPHPWriterAsAsset)(writer, compilation, node_path_1.default.join(this.dest.destination, "blockdir-loader.php"));
126
166
  }
127
167
  else {
128
- compilation.emitAsset(node_path_1.default.join(this.dest.destination, "blockdir.config.php"), new webpack_1.sources.RawSource((0, shared_1.makeEmittableConfigPHP)(blockData, true)));
168
+ compilation.emitAsset(node_path_1.default.join(this.dest.destination, "blockdir.config.php"), new webpack_1.sources.RawSource((0, shared_1.makeEmittableConfigPHP)(blockDirConfig, true)));
129
169
  }
130
170
  }
131
171
  transformBlocks(compilation, collatedWorkableBlockInfo, emittingWpmlXml) {
@@ -173,7 +213,7 @@ class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.Abst
173
213
  .convertToScriptHandles(handleData.filter(hd => !(0, shared_1.isStyleField)(hd.entrypointField) && (0, shared_1.isScriptModuleField)(hd.entrypointField)))),
174
214
  styleHandles: Object.fromEntries(handleData.filter(hd => (0, shared_1.isStyleField)(hd.entrypointField))
175
215
  .map(hd => {
176
- return [hd.handle, { src: hd.outputPath, rest: [hd.originalValue !== undefined ? hd.assetData.dependencies : [], hd.assetData.version] }];
216
+ return [hd.handle, { src: hd.outputPath, rest: [hd.originalValue !== undefined ? hd.assetData.dependencies : [], hd.assetData.version], inlinedAsset: hd.inlinedAsset }];
177
217
  }))
178
218
  },
179
219
  ...Object.fromEntries(Object.entries(blockData).sort((a, b) => a[0].localeCompare(b[0])))
@@ -186,7 +226,20 @@ class EnhancedBlockJSONPlugin extends AbstractBiPhasicGroupAndEntryPlugin_1.Abst
186
226
  static convertToScriptHandles(handleData) {
187
227
  return handleData.map(hd => {
188
228
  const deps = hd.originalValue !== undefined ? hd.assetData.dependencies : [];
189
- return [hd.handle, { src: hd.outputPath, rest: hd.entrypointField.startsWith("editor") ? [deps, hd.assetData.version] : [deps, hd.assetData.version, { strategy: "defer" }] }];
229
+ let scriptArgsObject;
230
+ if (hd.scriptArgsObject !== undefined) {
231
+ scriptArgsObject = hd.scriptArgsObject;
232
+ }
233
+ else if (hd.inlinedAsset !== undefined) {
234
+ scriptArgsObject = hd.inlinedAsset.position === 'before' ? { strategy: "defer" } : undefined;
235
+ }
236
+ else if (!hd.entrypointField.startsWith("editor")) {
237
+ scriptArgsObject = { strategy: "defer" };
238
+ }
239
+ else {
240
+ scriptArgsObject = undefined;
241
+ }
242
+ return [hd.handle, { src: hd.outputPath, rest: scriptArgsObject !== undefined ? [deps, hd.assetData.version, scriptArgsObject] : [deps, hd.assetData.version], inlinedAsset: hd.inlinedAsset }];
190
243
  });
191
244
  }
192
245
  static doFileOrHandleReplacements(compilation, blockJson, workableBlockEntrypointsInfo, getter) {
@@ -1,5 +1,5 @@
1
1
  import { AbstractBiPhasicGroupAndEntryPlugin, EntryProvider } from "./AbstractBiPhasicGroupAndEntryPlugin";
2
- import { ParsedAssetJsonProvider } from "../shared";
2
+ import type { ParsedAssetJsonProvider } from "../shared";
3
3
  import type { VerifiedPlauditWordpressWebpackConfig } from "../utils/common-config-helpers";
4
4
  import { Compilation } from "webpack";
5
5
  export declare class ExtensionsConfigFileGeneratorPluginV1 extends AbstractBiPhasicGroupAndEntryPlugin {
@@ -1,4 +1,5 @@
1
- import type { Compiler, WebpackPluginInstance } from "webpack";
2
- export declare class MiniCSSExtractPluginErrorCleaner implements WebpackPluginInstance {
1
+ import type { Compiler } from "webpack";
2
+ import type { WebpackPlugin } from "../shared";
3
+ export declare class MiniCSSExtractPluginErrorCleaner implements WebpackPlugin {
3
4
  apply(compiler: Compiler): void;
4
5
  }
@@ -1,4 +1,5 @@
1
- import type { Compiler, WebpackPluginInstance } from "webpack";
2
- export declare class PackageConfigSanityChecker implements WebpackPluginInstance {
1
+ import type { Compiler } from "webpack";
2
+ import type { WebpackPlugin } from "../shared";
3
+ export declare class PackageConfigSanityChecker implements WebpackPlugin {
3
4
  apply(compiler: Compiler): void;
4
5
  }
@@ -9,6 +9,7 @@ const php_writer_1 = require("@plaudit/php-writer");
9
9
  const expressions_1 = require("@plaudit/php-writer/expressions");
10
10
  const shared_1 = require("../shared");
11
11
  const pseduo_semaphore_1 = require("../utils/pseduo-semaphore");
12
+ const path_query_and_related_helpers_1 = require("../utils/path-query-and-related-helpers");
12
13
  const AbstractBiPhasicGroupAndEntryPlugin_1 = require("./AbstractBiPhasicGroupAndEntryPlugin");
13
14
  const UnifiedLoaderGenerator_1 = require("./UnifiedLoaderGenerator");
14
15
  const webpack_1 = require("webpack");
@@ -29,6 +30,7 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
29
30
  const emitDir = node_path_1.default.join(this.buildRoot, this.outputDir);
30
31
  const handleLists = {
31
32
  register: [],
33
+ inline: [],
32
34
  ...Object.fromEntries((0, shared_1.constantKeys)(shared_1.standardLocationNamesMeta).map(sln => [sln, []]))
33
35
  };
34
36
  const allNamedHandles = assets
@@ -41,7 +43,7 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
41
43
  .map(handle => [handle.handleName, handle.src]))]));
42
44
  const plainEntrypointsConfig = { scriptHandles: {}, script_moduleHandles: {}, styleHandles: {} };
43
45
  for (const { handles, handlePrefix } of assets) {
44
- for (const { src, rest, locations, type, handleName, lazyLoader } of handles) {
46
+ for (const { src, rest, locations, type, handleName, lazyLoader, ...otherProps } of handles) {
45
47
  const basename = node_path_1.default.basename(src).replace(/_(?:script(?:-\d+)?\.js|style(?:-\d+)?\.css)$|(?<!_(script|style))\.(js|css)$/, "");
46
48
  let finalHandleName;
47
49
  if (typeof handleName === 'string') {
@@ -55,7 +57,7 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
55
57
  }
56
58
  handleNameMap[finalHandleName] = src;
57
59
  }
58
- plainEntrypointsConfig[`${type}Handles`][finalHandleName] = { src, rest, locations, type, lazyLoader };
60
+ plainEntrypointsConfig[`${type}Handles`][finalHandleName] = { src, rest, locations, type, lazyLoader, ...otherProps };
59
61
  }
60
62
  }
61
63
  PlainEntrypointsConfigFileGeneratorPlugin.addHandlesToHandleLists('script', Object.entries(plainEntrypointsConfig.scriptHandles)
@@ -79,7 +81,26 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
79
81
  writer.action("init", writer => {
80
82
  writer.call("plaudit_webpack_extensions__resolve_base_uri", [expressions_1.Constants.__DIR__], { assignTo: baseUriVar });
81
83
  for (const { handle, type, data } of prioritizedHandleList) {
82
- writer.call(`wp_register_${type}`, [handle, expressions_1.Op.concat(baseUriVar, node_path_1.default.relative(emitDir, data.src)), ...data.rest]);
84
+ const { inlinedAsset, rest, src } = data;
85
+ const emittedSrc = inlinedAsset === undefined
86
+ ? expressions_1.Op.concat(baseUriVar, node_path_1.default.relative(emitDir, src))
87
+ : false;
88
+ writer.call(`wp_register_${type}`, [handle, emittedSrc, ...rest]);
89
+ if (inlinedAsset !== undefined) {
90
+ (0, shared_1.appendAddInlineAssetCall)(compilation, writer, handle, type, inlinedAsset, data, src);
91
+ }
92
+ }
93
+ }, { priority, accountForAlreadyDoing: this.config.includePostInitFallback });
94
+ }
95
+ for (const [priority, prioritizedHandleList] of PlainEntrypointsConfigFileGeneratorPlugin.separateHandleListByPriority(handleLists.inline)) {
96
+ writer.action("init", writer => {
97
+ writer.call("plaudit_webpack_extensions__resolve_base_uri", [expressions_1.Constants.__DIR__], { assignTo: baseUriVar });
98
+ for (const { handle, type, data } of prioritizedHandleList) {
99
+ const { inlinedAsset, rest, src } = data;
100
+ writer.call(`wp_register_${type}`, [handle, false, ...rest]);
101
+ if (inlinedAsset !== undefined) {
102
+ (0, shared_1.appendAddInlineAssetCall)(compilation, writer, handle, type, inlinedAsset, data, src);
103
+ }
83
104
  }
84
105
  }, { priority, accountForAlreadyDoing: this.config.includePostInitFallback });
85
106
  }
@@ -127,6 +148,9 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
127
148
  if (data.locations.register !== false) {
128
149
  handleLists.register.push({ handle, type, data, priority: typeof data.locations.register === 'number' ? data.locations.register : 10 });
129
150
  }
151
+ else if (data.inlinedAsset !== undefined) {
152
+ handleLists.inline.push({ handle, type, data, priority: typeof data.locations.inline === 'number' ? data.locations.inline : 10 });
153
+ }
130
154
  for (const location of (0, shared_1.constantKeys)(shared_1.standardLocationNamesMeta)) {
131
155
  let priority, hook_name;
132
156
  const dataLocation = data.locations[location];
@@ -277,14 +301,18 @@ class PlainEntrypointsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAnd
277
301
  const type = extension === ".js" ? 'script' : (extension === ".mjs" ? 'script_module' : 'style');
278
302
  const isScript = type !== 'style';
279
303
  const dependencies = isScript === entrypointChunkIsScript ? assetData.dependencies : [];
280
- const { registerScriptArgs } = this.dest.locations;
281
- const rest = isScript && registerScriptArgs !== undefined ? [dependencies, assetData.version, registerScriptArgs] : [dependencies, assetData.version];
304
+ const { lazyLoader, locations } = this.dest;
305
+ const { inlinedAsset, scriptArgsObject } = (0, path_query_and_related_helpers_1.parseScriptArgsObjectFromPathQueryParameters)(compilation, file, (0, path_query_and_related_helpers_1.mergeInPathQueryParameters)(file, locations.registerScriptArgs, this.dest.pathQueryParameters));
306
+ const rest = isScript && scriptArgsObject !== undefined ? [dependencies, assetData.version, scriptArgsObject] : [dependencies, assetData.version];
282
307
  const destPath = node_path_1.default.join(compilation.outputOptions.path, file);
283
308
  handles.push({
284
- src: destPath, rest, type,
285
- locations: this.dest.locations,
286
- handleName: useHandleName ? this.dest.locations.handle : undefined,
287
- lazyLoader: this.dest.lazyLoader
309
+ src: destPath,
310
+ rest,
311
+ type,
312
+ locations,
313
+ handleName: useHandleName ? locations.handle : undefined,
314
+ lazyLoader,
315
+ inlinedAsset
288
316
  });
289
317
  }
290
318
  myAssetHandles.push({ handles, handlePrefix: this.config.targetHandlePrefix });
@@ -1,6 +1,7 @@
1
1
  import type { VerifiedPlauditWordpressWebpackConfig } from "../utils/common-config-helpers";
2
- import type { Compiler, WebpackPluginInstance } from "webpack";
3
- export declare class VariablesJSMonitorPlugin implements WebpackPluginInstance {
2
+ import type { Compiler } from "webpack";
3
+ import type { WebpackPlugin } from "../shared";
4
+ export declare class VariablesJSMonitorPlugin implements WebpackPlugin {
4
5
  private readonly config;
5
6
  constructor(config: VerifiedPlauditWordpressWebpackConfig);
6
7
  apply(compiler: Compiler): void;
@@ -1,6 +1,7 @@
1
+ import { type WebpackPlugin } from "../shared";
1
2
  import { AbstractBiPhasicGroupAndEntryPlugin } from "./AbstractBiPhasicGroupAndEntryPlugin";
2
- import { type Compiler, type WebpackPluginInstance } from "webpack";
3
- export declare class WPMLConfigBuilderPlugin implements WebpackPluginInstance {
3
+ import { type Compiler } from "webpack";
4
+ export declare class WPMLConfigBuilderPlugin implements WebpackPlugin {
4
5
  private readonly destDir;
5
6
  private readonly referencePlugin;
6
7
  private static jsdomInstance?;
package/build/shared.d.ts CHANGED
@@ -1,20 +1,25 @@
1
1
  import { PHPWriter } from "@plaudit/php-writer";
2
2
  import type { Options as PostcssFunctionsOptions } from "postcss-functions";
3
- import { AssetInfo, Compilation, type Configuration, Entrypoint, WebpackError } from "webpack";
3
+ import { AssetInfo, Compilation, Configuration, Entrypoint, WebpackError, Compiler } from "webpack";
4
4
  export type ParsedAssetsJson = Record<string, {
5
5
  dependencies: string[];
6
6
  version: string;
7
7
  }>;
8
8
  export declare function isParsedAssetsJson(thing: any): thing is ParsedAssetsJson;
9
- type ScriptArgsObject = {
9
+ export type ScriptArgsObject = {
10
10
  strategy?: 'defer' | 'async';
11
11
  in_footer?: boolean;
12
12
  fetchpriority?: 'auto' | 'low' | 'high';
13
13
  };
14
14
  type BaseRestType = [/* dependencies: */ string[], /* version: */ string];
15
+ export type InlinedAsset = {
16
+ contents: string;
17
+ position?: 'before' | 'after';
18
+ };
15
19
  export type HandleData = {
16
20
  src: string;
17
- rest: BaseRestType | [...BaseRestType, ScriptArgsObject | boolean];
21
+ rest: BaseRestType | [...BaseRestType, ScriptArgsObject];
22
+ inlinedAsset?: InlinedAsset;
18
23
  };
19
24
  export declare const standardLocationNamesMeta: {
20
25
  readonly clientView: {
@@ -53,17 +58,19 @@ type LocationWithHookNameSupport = boolean | number | string | string[] | {
53
58
  hook_name?: string | string[];
54
59
  priority?: number;
55
60
  };
61
+ type InputRegisterScriptArgs = ScriptArgsObject | boolean | 'lazy' | 'eager' | 'inline';
56
62
  export type UsageLocations = {
57
63
  [K in StandardLocationNames]?: typeof standardLocationNamesMeta[K] extends {
58
64
  supports_hook_name: true;
59
65
  } ? LocationWithHookNameSupport : boolean | number;
60
66
  } & {
61
67
  register?: boolean | number;
68
+ inline?: number;
62
69
  handle?: string | ((generatedHandle: string) => string);
63
- registerScriptArgs?: ScriptArgsObject | boolean | 'lazy';
70
+ registerScriptArgs?: InputRegisterScriptArgs;
64
71
  };
65
72
  export type NormalizedUsageLocations = Omit<UsageLocations, 'registerScriptArgs'> & {
66
- registerScriptArgs?: ScriptArgsObject | boolean;
73
+ registerScriptArgs?: InputRegisterScriptArgs;
67
74
  };
68
75
  export declare function isNormalizedUsageLocations(usageLocations: UsageLocations): usageLocations is NormalizedUsageLocations;
69
76
  export declare function constantKeys<K extends string, V>(object: {
@@ -78,6 +85,9 @@ export declare const enum SourceType {
78
85
  plain = "plain"
79
86
  }
80
87
  export declare function determineCurrentSourceType(dest: string | AdvancedOutputConfig, srcIsDirectory: boolean): SourceType;
88
+ export interface WebpackPlugin {
89
+ apply(compiler: Compiler): void;
90
+ }
81
91
  export type ObjectIndividualExternalDepConfig = {
82
92
  import?: string | [string, ...string[]];
83
93
  handle: string;
@@ -96,8 +106,9 @@ export type AdvancedOutputConfig = {
96
106
  bundleAnalyzer?: boolean;
97
107
  locations?: UsageLocations | UsageLocations['handle'];
98
108
  lazyLoader?: string;
109
+ pathQueryParameters?: PathQueryParameters;
99
110
  };
100
- type OptionalCfgFields = 'directoryLayout' | 'externalize' | 'lazyLoader';
111
+ type OptionalCfgFields = 'directoryLayout' | 'externalize' | 'lazyLoader' | 'pathQueryParameters';
101
112
  export type VerifiedAdvancedOutputConfig = Required<Omit<AdvancedOutputConfig, 'locations' | OptionalCfgFields>> & Pick<AdvancedOutputConfig, OptionalCfgFields> & {
102
113
  locations: NormalizedUsageLocations;
103
114
  };
@@ -136,7 +147,9 @@ export type FileSegmentBlockEntrypointInfo = {
136
147
  handle: string;
137
148
  dest: VerifiedAdvancedOutputConfig;
138
149
  absoluteSrc: string;
150
+ pathQueryParameters: PathQueryParameters | undefined;
139
151
  };
152
+ export type PathQueryParameters = Record<string, unknown | [unknown, ...unknown[]]>;
140
153
  export type BlockEntrypointInfo = FileSegmentBlockEntrypointInfo | {
141
154
  dest: VerifiedAdvancedOutputConfig;
142
155
  purpose: string;
@@ -160,6 +173,7 @@ export declare function scriptOrStyleTest(entryPath: string, scriptExtension: Re
160
173
  export declare function isStyleField(field: string): field is 'style' | 'viewStyle' | 'editorStyle';
161
174
  export declare function isScriptModuleField(field: string): field is 'viewScriptModule';
162
175
  export declare function getHandleGroup(field: string): 'styleHandles' | 'scriptHandles' | 'scriptModuleHandles';
176
+ export type StripFirstTwoItems<A extends any[]> = A extends [any, any, ...rest: infer R] ? R : never;
163
177
  export declare function hasAtLeastOneItem<T>(list: T[]): list is [T, ...T[]];
164
178
  export type TupleOf<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never;
165
179
  type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>;
@@ -184,4 +198,14 @@ export declare function getParsedAssetsJsonDataForEntrypoint(compilation: Compil
184
198
  export declare function emitPHPWriterAsAsset(writer: PHPWriter, compilation: Compilation, file: string, assetInfo?: AssetInfo): void;
185
199
  export declare function dedent(text: TemplateStringsArray): string;
186
200
  export declare function resolveLegacyBlockScriptsInFolder(folder: string): string[];
201
+ /**
202
+ * @param compilation
203
+ * @param writer
204
+ * @param handle
205
+ * @param type 'script_module' is NOT supported at this time; however, it is *handled* in this function
206
+ * @param inlinedAsset
207
+ * @param handleData
208
+ * @param file something that represents the file that is being inlined (this is purely for error-reporting purposes)
209
+ */
210
+ export declare function appendAddInlineAssetCall(compilation: Compilation, writer: PHPWriter, handle: string, type: 'script' | 'style' | 'script_module', inlinedAsset: InlinedAsset, handleData: HandleData, file: string): void;
187
211
  export {};
package/build/shared.js CHANGED
@@ -29,12 +29,14 @@ exports.getParsedAssetsJsonDataForEntrypoint = getParsedAssetsJsonDataForEntrypo
29
29
  exports.emitPHPWriterAsAsset = emitPHPWriterAsAsset;
30
30
  exports.dedent = dedent;
31
31
  exports.resolveLegacyBlockScriptsInFolder = resolveLegacyBlockScriptsInFolder;
32
+ exports.appendAddInlineAssetCall = appendAddInlineAssetCall;
32
33
  const node_fs_1 = __importDefault(require("node:fs"));
33
34
  const promises_1 = __importDefault(require("node:fs/promises"));
34
35
  const node_path_1 = __importDefault(require("node:path"));
35
36
  const php_writer_1 = require("@plaudit/php-writer");
36
37
  const expressions_1 = require("@plaudit/php-writer/expressions");
37
38
  const webpack_1 = require("webpack");
39
+ const node_crypto_1 = require("node:crypto");
38
40
  function isParsedAssetsJson(thing) {
39
41
  if (!thing || typeof thing !== 'object') {
40
42
  return false;
@@ -103,9 +105,9 @@ function leadingSlashIt(pathOrSomething) {
103
105
  return pathOrSomething.startsWith('/') ? pathOrSomething : ('/' + pathOrSomething);
104
106
  }
105
107
  exports.scriptExtension = /(?<filename>.+)(?<extension>\.m?[jt]sx?)$/i;
106
- exports.scriptWithoutModuleExtension = /(?<filename>.+)(?<extension>\.[jt]sx?)$/i;
107
- exports.scriptWithModuleExtension = /(?<filename>.+)(?<extension>\.m[jt]sx?)$/i;
108
- exports.styleExtension = /(?<filename>.+)(?<extension>\.(p?c|sa)ss)$/i;
108
+ exports.scriptWithoutModuleExtension = /(?<filename>.+)(?<extension>\.[jt]sx?)($|\?)/i;
109
+ exports.scriptWithModuleExtension = /(?<filename>.+)(?<extension>\.m[jt]sx?)($|\?)/i;
110
+ exports.styleExtension = /(?<filename>.+)(?<extension>\.(p?c|sa)ss)($|\?)/i;
109
111
  function scriptOrStyleTest(entryPath, scriptExtension) {
110
112
  return scriptExtension.test(entryPath) ? "script" : (exports.styleExtension.test(entryPath) ? "style" : "");
111
113
  }
@@ -250,3 +252,25 @@ function resolveLegacyBlockScriptsInFolder(folder) {
250
252
  }
251
253
  return blockScriptEntrypoints;
252
254
  }
255
+ /**
256
+ * @param compilation
257
+ * @param writer
258
+ * @param handle
259
+ * @param type 'script_module' is NOT supported at this time; however, it is *handled* in this function
260
+ * @param inlinedAsset
261
+ * @param handleData
262
+ * @param file something that represents the file that is being inlined (this is purely for error-reporting purposes)
263
+ */
264
+ function appendAddInlineAssetCall(compilation, writer, handle, type, inlinedAsset, handleData, file) {
265
+ if (type === 'script_module') {
266
+ throw newWebpackErrorForFile("WordPress does not support inlined script modules", file);
267
+ }
268
+ if (handleData.rest[0]?.length) { // If there are any dependencies
269
+ compilation.errors.push(newWebpackErrorForFile("Inlined scripts MUST NOT have dependencies. It WILL cause runtime inconsistencies and potentially cause sever performance issues", handleData.src));
270
+ }
271
+ const args = [handle, new expressions_1.HereOrNowDoc(`plaudit_inlined_${type}_${(0, node_crypto_1.createHash)('md5').update(handle).digest("hex")}`, inlinedAsset.contents, false)];
272
+ if (type === 'script' && inlinedAsset.position === 'before') {
273
+ args.push('before');
274
+ }
275
+ writer.call(`wp_add_inline_${type}`, args);
276
+ }
@@ -1,6 +1,6 @@
1
1
  import type { AbstractBiPhasicGroupAndEntryPlugin, EntryProvider } from "../plugins/AbstractBiPhasicGroupAndEntryPlugin";
2
2
  import type { AdditionalDependencyInjectorPlugin } from "../plugins/AdditionalDependencyInjectorPlugin";
3
- import { EntrypointFields, PlauditWordpressWebpackConfig, BlockEntrypointInfo, VerifiedAdvancedOutputConfig, MinimumViableMetadata } from "../shared";
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
6
  export type VerifiedPlauditWordpressWebpackConfig = Required<Omit<PlauditWordpressWebpackConfig, 'variables' | 'src' | 'externals'>> & {
@@ -8,7 +8,7 @@ export type VerifiedPlauditWordpressWebpackConfig = Required<Omit<PlauditWordpre
8
8
  currentVariables: Record<string, any>;
9
9
  } & Pick<PlauditWordpressWebpackConfig, 'externals'>;
10
10
  export type CommonPluginConfig = {
11
- plugins: (WebpackPluginInstance | ((this: Compiler, compiler: Compiler) => void))[];
11
+ plugins: (WebpackPluginInstance | WebpackPlugin | ((this: Compiler, compiler: Compiler) => void))[];
12
12
  removeEmptyScriptsPlugin: WebpackRemoveEmptyScriptsPlugin;
13
13
  makeAdditionalDependencyInjectorPlugin(referencePlugin: AbstractBiPhasicGroupAndEntryPlugin<any>): AdditionalDependencyInjectorPlugin;
14
14
  };
@@ -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 path_query_and_related_helpers_1 = require("./path-query-and-related-helpers");
13
14
  const shared_1 = require("../shared");
14
15
  const css_minimizer_webpack_plugin_1 = __importDefault(require("css-minimizer-webpack-plugin"));
15
16
  function joinPossiblyAbsolutePaths(...paths) {
@@ -34,7 +35,8 @@ function mapToRealEntrypoints(entrypoint, dir, supportedExtensions, args) {
34
35
  return (Array.isArray(entrypoint) ? entrypoint : [entrypoint])
35
36
  .map(ep => joinPossiblyAbsolutePaths(dir, mapper(ep)))
36
37
  .filter(ep => supportedExtensions(ep) && node_fs_1.default.statSync(ep, { throwIfNoEntry: false })?.isFile())
37
- .map(ep => {
38
+ .map(path_query_and_related_helpers_1.unpackPotentiallyPrefixedFilePath)
39
+ .map(([ep, pathQueryParameters]) => {
38
40
  const parsedEntrypoint = node_path_1.default.parse(ep);
39
41
  const entrypointField = shared_1.styleExtension.test(ep) ? 'style' : shared_1.scriptWithModuleExtension.test(ep) ? 'viewScriptModule' : 'script';
40
42
  const fakeEntrypointInfo = {
@@ -45,7 +47,8 @@ function mapToRealEntrypoints(entrypoint, dir, supportedExtensions, args) {
45
47
  handle: (0, shared_1.convertUsageLocationsHandleToEmittableHandle)(dest.locations.handle, parsedEntrypoint.name),
46
48
  handleGroup: (0, shared_1.getHandleGroup)(entrypointField),
47
49
  dest,
48
- absoluteSrc: ep
50
+ absoluteSrc: ep,
51
+ pathQueryParameters
49
52
  };
50
53
  return [joinPossiblyAbsolutePaths(dest.destination, node_path_1.default.basename(parsedEntrypoint.dir), parsedEntrypoint.name),
51
54
  { import: [ep], plauditMetadata: fakeEntrypointInfo }];
@@ -134,17 +137,19 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
134
137
  .filter(entrypointField => entrypointField in blockJson)
135
138
  .flatMap(entrypointField => {
136
139
  return (Array.isArray(blockJson[entrypointField]) ? blockJson[entrypointField] : [blockJson[entrypointField]])
137
- .filter(originalValue => originalValue.startsWith("file:"))
140
+ .filter(originalValue => typeof originalValue === 'string')
141
+ .filter(originalValue => originalValue?.startsWith("file:"))
138
142
  .map(originalValue => {
139
- const entrypointPath = originalValue.substring(5);
143
+ const [entrypointPath, localPathQueryParameters] = (0, path_query_and_related_helpers_1.unpackPotentiallyPrefixedFilePath)(originalValue);
140
144
  const absoluteSrc = node_path_1.default.normalize(node_path_1.default.join(dir, entrypointPath));
145
+ const pathQueryParameters = (0, path_query_and_related_helpers_1.mergeInPathQueryParameters)(absoluteSrc, localPathQueryParameters, dest.pathQueryParameters);
141
146
  return promises_1.default.stat(absoluteSrc)
142
147
  .then(stats => {
143
148
  if (stats.isFile()) {
144
149
  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)));
145
150
  const extensionlessExpectedSrc = node_path_1.default.normalize(node_path_1.default.join(parsedEntrypoint.dir, parsedEntrypoint.name));
146
151
  const entrypointName = node_path_1.default.normalize(joinPossiblyAbsolutePaths(parsedEntrypoint.dir, parsedEntrypoint.name));
147
- return { entrypointField, originalValue, entrypointName, extensionlessExpectedSrc, absoluteSrc };
152
+ return { entrypointField, originalValue, entrypointName, extensionlessExpectedSrc, absoluteSrc, pathQueryParameters };
148
153
  }
149
154
  else {
150
155
  return undefined;
@@ -196,7 +201,7 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
196
201
  }
197
202
  ];
198
203
  }));
199
- rawEntrypoints.push([blockJsonChunkName, { import: [blockJsonOrigin], plauditMetadata: { purpose: "block-json-inclusion-assurance", dest, absoluteSrc: blockJsonOrigin } }]);
204
+ rawEntrypoints.push([blockJsonChunkName, { import: [blockJsonOrigin], plauditMetadata: { purpose: "block-json-inclusion-assurance", dest, absoluteSrc: blockJsonOrigin, pathQueryParameters: undefined } }]);
200
205
  wpmlFiles.push(node_path_1.default.join(dir, 'block.json'));
201
206
  }
202
207
  catch (e) {
@@ -0,0 +1,53 @@
1
+ import { Compilation } from "webpack";
2
+ import { InlinedAsset, PathQueryParameters, ScriptArgsObject, UsageLocations } from "../shared";
3
+ export declare function getAssetFileContents(compilation: Compilation, name: string): string;
4
+ export declare function unpackPotentiallyPrefixedFilePath(filePath: string): [string, PathQueryParameters | undefined];
5
+ /**
6
+ * The following substitutions are performed:
7
+ * <ul>
8
+ * <li>parameters without an assigned value -> a boolean parameter set to true</li>
9
+ * <li>true and false -> their boolean equivalents</li>
10
+ * <li>numeric values -> their number equivalents</li>
11
+ * </ul>
12
+ *
13
+ * @param pathQuery the part after the "?" in a webpack inclusion path
14
+ * @return the query as an object with common string -> JS type conversions already performed
15
+ */
16
+ export declare function unpackPathQuery(pathQuery: string): PathQueryParameters | undefined;
17
+ export type LoadingStrategy = boolean | 'defer' | 'async' | 'eager' | 'lazy' | 'inline';
18
+ export declare function isValidLoadingStrategy(strategy: any): strategy is LoadingStrategy | undefined;
19
+ export declare function newInvalidLoadingStrategyError(strategy: unknown, file: string): import("webpack").WebpackError;
20
+ export type InFooter = boolean;
21
+ export declare function isValidInFooter(in_footer: unknown): in_footer is InFooter;
22
+ export declare function newInvalidInFooterError(in_footer: unknown, file: string): import("webpack").WebpackError;
23
+ export type FetchPriority = 'auto' | 'low' | 'high';
24
+ export declare function isValidFetchPriority(fetchpriority: unknown): fetchpriority is FetchPriority;
25
+ export declare function newInvalidFetchPriorityError(fetchpriority: unknown, file: string): import("webpack").WebpackError;
26
+ export type PositionForInlineStrategy = 'before' | 'after';
27
+ export declare function isValidPositionForInlineStrategy(position: unknown): position is PositionForInlineStrategy;
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
+ /**
31
+ * This function ensures that the passed pathQueryParameters are normalized for the config-loading step, NOT the emission step
32
+ */
33
+ export type NormalizedScriptEnqueuingControlFlags = {
34
+ strategy?: Exclude<LoadingStrategy, 'inline'>;
35
+ in_footer?: InFooter;
36
+ inline?: boolean;
37
+ fetchpriority?: FetchPriority;
38
+ position?: 'before' | 'after';
39
+ };
40
+ /**
41
+ * This function does a few things:
42
+ * <ol>
43
+ * <li>It extracts strategy, in_footer, and fetchpriority from pathQueryParameters</li>
44
+ * <li>If the strategy is, 'inline', it records the contents of the asset for later injection inline and removes the asset from the compilation output</li>
45
+ * </ol>
46
+ * @param compilation
47
+ * @param file
48
+ * @param pathQueryParameters
49
+ */
50
+ export declare function parseScriptArgsObjectFromPathQueryParameters(compilation: Compilation, file: string, pathQueryParameters: PathQueryParameters | undefined): {
51
+ scriptArgsObject?: ScriptArgsObject;
52
+ inlinedAsset?: InlinedAsset;
53
+ };