@plaudit/webpack-extensions 2.58.1 → 2.58.3

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.
@@ -321,13 +321,16 @@ class BlockJSONManagingPlugin {
321
321
  registerBlockJsonProcessor(compilation) {
322
322
  const blockDirConfigData = {};
323
323
  compilation.hooks.processAssets.tap({ name: `${this.constructor.name}_UnifiedLoaderGeneratorIntegration`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_DERIVED }, () => {
324
- UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, ['block.json', writer => {
324
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, {
325
+ group: `block-json-${this.blocksDest}`,
326
+ action: writer => {
325
327
  writer
326
328
  .use("Plaudit\\Common\\ACF\\BlockManager")
327
329
  .action("init", writer => {
328
330
  writer.call("BlockManager::autoloadSubfolders", [new php_writer_1.Expr(`__DIR__.${php_writer_1.Expr.convertJsonToPHP("/" + this.blocksDest)}`)]);
329
331
  });
330
- }]);
332
+ }
333
+ });
331
334
  });
332
335
  compilation.hooks.afterProcessAssets.tap(`${this.constructor.name}_GenerateMetadata`, compilationAssets => {
333
336
  const currentBlockJSONAssets = BlockJSONManagingPlugin.blockJSONAssetSourceDirs.entries()
@@ -1,14 +1,15 @@
1
+ import { VerifiedPlauditWordpressWebpackConfig } from "../utils/common-config-helpers";
1
2
  import { type Compiler, type WebpackPluginInstance } from "webpack";
2
3
  export declare class ExtensionsConfigFileGeneratorPlugin implements WebpackPluginInstance {
4
+ private readonly config;
3
5
  private readonly extensionsPath;
4
- private readonly version;
5
6
  private readonly extensionsDest;
6
- private readonly handlePrefix;
7
7
  private static readonly semaphore;
8
- private static cache;
8
+ private static phaseTwoAttached;
9
9
  private readonly id;
10
- constructor(extensionsPath: string, version: 1 | 2, extensionsDest: string, handlePrefix: string);
10
+ constructor(config: VerifiedPlauditWordpressWebpackConfig, extensionsPath: string, extensionsDest: string);
11
11
  apply(compiler: Compiler): void;
12
+ private generateVersionTwoConfigFile;
12
13
  private makeVersionOneAfterProcessAssets;
13
14
  private stripExtensionsDest;
14
15
  }
@@ -6,25 +6,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ExtensionsConfigFileGeneratorPlugin = void 0;
7
7
  const promises_1 = __importDefault(require("node:fs/promises"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
+ const UnifiedLoaderGenerator_1 = require("./UnifiedLoaderGenerator");
9
10
  const shared_1 = require("../shared");
10
11
  const php_serializer_1 = require("../utils/php-serializer");
12
+ const php_writer_1 = require("../utils/php-writer");
11
13
  const pseduo_semaphore_1 = require("../utils/pseduo-semaphore");
12
14
  const webpack_1 = require("webpack");
13
- const UnifiedLoaderGenerator_1 = require("./UnifiedLoaderGenerator");
14
- const php_writer_1 = require("../utils/php-writer");
15
15
  class ExtensionsConfigFileGeneratorPlugin {
16
+ config;
16
17
  extensionsPath;
17
- version;
18
18
  extensionsDest;
19
- handlePrefix;
20
19
  static semaphore = new pseduo_semaphore_1.PseudoSemaphore({ assets: [], setupFiles: [] }, "Extensions");
21
- static cache = undefined;
20
+ static phaseTwoAttached = false;
22
21
  id;
23
- constructor(extensionsPath, version, extensionsDest, handlePrefix) {
22
+ constructor(config, extensionsPath, extensionsDest) {
23
+ this.config = config;
24
24
  this.extensionsPath = extensionsPath;
25
- this.version = version;
26
25
  this.extensionsDest = extensionsDest;
27
- this.handlePrefix = handlePrefix;
28
26
  this.id = Math.random().toString();
29
27
  ExtensionsConfigFileGeneratorPlugin.semaphore.register(this.id);
30
28
  UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.register(this.id);
@@ -46,86 +44,35 @@ class ExtensionsConfigFileGeneratorPlugin {
46
44
  }
47
45
  await Promise.all(emissionPromises);
48
46
  });
49
- if (this.version === 2) {
50
- const tapName = { name: `${this.constructor.name}_ProcessBlockJSONFiles`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_REPORT };
47
+ if (this.config.extensionsVersion === 2) {
51
48
  compiler.hooks.compilation.tap(this.constructor.name, compilation => {
52
- ExtensionsConfigFileGeneratorPlugin.cache = undefined;
49
+ ExtensionsConfigFileGeneratorPlugin.phaseTwoAttached = false;
53
50
  ExtensionsConfigFileGeneratorPlugin.semaphore.reset(this.id);
54
51
  UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.reset(this.id);
55
- compilation.hooks.processAssets.tap({ name: `${this.constructor.name}_UnifiedLoaderGeneratorIntegration`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_DERIVED }, () => {
56
- UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, ['extensions-config-v2', writer => {
57
- let finalExtensionsDest = this.extensionsDest.endsWith("/") ? this.extensionsDest : this.extensionsDest + "/";
58
- if (!finalExtensionsDest.startsWith("/")) {
59
- finalExtensionsDest = "/" + finalExtensionsDest;
52
+ compilation.hooks.beforeChunkIds.tap(this.constructor.name, () => {
53
+ if (!ExtensionsConfigFileGeneratorPlugin.phaseTwoAttached) {
54
+ ExtensionsConfigFileGeneratorPlugin.phaseTwoAttached = true;
55
+ compilation.hooks.processAssets.tapPromise({ name: `${this.constructor.name}_GenerateConfigFile`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_REPORT }, async () => {
56
+ const combinedExtensionData = (await ExtensionsConfigFileGeneratorPlugin.semaphore.wait())
57
+ .reduce((main, { assets, setupFiles }) => {
58
+ main.assets.push(...assets);
59
+ main.setupFiles.push(...setupFiles);
60
+ return main;
61
+ }, { assets: [], setupFiles: [] });
62
+ if (combinedExtensionData.assets.length > 0 || combinedExtensionData.setupFiles.length > 0 || !this.config.useUnifiedLoader) {
63
+ this.generateVersionTwoConfigFile(compilation, combinedExtensionData);
60
64
  }
61
- writer
62
- .use("Plaudit\\Base\\API\\ThemeUtils")
63
- .withScope(writer => writer
64
- .assign("$filePathPrefix", new php_writer_1.Expr(`__DIR__.${php_writer_1.Expr.convertJsonToPHP(finalExtensionsDest)}`))
65
- .call("plaudit_webpack_extensions__resolve_base_uri", [new php_writer_1.Expr("$filePathPrefix")], { assignTo: "$fileUriPrefix" })
66
- .call("ThemeUtils::loadExtensionsV2", [
67
- new php_writer_1.Expr(`__DIR__.${php_writer_1.Expr.convertJsonToPHP(finalExtensionsDest + "mapping.config.php")}`),
68
- new php_writer_1.Expr(`$filePathPrefix`), new php_writer_1.Expr("$fileUriPrefix"),
69
- `${this.handlePrefix ? this.handlePrefix : node_path_1.default.basename(process.cwd())}_extension_`
70
- ]));
71
- }]);
65
+ });
66
+ }
72
67
  });
73
- compilation.hooks.processAssets.tapPromise(tapName, async (assets) => {
68
+ compilation.hooks.processAssets.tapPromise({ name: this.constructor.name, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ANALYSE, additionalAssets: true }, async (assets) => {
69
+ if (!("assets.json" in assets)) {
70
+ return;
71
+ }
74
72
  try {
75
- //TODO: Add handling of extracted CSS from JS
76
73
  //TODO: It should be possible to use EntryPoints to determine the "original" file
77
- //TODO: Use the version hash of the original file, but not its dependencies for the additional file's "rest" parameter (see BlockJSONManagingPlugin.ts for how to do so)
78
74
  //TODO: There is no reason to not use basically the exact same logic to implement support for this in plain file contexts
79
75
  //TODO: BlockJSONManagingPlugin should be rewritten from scratch to use this method instead of its 15 layers of tracking + syncing
80
- if (ExtensionsConfigFileGeneratorPlugin.cache === undefined) {
81
- ExtensionsConfigFileGeneratorPlugin.cache = { assets: [], setupFiles: [] };
82
- compilation.hooks.afterProcessAssets.tap(`${this.constructor.name}_GenerateConfigFile`, () => {
83
- const regex = /^(.+?)-((?:editor-|view-|)(?:style|script|script-module))\.(?:css|m?js)$/i;
84
- const blockExtensionsConfig = { metadata: { version: this.version }, scriptHandles: {}, styleHandles: {}, blocks: {}, setupFiles: {} };
85
- for (const assetDataSource of ExtensionsConfigFileGeneratorPlugin.cache?.assets ?? []) {
86
- const normalizedAssetData = Object.entries(assetDataSource)
87
- .map(entry => {
88
- const assetPath = this.extensionsDest && entry[0].startsWith(this.extensionsDest + "/")
89
- ? entry[0].substring(this.extensionsDest.length + 1) : entry[0];
90
- return [assetPath, entry[1]];
91
- });
92
- for (const [assetPath, assetData] of normalizedAssetData) {
93
- const match = regex.exec(assetPath);
94
- if (!match) {
95
- continue;
96
- }
97
- const blockSlug = match[1], assetType = match[2];
98
- if (blockSlug && assetType) {
99
- const key = assetType.replace(/-[sm]/gi, chars => chars.substring(1).toUpperCase());
100
- const handle = `plaudit_block-extension_${blockSlug}-${assetType}`;
101
- const isCss = assetType.endsWith("tyle");
102
- blockExtensionsConfig[isCss ? 'styleHandles' : 'scriptHandles'][handle] = {
103
- src: isCss ? assetPath.replace(/\.js$/, ".css") : assetPath,
104
- rest: isCss || key.startsWith("editor")
105
- ? [assetData.dependencies, assetData.version]
106
- : [assetData.dependencies, assetData.version, { strategy: 'defer' }]
107
- };
108
- (blockExtensionsConfig.blocks[blockSlug] ?? (blockExtensionsConfig.blocks[blockSlug] = {}))[key] = handle;
109
- }
110
- }
111
- for (const [blockSlug, asset] of ExtensionsConfigFileGeneratorPlugin.cache?.setupFiles ?? []) {
112
- blockExtensionsConfig.setupFiles[blockSlug] = asset;
113
- }
114
- }
115
- blockExtensionsConfig.scriptHandles = Object.fromEntries(Object.entries(blockExtensionsConfig.scriptHandles)
116
- .toSorted(([a], [b]) => a.localeCompare(b)));
117
- blockExtensionsConfig.styleHandles = Object.fromEntries(Object.entries(blockExtensionsConfig.styleHandles)
118
- .toSorted(([a], [b]) => a.localeCompare(b)));
119
- blockExtensionsConfig.setupFiles = Object.fromEntries(Object.entries(blockExtensionsConfig.setupFiles)
120
- .toSorted(([a], [b]) => a.localeCompare(b)));
121
- blockExtensionsConfig.blocks = Object.fromEntries(Object.entries(blockExtensionsConfig.blocks)
122
- .map(block => {
123
- return [block[0], Object.fromEntries(Object.entries(block[1]).toSorted(([a], [b]) => a.localeCompare(b)))];
124
- })
125
- .toSorted(([a], [b]) => a.localeCompare(b)));
126
- compilation.emitAsset(node_path_1.default.join(this.extensionsDest, "mapping.config.php"), new webpack_1.sources.RawSource((0, shared_1.makeEmittableConfigPHP)(blockExtensionsConfig)));
127
- });
128
- }
129
76
  const myCacheData = { assets: [], setupFiles: [] };
130
77
  for (const asset of Object.keys(compilation.assets).map(asset => this.stripExtensionsDest(asset))) {
131
78
  const blockSlug = /^(.+?)-setup.php$/i.exec(asset)?.[1];
@@ -148,15 +95,29 @@ class ExtensionsConfigFileGeneratorPlugin {
148
95
  myCacheData.assets.push(assetDataSource);
149
96
  compilation.deleteAsset("assets.json");
150
97
  ExtensionsConfigFileGeneratorPlugin.semaphore.resolve(this.id, myCacheData);
151
- ExtensionsConfigFileGeneratorPlugin.cache = (await ExtensionsConfigFileGeneratorPlugin.semaphore.wait())
152
- .reduce((main, { assets, setupFiles }) => {
153
- main.assets.push(...assets);
154
- main.setupFiles.push(...setupFiles);
155
- return main;
156
- }, { assets: [], setupFiles: [] });
98
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, myCacheData.setupFiles.length > 0 || myCacheData.assets.length > 0 ? {
99
+ group: 'extensions-config-v2',
100
+ action: writer => {
101
+ let finalExtensionsDest = this.extensionsDest.endsWith("/") ? this.extensionsDest : this.extensionsDest + "/";
102
+ if (!finalExtensionsDest.startsWith("/")) {
103
+ finalExtensionsDest = "/" + finalExtensionsDest;
104
+ }
105
+ writer
106
+ .use("Plaudit\\Base\\API\\ThemeUtils")
107
+ .withScope(writer => writer
108
+ .assign("$filePathPrefix", new php_writer_1.Expr(`__DIR__.${php_writer_1.Expr.convertJsonToPHP(finalExtensionsDest)}`))
109
+ .call("plaudit_webpack_extensions__resolve_base_uri", [new php_writer_1.Expr("$filePathPrefix")], { assignTo: "$fileUriPrefix" })
110
+ .call("ThemeUtils::loadExtensionsV2", [
111
+ new php_writer_1.Expr(`__DIR__.${php_writer_1.Expr.convertJsonToPHP(finalExtensionsDest + "mapping.config.php")}`),
112
+ new php_writer_1.Expr(`$filePathPrefix`), new php_writer_1.Expr("$fileUriPrefix"),
113
+ `${this.config.plainEntrypointsHandlePrefix || node_path_1.default.basename(process.cwd())}_extension_`
114
+ ]));
115
+ }
116
+ } : undefined);
157
117
  }
158
118
  catch (e) {
159
119
  ExtensionsConfigFileGeneratorPlugin.semaphore.reject(this.id);
120
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.reject(this.id);
160
121
  if (e instanceof Error) {
161
122
  compilation.errors.push(e);
162
123
  return;
@@ -170,16 +131,62 @@ class ExtensionsConfigFileGeneratorPlugin {
170
131
  compiler.hooks.thisCompilation.tap(this.constructor.name, compilation => {
171
132
  UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.reset(this.id);
172
133
  compilation.hooks.processAssets.tap({ name: `${this.constructor.name}_UnifiedLoaderGeneratorIntegration`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_DERIVED }, () => {
173
- UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, ['extensions-config-v1', writer => {
134
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, { group: 'extensions-config-v1', action: writer => {
174
135
  writer
175
136
  .use("Plaudit\\Base\\API\\ThemeUtils")
176
137
  .call("ThemeUtils::installExtensionSupport", [new php_writer_1.Expr(`__DIR__.${php_writer_1.Expr.convertJsonToPHP(this.extensionsDest)}`)]);
177
- }]);
138
+ } });
178
139
  });
179
140
  compilation.hooks.afterProcessAssets.tap(`${this.constructor.name}_AfterProcessAssets`, this.makeVersionOneAfterProcessAssets(compilation));
180
141
  });
181
142
  }
182
143
  }
144
+ generateVersionTwoConfigFile(compilation, combinedExtensionData) {
145
+ const regex = /^(.+?)-((?:editor-|view-|)(?:style|script|script-module))\.(?:css|m?js)$/i;
146
+ const blockExtensionsConfig = { metadata: { version: this.config.extensionsVersion }, scriptHandles: {}, styleHandles: {}, blocks: {}, setupFiles: {} };
147
+ for (const assetDataSource of combinedExtensionData.assets) {
148
+ const normalizedAssetData = Object.entries(assetDataSource)
149
+ .map(entry => {
150
+ const assetPath = this.extensionsDest && entry[0].startsWith(this.extensionsDest + "/")
151
+ ? entry[0].substring(this.extensionsDest.length + 1) : entry[0];
152
+ return [assetPath, entry[1]];
153
+ });
154
+ for (const [assetPath, assetData] of normalizedAssetData) {
155
+ const match = regex.exec(assetPath);
156
+ if (!match) {
157
+ continue;
158
+ }
159
+ const blockSlug = match[1], assetType = match[2];
160
+ if (blockSlug && assetType) {
161
+ const key = assetType.replace(/-[sm]/gi, chars => chars.substring(1).toUpperCase());
162
+ const handle = `plaudit_block-extension_${blockSlug}-${assetType}`;
163
+ const isCss = assetType.endsWith("tyle");
164
+ blockExtensionsConfig[isCss ? 'styleHandles' : 'scriptHandles'][handle] = {
165
+ src: isCss ? assetPath.replace(/\.js$/, ".css") : assetPath,
166
+ rest: isCss || key.startsWith("editor")
167
+ ? [assetData.dependencies, assetData.version]
168
+ : [assetData.dependencies, assetData.version, { strategy: 'defer' }]
169
+ };
170
+ (blockExtensionsConfig.blocks[blockSlug] ?? (blockExtensionsConfig.blocks[blockSlug] = {}))[key] = handle;
171
+ }
172
+ }
173
+ for (const [blockSlug, asset] of combinedExtensionData.setupFiles) {
174
+ blockExtensionsConfig.setupFiles[blockSlug] = asset;
175
+ }
176
+ }
177
+ blockExtensionsConfig.scriptHandles = Object.fromEntries(Object.entries(blockExtensionsConfig.scriptHandles)
178
+ .toSorted(([a], [b]) => a.localeCompare(b)));
179
+ blockExtensionsConfig.styleHandles = Object.fromEntries(Object.entries(blockExtensionsConfig.styleHandles)
180
+ .toSorted(([a], [b]) => a.localeCompare(b)));
181
+ blockExtensionsConfig.setupFiles = Object.fromEntries(Object.entries(blockExtensionsConfig.setupFiles)
182
+ .toSorted(([a], [b]) => a.localeCompare(b)));
183
+ blockExtensionsConfig.blocks = Object.fromEntries(Object.entries(blockExtensionsConfig.blocks)
184
+ .map(block => {
185
+ return [block[0], Object.fromEntries(Object.entries(block[1]).toSorted(([a], [b]) => a.localeCompare(b)))];
186
+ })
187
+ .toSorted(([a], [b]) => a.localeCompare(b)));
188
+ compilation.emitAsset(node_path_1.default.join(this.extensionsDest, "mapping.config.php"), new webpack_1.sources.RawSource((0, shared_1.makeEmittableConfigPHP)(blockExtensionsConfig)));
189
+ }
183
190
  makeVersionOneAfterProcessAssets(compilation) {
184
191
  return compilationAssets => {
185
192
  const regex = /^(.+?)-((?:editor-|view-|)(?:style|script|script-module))\.(?:css|m?js)$/i;
@@ -8,7 +8,7 @@ export declare class PlainEntrypointsConfigFileGeneratorPlugin implements Webpac
8
8
  private readonly handlePrefix;
9
9
  private readonly useUnifiedLoader;
10
10
  private static readonly semaphore;
11
- private static cache?;
11
+ private static phaseTwoAttached;
12
12
  private readonly id;
13
13
  constructor(buildRoot: string, outputDir: string, usageLocations: UsageLocations, handlePrefix: string, useUnifiedLoader: boolean);
14
14
  apply(compiler: Compiler): void;
@@ -17,7 +17,7 @@ class PlainEntrypointsConfigFileGeneratorPlugin {
17
17
  handlePrefix;
18
18
  useUnifiedLoader;
19
19
  static semaphore = new pseduo_semaphore_1.PseudoSemaphore([], "Plain");
20
- static cache = undefined;
20
+ static phaseTwoAttached = false;
21
21
  id;
22
22
  constructor(buildRoot, outputDir, usageLocations, handlePrefix, useUnifiedLoader) {
23
23
  this.buildRoot = buildRoot;
@@ -30,24 +30,23 @@ class PlainEntrypointsConfigFileGeneratorPlugin {
30
30
  UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.register(this.id);
31
31
  }
32
32
  apply(compiler) {
33
- const tapName = { name: `${this.constructor.name}_ProcessPlainEntrypointFiles`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_REPORT };
34
33
  compiler.hooks.compilation.tap(this.constructor.name, compilation => {
35
- PlainEntrypointsConfigFileGeneratorPlugin.cache = undefined;
34
+ PlainEntrypointsConfigFileGeneratorPlugin.phaseTwoAttached = false;
36
35
  PlainEntrypointsConfigFileGeneratorPlugin.semaphore.reset(this.id);
37
36
  UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.reset(this.id);
38
- compilation.hooks.processAssets.tap({ name: `${this.constructor.name}_UnifiedLoaderGeneratorIntegration`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_DERIVED }, () => {
39
- UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, ['plain-entrypoints-v2', writer => {
40
- writer.append("require_once __DIR__.'/plain-entrypoints-loader.php';");
41
- }]);
37
+ compilation.hooks.beforeChunkIds.tap(this.constructor.name, () => {
38
+ if (!PlainEntrypointsConfigFileGeneratorPlugin.phaseTwoAttached) {
39
+ PlainEntrypointsConfigFileGeneratorPlugin.phaseTwoAttached = true;
40
+ compilation.hooks.processAssets.tapPromise({ name: `${this.constructor.name}_CompileLoader`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_REPORT }, async () => {
41
+ this.afterProcessAssets(compilation, (await PlainEntrypointsConfigFileGeneratorPlugin.semaphore.wait()).flat());
42
+ });
43
+ }
42
44
  });
43
- compilation.hooks.processAssets.tapPromise(tapName, async (assets) => {
45
+ compilation.hooks.processAssets.tapPromise({ name: this.constructor.name, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ANALYSE, additionalAssets: true }, async (assets) => {
46
+ if (!("assets.json" in assets)) {
47
+ return;
48
+ }
44
49
  try {
45
- if (PlainEntrypointsConfigFileGeneratorPlugin.cache === undefined) {
46
- PlainEntrypointsConfigFileGeneratorPlugin.cache = { assets: [] };
47
- compilation.hooks.afterProcessAssets.tap(`${this.constructor.name}_CompileLoader`, () => {
48
- this.afterProcessAssets(compilation);
49
- });
50
- }
51
50
  const rawAssetDataSource = assets["assets.json"]?.source();
52
51
  if (typeof rawAssetDataSource !== 'string') {
53
52
  PlainEntrypointsConfigFileGeneratorPlugin.semaphore.reject(this.id);
@@ -104,7 +103,9 @@ class PlainEntrypointsConfigFileGeneratorPlugin {
104
103
  }
105
104
  compilation.deleteAsset("assets.json");
106
105
  PlainEntrypointsConfigFileGeneratorPlugin.semaphore.resolve(this.id, myAssetHandles);
107
- PlainEntrypointsConfigFileGeneratorPlugin.cache.assets = (await PlainEntrypointsConfigFileGeneratorPlugin.semaphore.wait()).flat();
106
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, myAssetHandles.length
107
+ ? { group: 'plain-entrypoints-v2', action: writer => writer.append("require_once __DIR__.'/plain-entrypoints-loader.php';") }
108
+ : undefined);
108
109
  }
109
110
  catch (e) {
110
111
  PlainEntrypointsConfigFileGeneratorPlugin.semaphore.reject(this.id);
@@ -114,9 +115,8 @@ class PlainEntrypointsConfigFileGeneratorPlugin {
114
115
  });
115
116
  });
116
117
  }
117
- afterProcessAssets(compilation) {
118
+ afterProcessAssets(compilation, assets) {
118
119
  const emitDir = node_path_1.default.join(this.buildRoot, this.outputDir);
119
- //TODO: Add support for editorStyles via the 'block_editor_settings_all' filter
120
120
  const handleLists = {
121
121
  register: [],
122
122
  clientView: [],
@@ -126,7 +126,7 @@ class PlainEntrypointsConfigFileGeneratorPlugin {
126
126
  customizer: [],
127
127
  analytics: []
128
128
  };
129
- const allNamedHandles = (PlainEntrypointsConfigFileGeneratorPlugin.cache?.assets ?? [])
129
+ const allNamedHandles = assets
130
130
  .flatMap(({ handles }) => handles)
131
131
  .filter((handle) => !!handle.handleName)
132
132
  .sort((a, b) => a.src.localeCompare(b.src));
@@ -137,7 +137,7 @@ class PlainEntrypointsConfigFileGeneratorPlugin {
137
137
  .filter(handle => !handle.isScript)
138
138
  .map(handle => [handle.handleName, handle.src]));
139
139
  const plainEntrypointsConfig = { scriptHandles: {}, styleHandles: {} };
140
- for (const { handles, handlePrefix } of PlainEntrypointsConfigFileGeneratorPlugin.cache?.assets ?? []) {
140
+ for (const { handles, handlePrefix } of assets) {
141
141
  for (const { src, rest, locations, isScript, handleName } of handles) {
142
142
  let finalHandleName;
143
143
  if (handleName) {
@@ -257,7 +257,7 @@ class PlainEntrypointsConfigFileGeneratorPlugin {
257
257
  writer
258
258
  .static("$base_uris", { initializer: [] })
259
259
  .if("isset($base_uris[$dir])")
260
- .return("$base_uris[$dir]")
260
+ .return(new php_writer_1.Expr("$base_uris[$dir]"))
261
261
  .elseIf("str_starts_with($dir, ABSPATH)")
262
262
  .append("$path = ltrim(substr($dir, strlen(ABSPATH)), '/');")
263
263
  .elseIf("str_starts_with($dir, '/workspace/website')")
@@ -29,12 +29,13 @@ class SpecialAssetHandlingPlugin {
29
29
  SpecialAssetHandlingPlugin.hasAttachedAssetCollatorForCurrentBatch = false;
30
30
  SpecialAssetHandlingPlugin.semaphore.reset(this.id);
31
31
  UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.reset(this.id);
32
- compilation.hooks.processAssets.tap({ name: `${this.constructor.name}_UnifiedLoaderGeneratorIntegration`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_DERIVED }, () => {
33
- UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, ['special-assets', writer => {
34
- writer.append("require_once __DIR__.'/special-assets.php';");
35
- }]);
32
+ compilation.hooks.beforeChunkIds.tap(this.constructor.name, () => {
33
+ if (!SpecialAssetHandlingPlugin.hasAttachedAssetCollatorForCurrentBatch) {
34
+ SpecialAssetHandlingPlugin.hasAttachedAssetCollatorForCurrentBatch = true;
35
+ compilation.hooks.processAssets.tapPromise({ name: `${this.constructor.name}_CompileLoader`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_REPORT }, () => this.collateAssets(compilation));
36
+ }
36
37
  });
37
- compilation.hooks.processAssets.tapPromise(this.constructor.name, async (assets) => {
38
+ compilation.hooks.processAssets.tapPromise({ name: this.constructor.name, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ANALYSE }, async (assets) => {
38
39
  try {
39
40
  const specialAssetData = {};
40
41
  for (const pathname of Object.keys(assets)) {
@@ -63,12 +64,9 @@ class SpecialAssetHandlingPlugin {
63
64
  }
64
65
  }
65
66
  SpecialAssetHandlingPlugin.semaphore.resolve(this.id, specialAssetData);
66
- if (!SpecialAssetHandlingPlugin.hasAttachedAssetCollatorForCurrentBatch) {
67
- SpecialAssetHandlingPlugin.hasAttachedAssetCollatorForCurrentBatch = true;
68
- const collatedSpecialAssetData = (await SpecialAssetHandlingPlugin.semaphore.wait())
69
- .reduce((collector, current) => ({ ...collector, ...current }), {});
70
- this.collateAssets(compilation, collatedSpecialAssetData);
71
- }
67
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, Object.keys(specialAssetData).length > 0
68
+ ? { group: 'special-assets', action: writer => writer.append("require_once __DIR__.'/special-assets.php';") }
69
+ : undefined);
72
70
  }
73
71
  catch (e) {
74
72
  SpecialAssetHandlingPlugin.semaphore.reject(this.id);
@@ -77,14 +75,18 @@ class SpecialAssetHandlingPlugin {
77
75
  });
78
76
  });
79
77
  }
80
- collateAssets(compilation, collatedSpecialAssetData) {
78
+ async collateAssets(compilation) {
79
+ const collatedSpecialAssetData = (await SpecialAssetHandlingPlugin.semaphore.wait())
80
+ .reduce((collector, current) => ({ ...collector, ...current }), {});
81
81
  const preloadedAssets = Object.entries(collatedSpecialAssetData)
82
82
  .filter(([_, { preload }]) => preload)
83
83
  .sort(([a], [b]) => a.localeCompare(b));
84
84
  const outputFile = this.outputDir ? "special-assets.php" : node_path_1.default.join(node_path_1.default.dirname(node_path_1.default.dirname(SpecialAssetHandlingPlugin.validPathname)), "special-assets.php");
85
85
  const writer = new php_writer_1.PHPWriter();
86
86
  if (!preloadedAssets.length) {
87
- writer.emitAsset(compilation, outputFile);
87
+ if (!this.useUnifiedLoader) {
88
+ writer.emitAsset(compilation, outputFile);
89
+ }
88
90
  return;
89
91
  }
90
92
  if (!this.useUnifiedLoader) {
@@ -1,10 +1,16 @@
1
1
  import { PseudoSemaphore } from "../utils/pseduo-semaphore";
2
2
  import { PHPWriter } from "../utils/php-writer";
3
3
  import { Compiler, WebpackPluginInstance } from "webpack";
4
+ type LoaderInfo = {
5
+ group: string;
6
+ action(writer: PHPWriter): void;
7
+ priority?: number;
8
+ };
4
9
  export declare class UnifiedLoaderGenerator implements WebpackPluginInstance {
5
- static readonly semaphore: PseudoSemaphore<[string, (writer: PHPWriter) => void] | undefined>;
10
+ static readonly semaphore: PseudoSemaphore<LoaderInfo | undefined>;
6
11
  private static attached;
7
12
  private readonly id;
8
13
  constructor();
9
14
  apply(compiler: Compiler): void;
10
15
  }
16
+ export {};
@@ -23,8 +23,15 @@ class UnifiedLoaderGenerator {
23
23
  UnifiedLoaderGenerator.semaphore.resolve(this.id, undefined);
24
24
  if (!UnifiedLoaderGenerator.attached) {
25
25
  UnifiedLoaderGenerator.attached = true;
26
- const writerCallbacks = Object.values(Object.fromEntries((await UnifiedLoaderGenerator.semaphore.wait())
27
- .filter(a => a !== undefined))); // A simple deduplication trick
26
+ const alreadyAllocatedGroups = new Set();
27
+ const writerCallbacks = (await UnifiedLoaderGenerator.semaphore.wait())
28
+ .filter((a) => a !== undefined)
29
+ .sort((a, b) => {
30
+ const ap = a.priority ?? 0, bp = b.priority ?? 0;
31
+ return ap === bp ? a.group.localeCompare(b.group) : bp - ap;
32
+ })
33
+ .filter(a => !alreadyAllocatedGroups.has(a.group) && alreadyAllocatedGroups.add(a.group))
34
+ .map(a => a.action);
28
35
  if (writerCallbacks.length > 0) {
29
36
  compilation.hooks.afterProcessAssets.tap(this.constructor.name, () => {
30
37
  const writer = new php_writer_1.PHPWriter();
@@ -21,6 +21,7 @@ class WPMLConfigBuilderPlugin {
21
21
  this.destDir = destDir;
22
22
  }
23
23
  apply(compiler) {
24
+ //TODO: Filter by library here as well
24
25
  compiler.hooks.compilation.tap(this.constructor.name, compilation => {
25
26
  compilation.hooks.processAssets.tapPromise({ name: `${this.constructor.name}__processXML`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL }, async (assets) => {
26
27
  const entrypoint = compilation.entrypoints.get("wpml-config.xml");
@@ -115,6 +115,7 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
115
115
  if (!dirent.isDirectory()) {
116
116
  continue;
117
117
  }
118
+ //TODO: Instead of doing all of this in a precalc phase, add block.json "entrypoints" with their library type set to "block-json"
118
119
  const dir = joinPossiblyAbsolutePaths(srcRoot, dirent.name);
119
120
  loadingEntrypoints.push(new Promise(async (resolve) => {
120
121
  const rawEntrypoints = [];
@@ -33,7 +33,7 @@ export declare class PHPWriter {
33
33
  chain?: boolean;
34
34
  return?: boolean;
35
35
  }): this;
36
- return(line: string | Expr): this;
36
+ return(expression: unknown | Expr): this;
37
37
  static(variable: string, opts?: {
38
38
  initializer?: unknown | Expr;
39
39
  withTest?: boolean | 'chainable';
@@ -65,8 +65,8 @@ class PHPWriter {
65
65
  lineComponents.push(Expr.convertJsonToPHP(expression));
66
66
  return this.append(!opts.chain ? lineComponents.join(" ") + ';' : lineComponents.join(" "));
67
67
  }
68
- return(line) {
69
- return this.append(`return ${line};`);
68
+ return(expression) {
69
+ return this.append(`return ${Expr.convertJsonToPHP(expression)};`);
70
70
  }
71
71
  static(variable, opts = {}) {
72
72
  const initializer = opts.initializer ? Expr.convertJsonToPHP(opts.initializer) : "null";
@@ -497,7 +497,7 @@ function makeBlocksWebpackConfig(config, commonConfig, webpackConfig, dest, src,
497
497
  return (0, common_config_helpers_1.commonMakeWebpackConfig)(config, commonConfig, webpackConfig, true, dest, src, srcRoot, (0, common_config_helpers_1.resolveEntryFromDirectory)(commonConfig, srcRoot, dest), plugins);
498
498
  }
499
499
  function makeExtensionsWebpackConfig(config, commonConfig, webpackConfig, dest, src, srcRoot, plugins) {
500
- plugins.push(new ExtensionsConfigFileGeneratorPlugin_1.ExtensionsConfigFileGeneratorPlugin(srcRoot, config.extensionsVersion, dest.destination, config.plainEntrypointsHandlePrefix));
500
+ plugins.push(new ExtensionsConfigFileGeneratorPlugin_1.ExtensionsConfigFileGeneratorPlugin(config, srcRoot, dest.destination));
501
501
  const entry = async () => {
502
502
  const rawEntrypoints = [];
503
503
  for await (const dirent of await promises_1.default.opendir(srcRoot)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plaudit/webpack-extensions",
3
- "version": "2.58.1",
3
+ "version": "2.58.3",
4
4
  "license": "UNLICENSED",
5
5
  "files": [
6
6
  "/build"
@@ -18,7 +18,7 @@
18
18
  "devDependencies": {
19
19
  "@plaudit/gutenberg-api-extensions": "^2.75.0",
20
20
  "@types/browser-sync-webpack-plugin": "^2.2.5",
21
- "@types/node": "^22.17.1",
21
+ "@types/node": "^24.3.0",
22
22
  "@types/postcss-functions": "^4.0.4",
23
23
  "@types/tapable": "^2.2.7",
24
24
  "@types/webpack": "^5.28.5",
@@ -35,8 +35,8 @@
35
35
  "@plaudit/postcss-silent-extend": "^3.0.0",
36
36
  "@plaudit/postcss-strip-units": "^3.0.0",
37
37
  "@plaudit/postcss-variables": "^1.1.0",
38
- "@wordpress/dependency-extraction-webpack-plugin": "^6.28.0",
39
- "@wordpress/scripts": "^30.21.0",
38
+ "@wordpress/dependency-extraction-webpack-plugin": "^6.29.0",
39
+ "@wordpress/scripts": "^30.22.0",
40
40
  "autoprefixer": "^10.4.21",
41
41
  "browser-sync": "^3.0.4",
42
42
  "clean-webpack-plugin": "^4.0.0",
@@ -63,7 +63,7 @@
63
63
  "postcss-url": "^10.1.3",
64
64
  "react": "^18.3.1",
65
65
  "react-dom": "^18.3.1",
66
- "webpack": "^5.101.2",
66
+ "webpack": "^5.101.3",
67
67
  "webpack-remove-empty-scripts": "^1.1.1",
68
68
  "xml-formatter": "^3.6.6"
69
69
  },