@plaudit/webpack-extensions 2.38.0 → 2.40.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.
@@ -2,6 +2,7 @@ import { type Compiler, type WebpackPluginInstance } from "webpack";
2
2
  export default class AdditionalDependencyInjectorPlugin implements WebpackPluginInstance {
3
3
  private readonly entrypointAdditionalDependencies;
4
4
  private readonly processingModules;
5
- constructor(entrypointAdditionalDependencies: string[], processingModules: boolean);
5
+ private readonly addExternalizedDep;
6
+ constructor(entrypointAdditionalDependencies: string[], processingModules: boolean, addExternalizedDep: (dep: string) => void);
6
7
  apply(compiler: Compiler): void;
7
8
  }
@@ -8,53 +8,46 @@ const webpack_1 = require("webpack");
8
8
  class AdditionalDependencyInjectorPlugin {
9
9
  entrypointAdditionalDependencies;
10
10
  processingModules;
11
- constructor(entrypointAdditionalDependencies, processingModules) {
11
+ addExternalizedDep;
12
+ constructor(entrypointAdditionalDependencies, processingModules, addExternalizedDep) {
12
13
  this.entrypointAdditionalDependencies = entrypointAdditionalDependencies;
13
14
  this.processingModules = processingModules;
15
+ this.addExternalizedDep = addExternalizedDep;
14
16
  }
15
17
  apply(compiler) {
16
18
  compiler.hooks.thisCompilation.tap("AdditionalDependencyInjectorPlugin", compilation => {
17
19
  compilation.hooks.processAssets.tap({
18
- name: "AdditionalDependencyInjectorPlugin_ProcessAssets",
19
- stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ANALYSE
20
- }, compilationAssets => {
21
- const usableEntrypointTest = this.processingModules ? /\.mtsx?$/ : /\.tsx?$/;
22
- const assetSources = new Map();
20
+ name: "AdditionalDependencyInjectorPlugin_ProcessAssets_AddFakeModules",
21
+ stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
22
+ }, () => {
23
+ const usableEntrypointTest = this.processingModules ? /\.m[jt]sx?$/i : /\.[jt]sx?$/i;
23
24
  for (const entrypoint of compilation.entrypoints.values()) {
24
25
  const req = entrypoint.origins.filter(origin => usableEntrypointTest.test(origin.request))[0]?.request;
25
- if (req) {
26
- for (const chunk of entrypoint.chunks) {
27
- for (const file of chunk.files) {
28
- if (file.endsWith('.asset.php')) {
29
- assetSources.set(file, req);
30
- }
31
- }
32
- }
26
+ if (!req) {
27
+ continue;
28
+ }
29
+ const additionalDependencies = [...this.entrypointAdditionalDependencies];
30
+ const firstLine = node_fs_1.default.readFileSync(req, 'utf8').trim().split(/\r?\n/)[0];
31
+ if (firstLine?.startsWith("//ADDITIONAL_DEPENDENCIES:")) {
32
+ additionalDependencies.push(...firstLine.substring(26).trim().split(',').map(dep => dep.trim()));
33
+ }
34
+ const chunk = entrypoint.getEntrypointChunk();
35
+ for (const additionalDep of additionalDependencies) {
36
+ this.addExternalizedDep(additionalDep);
37
+ compilation.chunkGraph.connectChunkAndModule(chunk, new webpack_1.ExternalModule("__REMOVE_ME__", "", additionalDep));
33
38
  }
34
39
  }
35
- for (const [name, asset] of Object.entries(compilationAssets)) {
36
- if (name.endsWith(".asset.php") && asset.constructor.name === 'RawSource') {
37
- const assetSource = assetSources.get(name);
38
- if (!assetSource) {
39
- continue;
40
- }
41
- const additionalDependencies = [...this.entrypointAdditionalDependencies];
42
- const firstLine = node_fs_1.default.readFileSync(assetSource, 'utf8').trim().split(/\r?\n/)[0];
43
- if (firstLine?.startsWith("//ADDITIONAL_DEPENDENCIES:")) {
44
- additionalDependencies.push(...firstLine.substring(26).trim().split(',').map(dep => dep.trim()));
45
- }
46
- if (additionalDependencies.length > 0) {
47
- const seen = new Set();
48
- const additionalDeps = additionalDependencies.filter(dep => !seen.has(dep) && seen.add(dep)).sort().map(v => `'${v}'`).join(', ');
49
- if (additionalDeps.length > 0) {
50
- compilation.updateAsset(name, new webpack_1.sources.RawSource(asset.source().toString()
51
- .replaceAll(/(?:, )?'wp-[^']+\/[^']+'/gi, '')
52
- .replace(/('dependencies'\s+=>\s+(?:array\(|\[))(.*)([)\]], 'version')/g, (match, g1, g2, g3) => `${g1}${g2.length > 0 ? `${g2}, ${additionalDeps}` : additionalDeps}${g3}`)));
53
- continue;
54
- }
40
+ });
41
+ compilation.hooks.processAssets.tap({
42
+ name: "AdditionalDependencyInjectorPlugin_ProcessAssets_RemoveFakeModules",
43
+ stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_REPORT
44
+ }, () => {
45
+ for (const entrypoint of compilation.entrypoints.values()) {
46
+ const entrypointChunk = entrypoint.getEntrypointChunk();
47
+ for (const module of compilation.chunkGraph.getChunkModules(entrypointChunk)) {
48
+ if (module instanceof webpack_1.ExternalModule && module.request === '__REMOVE_ME__') {
49
+ compilation.chunkGraph.disconnectChunkAndModule(entrypointChunk, module);
55
50
  }
56
- compilation.updateAsset(name, new webpack_1.sources.RawSource(asset.source().toString()
57
- .replaceAll(/(?:, )?'wp-[^']+\/[^']+'/gi, '')));
58
51
  }
59
52
  }
60
53
  });
@@ -1,14 +1,18 @@
1
- import { type Compilation, type Compiler, type WebpackPluginInstance } from "webpack";
1
+ import { Compilation, type Compiler, type WebpackPluginInstance } from "webpack";
2
2
  export default class BlockJSONManagingPlugin implements WebpackPluginInstance {
3
3
  private readonly standaloneBlocks;
4
4
  private readonly processingModules;
5
5
  static readonly mappableModuleKeys: readonly ["viewScriptModule", "scriptModule"];
6
6
  static readonly mappableNonModuleKeys: readonly ["editorStyle", "style", "viewStyle", "editorScript", "script", "viewScript"];
7
+ private static readonly styleExtensionPattern;
8
+ private static readonly scriptExtensionPattern;
7
9
  private static readonly mappableKeys;
8
10
  private static readonly blockJsonToEntrypointsMap;
9
11
  private static readonly blockJsonRawDependenciesMap;
10
12
  private static readonly blockJSONAssetSourceDirs;
11
13
  private static readonly blockJsonAssetKeyMapping;
14
+ private static readonly blockJsonAssetKeyReadinessMapping;
15
+ readonly additionalMetadata: Map<string, any>;
12
16
  constructor(standaloneBlocks: boolean, processingModules: boolean);
13
17
  static recordRawDependency(entrypoint: string, dependency: string): void;
14
18
  static recordBlockJSONAssetSourceDir(entrypoint: string, source: string): void;
@@ -24,4 +28,9 @@ export default class BlockJSONManagingPlugin implements WebpackPluginInstance {
24
28
  private static remapReferencedAssetFile;
25
29
  private static getReferencedFileSlot;
26
30
  private static addAssetToBlockJsonKey;
31
+ private registerAssetProcessor;
32
+ private static populateEntrypointsMap;
33
+ private registerBlockJsonProcessor;
34
+ private static normalizeRenderTemplate;
35
+ private static getSyncs;
27
36
  }
@@ -13,11 +13,15 @@ class BlockJSONManagingPlugin {
13
13
  processingModules;
14
14
  static mappableModuleKeys = ["viewScriptModule", "scriptModule"];
15
15
  static mappableNonModuleKeys = ["editorStyle", "style", "viewStyle", "editorScript", "script", "viewScript"];
16
+ static styleExtensionPattern = /\.(p?c|sa)ss$/i;
17
+ static scriptExtensionPattern = /\.m?[tj]sx?$/i;
16
18
  static mappableKeys = [...BlockJSONManagingPlugin.mappableNonModuleKeys, ...BlockJSONManagingPlugin.mappableModuleKeys];
17
19
  static blockJsonToEntrypointsMap = new Map();
18
20
  static blockJsonRawDependenciesMap = new Map();
19
21
  static blockJSONAssetSourceDirs = new Map();
20
22
  static blockJsonAssetKeyMapping = new Map();
23
+ static blockJsonAssetKeyReadinessMapping = new Map();
24
+ additionalMetadata = new Map();
21
25
  constructor(standaloneBlocks, processingModules) {
22
26
  this.standaloneBlocks = standaloneBlocks;
23
27
  this.processingModules = processingModules;
@@ -34,171 +38,11 @@ class BlockJSONManagingPlugin {
34
38
  }
35
39
  apply(compiler) {
36
40
  compiler.hooks.compilation.tap(this.constructor.name, compilation => {
37
- compilation.hooks.afterProcessAssets.tap(`${this.constructor.name}_ProcessBlockJSONFiles`, compilationAssets => {
38
- const testableCompilationAssets = this.processingModules ? BlockJSONManagingPlugin.buildFakeCompilationAssets(compilation) : compilationAssets;
39
- const currentBlockJSONAssets = BlockJSONManagingPlugin.blockJSONAssetSourceDirs.entries()
40
- .filter(([name]) => name in testableCompilationAssets)
41
- .toArray();
42
- for (const [name] of currentBlockJSONAssets) {
43
- const dependencies = BlockJSONManagingPlugin.blockJsonRawDependenciesMap.get(name);
44
- if (dependencies) {
45
- for (const dependency of dependencies) {
46
- const entrypoint = compilation.entrypoints.get(dependency);
47
- if (!entrypoint) {
48
- continue;
49
- }
50
- const srcPath = entrypoint.origins.map(origin => origin.request)[0];
51
- if (!srcPath) {
52
- continue;
53
- }
54
- const destPath = BlockJSONManagingPlugin.resolveDestinationBySourceExtension(srcPath, entrypoint);
55
- if (!destPath) {
56
- continue;
57
- }
58
- const entrypointChunk = entrypoint.getEntrypointChunk();
59
- const additionalFiles = [];
60
- for (const entrypointChunkFile of entrypointChunk.files) {
61
- if (!entrypointChunkFile.endsWith(".asset.php") && entrypointChunkFile !== destPath) {
62
- additionalFiles.push(entrypointChunkFile);
63
- }
64
- }
65
- const entryMeta = { hash: entrypointChunk.hash ?? destPath, path: destPath };
66
- const currentEntrypoints = BlockJSONManagingPlugin.blockJsonToEntrypointsMap.get(name);
67
- if (currentEntrypoints) {
68
- currentEntrypoints.set(srcPath, [entryMeta, additionalFiles]);
69
- }
70
- else {
71
- BlockJSONManagingPlugin.blockJsonToEntrypointsMap.set(name, new Map([[srcPath, [entryMeta, additionalFiles]]]));
72
- }
73
- }
74
- }
75
- }
76
- //TODO: Fix modules support when running in non-dev mode
77
- const blockDirConfigData = {};
78
- for (const [name, sourceDir] of currentBlockJSONAssets) {
79
- const assetContents = this.processingModules ? node_fs_1.default.readFileSync(testableCompilationAssets[name], 'utf8') : compilation.assets[name]?.buffer().toString();
80
- if (!assetContents) {
81
- continue;
82
- }
83
- const json = JSON.parse(assetContents);
84
- const currentAssetKeyMappings = { directMappings: {}, referencedFiles: {}, compositeHash: "" };
85
- for (const mappableKey of BlockJSONManagingPlugin[this.processingModules ? 'mappableModuleKeys' : 'mappableNonModuleKeys']) {
86
- if (mappableKey in json) {
87
- const unmappedValue = json[mappableKey];
88
- if (Array.isArray(unmappedValue)) {
89
- for (const uv of unmappedValue) {
90
- BlockJSONManagingPlugin.incorporateRemappedAsset(currentAssetKeyMappings, mappableKey, ...BlockJSONManagingPlugin.remapReferencedAssetFile(uv, name));
91
- }
92
- }
93
- else if (typeof unmappedValue === 'string') {
94
- BlockJSONManagingPlugin.incorporateRemappedAsset(currentAssetKeyMappings, mappableKey, ...BlockJSONManagingPlugin.remapReferencedAssetFile(unmappedValue, name));
95
- }
96
- }
97
- }
98
- const assetKeyMappings = { ...BlockJSONManagingPlugin.blockJsonAssetKeyMapping.get(name), [this.processingModules ? 'module' : 'nonModule']: currentAssetKeyMappings };
99
- BlockJSONManagingPlugin.blockJsonAssetKeyMapping.set(name, assetKeyMappings);
100
- let compositeHash = "";
101
- const condensedBlockJsonAssetKeyMappings = {};
102
- for (const subType of ['nonModule', 'module']) {
103
- const mappings = assetKeyMappings[subType];
104
- if (mappings) {
105
- compositeHash += mappings.compositeHash;
106
- for (const mappableKey of BlockJSONManagingPlugin.mappableKeys) {
107
- if (mappings.directMappings[mappableKey]) {
108
- BlockJSONManagingPlugin.addAssetToBlockJsonKey(condensedBlockJsonAssetKeyMappings, mappableKey, mappings.directMappings[mappableKey]);
109
- }
110
- }
111
- for (const [referenceLocation, prefix] of [["editor", "editorS"], ["both", "s"], ["view", "viewS"]]) {
112
- if (mappings.referencedFiles[referenceLocation]) {
113
- for (const referencedFile of mappings.referencedFiles[referenceLocation]) {
114
- if (referencedFile.endsWith(".css")) {
115
- BlockJSONManagingPlugin.addAssetToBlockJsonKey(condensedBlockJsonAssetKeyMappings, `${prefix}tyle`, referencedFile);
116
- }
117
- else if (referencedFile.endsWith(".js")) {
118
- BlockJSONManagingPlugin.addAssetToBlockJsonKey(condensedBlockJsonAssetKeyMappings, `${prefix}cript`, referencedFile);
119
- }
120
- else if (referencedFile.endsWith(".mjs")) {
121
- BlockJSONManagingPlugin.addAssetToBlockJsonKey(condensedBlockJsonAssetKeyMappings, `${prefix}criptModule`, referencedFile);
122
- }
123
- }
124
- }
125
- }
126
- }
127
- }
128
- for (const mappableKey of BlockJSONManagingPlugin.mappableKeys) {
129
- if (mappableKey in condensedBlockJsonAssetKeyMappings) {
130
- json[mappableKey] = condensedBlockJsonAssetKeyMappings[mappableKey];
131
- }
132
- else {
133
- delete json[mappableKey];
134
- }
135
- }
136
- if (json["version"]) {
137
- json["version"] = `${json["version"]}-${BlockJSONManagingPlugin.hashThingForAsset(compositeHash)}`;
138
- }
139
- else {
140
- json["version"] = BlockJSONManagingPlugin.hashThingForAsset(compositeHash);
141
- }
142
- const outputDir = node_path_1.default.join(compiler.outputPath, node_path_1.default.dirname(name));
143
- const pathsNeedRemapping = !this.standaloneBlocks && json["plaudit"] !== "simple";
144
- BlockJSONManagingPlugin.remapReferencedPHPFilesOnKey(json, "setup", pathsNeedRemapping, sourceDir, outputDir, compilation, true);
145
- BlockJSONManagingPlugin.remapReferencedPHPFilesOnKey(json, "variations", pathsNeedRemapping, sourceDir, outputDir, compilation, false);
146
- if (json["acf"]) {
147
- if (json["acf"]["renderTemplate"]) {
148
- json["render_template"] = json["acf"]["renderTemplate"];
149
- delete json["acf"]["renderTemplate"];
150
- }
151
- else if (json["acf"]["render_template"]) {
152
- json["render_template"] = json["acf"]["render_template"];
153
- delete json["acf"]["render_template"];
154
- }
155
- }
156
- const blockName = json["name"]?.toString() || "non-existent/block-name";
157
- let rawRenderTemplate = json["render"] ?? json["render_template"];
158
- rawRenderTemplate = (rawRenderTemplate
159
- ? (typeof rawRenderTemplate === 'string' ? [rawRenderTemplate] : rawRenderTemplate)
160
- : [`${blockName.substring(blockName.indexOf('/') + 1)}.php`, "template.php", "template.twig"]);
161
- const renderTemplate = pathsNeedRemapping
162
- ? rawRenderTemplate
163
- .map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p))))
164
- .filter(p => node_fs_1.default.existsSync(p))
165
- .map(p => `file:./${BlockJSONManagingPlugin.findRelativeRouteBetween(outputDir, p)}`)
166
- : rawRenderTemplate
167
- .filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p)))));
168
- if (renderTemplate.length === 0) {
169
- delete json["render_template"];
170
- delete json["render"];
171
- }
172
- else {
173
- let validTemplateLocation, invalidTemplateLocation;
174
- if (json["acf"] || (json["plaudit"] && (json["plaudit"] !== "native" && (typeof json["plaudit"] !== 'object' || json["plaudit"]?.["type"] !== "native")))) {
175
- // ACF-like blocks need to have the template stored in render_template.
176
- // Because we can statically detect ACF-like blocks, we can make the move here instead of at run-time.
177
- validTemplateLocation = "render_template";
178
- invalidTemplateLocation = "render";
179
- }
180
- else {
181
- validTemplateLocation = "render";
182
- invalidTemplateLocation = "render_template";
183
- }
184
- delete json[invalidTemplateLocation];
185
- if (renderTemplate.length > 1) {
186
- const error = new webpack_1.WebpackError("Encountered a block with multiple possible render files");
187
- error.file = node_path_1.default.join(sourceDir, 'block.json');
188
- compilation.warnings.push(error);
189
- json[validTemplateLocation] = renderTemplate.find(p => p.endsWith(".php")) ?? renderTemplate[0];
190
- }
191
- else {
192
- json[validTemplateLocation] = renderTemplate[0];
193
- }
194
- }
195
- compilation[name in compilation.assets ? 'updateAsset' : 'emitAsset'](name, new webpack_1.sources.RawSource(JSON.stringify(json, undefined, " ")));
196
- blockDirConfigData[node_path_1.default.dirname(name)] = json;
197
- }
198
- const sortedBlockDirConfigData = Object.fromEntries([["__metadata", { version: 1 }], ...Object.entries(blockDirConfigData)
199
- .sort(([a], [b]) => a.localeCompare(b))]);
200
- compilation.emitAsset("blockdir.config", new webpack_1.sources.RawSource((0, php_serializer_1.default)(sortedBlockDirConfigData, { excludedKeys: ["$schema"] })));
201
- });
41
+ this.additionalMetadata.clear();
42
+ this.registerAssetProcessor(compilation);
43
+ if (!this.processingModules) {
44
+ this.registerBlockJsonProcessor(compilation);
45
+ }
202
46
  });
203
47
  }
204
48
  static resolveDestinationBySourceExtension(srcPath, entrypoint) {
@@ -331,7 +175,15 @@ class BlockJSONManagingPlugin {
331
175
  const prefix = value.startsWith("./", 5) ? "./" : "";
332
176
  const relativePath = node_path_1.default.relative(node_path_1.default.dirname(name), output.path);
333
177
  const res = [`file:${prefix}${relativePath}`, output.hash];
334
- return [res, additionalFiles.map(additionalFile => `file:./${node_path_1.default.relative(node_path_1.default.dirname(name), additionalFile)}`)];
178
+ if (BlockJSONManagingPlugin.styleExtensionPattern.test(output.path)) {
179
+ return [res,
180
+ additionalFiles.filter(additionalFile => !BlockJSONManagingPlugin.scriptExtensionPattern.test(additionalFile))
181
+ .map(additionalFile => `file:./${node_path_1.default.relative(node_path_1.default.dirname(name), additionalFile)}`)
182
+ ];
183
+ }
184
+ else {
185
+ return [res, additionalFiles.map(additionalFile => `file:./${node_path_1.default.relative(node_path_1.default.dirname(name), additionalFile)}`)];
186
+ }
335
187
  }
336
188
  }
337
189
  return [[value, ""], []];
@@ -373,5 +225,279 @@ class BlockJSONManagingPlugin {
373
225
  }
374
226
  }
375
227
  }
228
+ registerAssetProcessor(compilation) {
229
+ const tapName = { name: `${this.constructor.name}_ProcessBlockJSONFiles`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_DERIVED };
230
+ compilation.hooks.processAssets.tapPromise(tapName, async (compilationAssets) => {
231
+ const testableCompilationAssets = this.processingModules ? BlockJSONManagingPlugin.buildFakeCompilationAssets(compilation) : compilationAssets;
232
+ const currentBlockJSONAssets = BlockJSONManagingPlugin.blockJSONAssetSourceDirs.entries()
233
+ .filter(([name]) => name in testableCompilationAssets)
234
+ .toArray();
235
+ BlockJSONManagingPlugin.populateEntrypointsMap(currentBlockJSONAssets, compilation);
236
+ await Promise.all(currentBlockJSONAssets.map(async ([name]) => {
237
+ const assetContents = this.processingModules ? node_fs_1.default.readFileSync(testableCompilationAssets[name], 'utf8') : compilation.assets[name]?.buffer().toString();
238
+ if (!assetContents) {
239
+ return;
240
+ }
241
+ const json = JSON.parse(assetContents);
242
+ const currentAssetKeyMappings = { directMappings: {}, referencedFiles: {}, compositeHash: "" };
243
+ for (const mappableKey of BlockJSONManagingPlugin[this.processingModules ? 'mappableModuleKeys' : 'mappableNonModuleKeys']) {
244
+ if (mappableKey in json) {
245
+ const unmappedValue = json[mappableKey];
246
+ if (Array.isArray(unmappedValue)) {
247
+ for (const uv of unmappedValue) {
248
+ BlockJSONManagingPlugin.incorporateRemappedAsset(currentAssetKeyMappings, mappableKey, ...BlockJSONManagingPlugin.remapReferencedAssetFile(uv, name));
249
+ }
250
+ }
251
+ else if (typeof unmappedValue === 'string') {
252
+ BlockJSONManagingPlugin.incorporateRemappedAsset(currentAssetKeyMappings, mappableKey, ...BlockJSONManagingPlugin.remapReferencedAssetFile(unmappedValue, name));
253
+ }
254
+ }
255
+ }
256
+ const syncs = BlockJSONManagingPlugin.getSyncs(name);
257
+ let assetKeyMappings = BlockJSONManagingPlugin.blockJsonAssetKeyMapping.get(name);
258
+ if (!assetKeyMappings) {
259
+ BlockJSONManagingPlugin.blockJsonAssetKeyMapping.set(name, assetKeyMappings = {});
260
+ }
261
+ assetKeyMappings[this.processingModules ? 'module' : 'nonModule'] = currentAssetKeyMappings;
262
+ if (this.processingModules) {
263
+ syncs.module.resolve();
264
+ if (!BlockJSONManagingPlugin.mappableNonModuleKeys.some(key => key in json)) {
265
+ syncs.nonModule.resolve();
266
+ }
267
+ await syncs.nonModule.sync;
268
+ }
269
+ else {
270
+ syncs.nonModule.resolve();
271
+ if (!BlockJSONManagingPlugin.mappableModuleKeys.some(key => key in json)) {
272
+ syncs.module.resolve();
273
+ }
274
+ await syncs.module.sync;
275
+ }
276
+ }));
277
+ });
278
+ }
279
+ static populateEntrypointsMap(currentBlockJSONAssets, compilation) {
280
+ for (const [name] of currentBlockJSONAssets) {
281
+ const dependencies = BlockJSONManagingPlugin.blockJsonRawDependenciesMap.get(name);
282
+ if (dependencies) {
283
+ for (const dependency of dependencies) {
284
+ const entrypoint = compilation.entrypoints.get(dependency);
285
+ if (!entrypoint) {
286
+ continue;
287
+ }
288
+ const srcPath = entrypoint.origins.map(origin => origin.request)[0];
289
+ if (!srcPath) {
290
+ continue;
291
+ }
292
+ const destPath = BlockJSONManagingPlugin.resolveDestinationBySourceExtension(srcPath, entrypoint);
293
+ if (!destPath) {
294
+ continue;
295
+ }
296
+ const entrypointChunk = entrypoint.getEntrypointChunk();
297
+ const additionalFiles = [];
298
+ for (const entrypointChunkFile of entrypointChunk.files) {
299
+ if (!entrypointChunkFile.endsWith(".asset.php") && entrypointChunkFile !== destPath) {
300
+ additionalFiles.push(entrypointChunkFile);
301
+ }
302
+ }
303
+ const entryMeta = { hash: entrypointChunk.hash ?? destPath, path: destPath };
304
+ const currentEntrypoints = BlockJSONManagingPlugin.blockJsonToEntrypointsMap.get(name);
305
+ if (currentEntrypoints) {
306
+ currentEntrypoints.set(srcPath, [entryMeta, additionalFiles]);
307
+ }
308
+ else {
309
+ BlockJSONManagingPlugin.blockJsonToEntrypointsMap.set(name, new Map([[srcPath, [entryMeta, additionalFiles]]]));
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
315
+ registerBlockJsonProcessor(compilation) {
316
+ const blockDirConfigData = {};
317
+ compilation.hooks.afterProcessAssets.tap(`${this.constructor.name}_GenerateMetadata`, compilationAssets => {
318
+ const currentBlockJSONAssets = BlockJSONManagingPlugin.blockJSONAssetSourceDirs.entries()
319
+ .filter(([name]) => name in compilationAssets)
320
+ .toArray();
321
+ for (const [name, sourceDir] of currentBlockJSONAssets) {
322
+ const assetKeyMappings = BlockJSONManagingPlugin.blockJsonAssetKeyMapping.get(name);
323
+ let compositeHash = "";
324
+ const condensedBlockJsonAssetKeyMappings = {};
325
+ for (const subType of ['nonModule', 'module']) {
326
+ const mappings = assetKeyMappings[subType];
327
+ if (mappings) {
328
+ compositeHash += mappings.compositeHash;
329
+ for (const mappableKey of BlockJSONManagingPlugin.mappableKeys) {
330
+ if (mappings.directMappings[mappableKey]) {
331
+ BlockJSONManagingPlugin.addAssetToBlockJsonKey(condensedBlockJsonAssetKeyMappings, mappableKey, mappings.directMappings[mappableKey]);
332
+ }
333
+ }
334
+ for (const [referenceLocation, prefix] of [["editor", "editorS"], ["both", "s"], ["view", "viewS"]]) {
335
+ if (mappings.referencedFiles[referenceLocation]) {
336
+ for (const referencedFile of mappings.referencedFiles[referenceLocation]) {
337
+ if (referencedFile.endsWith(".css")) {
338
+ BlockJSONManagingPlugin.addAssetToBlockJsonKey(condensedBlockJsonAssetKeyMappings, `${prefix}tyle`, referencedFile);
339
+ }
340
+ else if (referencedFile.endsWith(".js")) {
341
+ BlockJSONManagingPlugin.addAssetToBlockJsonKey(condensedBlockJsonAssetKeyMappings, `${prefix}cript`, referencedFile);
342
+ }
343
+ else if (referencedFile.endsWith(".mjs")) {
344
+ BlockJSONManagingPlugin.addAssetToBlockJsonKey(condensedBlockJsonAssetKeyMappings, `${prefix}criptModule`, referencedFile);
345
+ }
346
+ }
347
+ }
348
+ }
349
+ }
350
+ }
351
+ const assetContents = compilation.assets[name]?.buffer().toString();
352
+ if (!assetContents) {
353
+ continue;
354
+ }
355
+ const json = JSON.parse(assetContents);
356
+ for (const mappableKey of BlockJSONManagingPlugin.mappableKeys) {
357
+ if (mappableKey in condensedBlockJsonAssetKeyMappings) {
358
+ json[mappableKey] = condensedBlockJsonAssetKeyMappings[mappableKey];
359
+ }
360
+ else {
361
+ delete json[mappableKey];
362
+ }
363
+ }
364
+ if (json["version"]) {
365
+ json["version"] = `${json["version"]}-${BlockJSONManagingPlugin.hashThingForAsset(compositeHash)}`;
366
+ }
367
+ else {
368
+ json["version"] = BlockJSONManagingPlugin.hashThingForAsset(compositeHash);
369
+ }
370
+ const outputDir = node_path_1.default.join(compilation.compiler.outputPath, node_path_1.default.dirname(name));
371
+ const pathsNeedRemapping = !this.standaloneBlocks && json["plaudit"] !== "simple";
372
+ BlockJSONManagingPlugin.remapReferencedPHPFilesOnKey(json, "setup", pathsNeedRemapping, sourceDir, outputDir, compilation, true);
373
+ BlockJSONManagingPlugin.remapReferencedPHPFilesOnKey(json, "variations", pathsNeedRemapping, sourceDir, outputDir, compilation, false);
374
+ BlockJSONManagingPlugin.normalizeRenderTemplate(json, pathsNeedRemapping, sourceDir, outputDir, compilation);
375
+ compilation[name in compilation.assets ? 'updateAsset' : 'emitAsset'](name, new webpack_1.sources.RawSource(JSON.stringify(json, undefined, " ")));
376
+ blockDirConfigData[node_path_1.default.dirname(name)] = json;
377
+ }
378
+ let sortedBlockDirConfigData;
379
+ const blockDirConfigs = Object.entries(blockDirConfigData).sort(([a], [b]) => a.localeCompare(b));
380
+ const rawAssetDataSource = compilation.assets["assets.json"]?.source();
381
+ if (typeof rawAssetDataSource === 'string') {
382
+ const scriptHandles = {};
383
+ const styleHandles = {};
384
+ const rawAssetData = JSON.parse(rawAssetDataSource);
385
+ const mappableKeys = [...BlockJSONManagingPlugin.mappableModuleKeys, ...BlockJSONManagingPlugin.mappableNonModuleKeys];
386
+ for (const [blockFolder, config] of blockDirConfigs) {
387
+ for (const mappableKey of mappableKeys) {
388
+ const cfg = config[mappableKey];
389
+ if (cfg) {
390
+ if (Array.isArray(cfg)) {
391
+ for (let i = 0; i < cfg.length; i++) {
392
+ const assetDetails = getAssetDetails(blockFolder, cfg[i], rawAssetData);
393
+ if (assetDetails) {
394
+ (assetDetails[0] ? styleHandles : scriptHandles)[assetDetails[1]] = assetDetails[2];
395
+ cfg[i] = assetDetails[1];
396
+ }
397
+ }
398
+ }
399
+ else {
400
+ const assetDetails = getAssetDetails(blockFolder, cfg, rawAssetData);
401
+ if (assetDetails) {
402
+ (assetDetails[0] ? styleHandles : scriptHandles)[assetDetails[1]] = assetDetails[2];
403
+ config[mappableKey] = assetDetails[1];
404
+ }
405
+ }
406
+ }
407
+ }
408
+ }
409
+ sortedBlockDirConfigData = Object.fromEntries([
410
+ ["__metadata", { version: 2, ...Object.fromEntries(this.additionalMetadata.entries()), scriptHandles, styleHandles }],
411
+ ...blockDirConfigs
412
+ ]);
413
+ compilation.deleteAsset("assets.json");
414
+ }
415
+ else {
416
+ sortedBlockDirConfigData = Object.fromEntries([["__metadata", { version: 1, ...Object.fromEntries(this.additionalMetadata.entries()) }], ...blockDirConfigs]);
417
+ }
418
+ compilation.emitAsset("blockdir.config", new webpack_1.sources.RawSource((0, php_serializer_1.default)(sortedBlockDirConfigData, { excludedKeys: ["$schema"] })));
419
+ });
420
+ }
421
+ static normalizeRenderTemplate(json, pathsNeedRemapping, sourceDir, outputDir, compilation) {
422
+ if (json["acf"]) {
423
+ if (json["acf"]["renderTemplate"]) {
424
+ json["render_template"] = json["acf"]["renderTemplate"];
425
+ delete json["acf"]["renderTemplate"];
426
+ }
427
+ else if (json["acf"]["render_template"]) {
428
+ json["render_template"] = json["acf"]["render_template"];
429
+ delete json["acf"]["render_template"];
430
+ }
431
+ }
432
+ const blockName = json["name"]?.toString() || "non-existent/block-name";
433
+ let rawRenderTemplate = json["render"] ?? json["render_template"];
434
+ rawRenderTemplate = (rawRenderTemplate
435
+ ? (typeof rawRenderTemplate === 'string' ? [rawRenderTemplate] : rawRenderTemplate)
436
+ : [`${blockName.substring(blockName.indexOf('/') + 1)}.php`, "template.php", "template.twig"]);
437
+ const renderTemplate = pathsNeedRemapping
438
+ ? rawRenderTemplate
439
+ .map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p))))
440
+ .filter(p => node_fs_1.default.existsSync(p))
441
+ .map(p => `file:./${BlockJSONManagingPlugin.findRelativeRouteBetween(outputDir, p)}`)
442
+ : rawRenderTemplate
443
+ .filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p)))));
444
+ if (renderTemplate.length === 0) {
445
+ delete json["render_template"];
446
+ delete json["render"];
447
+ }
448
+ else {
449
+ let validTemplateLocation, invalidTemplateLocation;
450
+ if (json["acf"] || (json["plaudit"] && (json["plaudit"] !== "native" && (typeof json["plaudit"] !== 'object' || json["plaudit"]?.["type"] !== "native")))) {
451
+ // ACF-like blocks need to have the template stored in render_template.
452
+ // Because we can statically detect ACF-like blocks, we can make the move here instead of at run-time.
453
+ validTemplateLocation = "render_template";
454
+ invalidTemplateLocation = "render";
455
+ }
456
+ else {
457
+ validTemplateLocation = "render";
458
+ invalidTemplateLocation = "render_template";
459
+ }
460
+ delete json[invalidTemplateLocation];
461
+ if (renderTemplate.length > 1) {
462
+ const error = new webpack_1.WebpackError("Encountered a block with multiple possible render files");
463
+ error.file = node_path_1.default.join(sourceDir, 'block.json');
464
+ compilation.warnings.push(error);
465
+ json[validTemplateLocation] = renderTemplate.find(p => p.endsWith(".php")) ?? renderTemplate[0];
466
+ }
467
+ else {
468
+ json[validTemplateLocation] = renderTemplate[0];
469
+ }
470
+ }
471
+ }
472
+ static getSyncs(name) {
473
+ const res = BlockJSONManagingPlugin.blockJsonAssetKeyReadinessMapping.get(name);
474
+ if (res) {
475
+ return res;
476
+ }
477
+ BlockJSONManagingPlugin.blockJsonAssetKeyReadinessMapping.set(name, { nonModule: makeSync(), module: makeSync() });
478
+ return BlockJSONManagingPlugin.blockJsonAssetKeyReadinessMapping.get(name);
479
+ }
376
480
  }
377
481
  exports.default = BlockJSONManagingPlugin;
482
+ function makeSync() {
483
+ const res = { done: false };
484
+ res.sync = new Promise((resolve, reject) => {
485
+ res.resolve = (v) => resolve(v);
486
+ res.reject = () => reject();
487
+ });
488
+ return res;
489
+ }
490
+ function getAssetDetails(blockFolder, asset, rawAssetData) {
491
+ if (!asset.startsWith("file:./")) {
492
+ return undefined;
493
+ }
494
+ const src = `${blockFolder}/${asset.substring(7)}`;
495
+ const isCss = src.endsWith(".css");
496
+ const assetData = isCss
497
+ ? rawAssetData[src.substring(0, src.length - 3) + "js"] ?? rawAssetData[src.substring(0, src.length - 3).replace("style-style", "style") + "js"]
498
+ : rawAssetData[src];
499
+ if (!assetData) {
500
+ return undefined;
501
+ }
502
+ return [isCss, src.substring(0, src.length - (isCss ? 4 : 3)), { src, rest: [assetData.dependencies, assetData.version] }];
503
+ }
@@ -0,0 +1,16 @@
1
+ import { type Compiler, type WebpackPluginInstance } from "webpack";
2
+ import BlockJSONManagingPlugin from "./BlockJSONManagingPlugin";
3
+ export default class WPMLConfigBuilder implements WebpackPluginInstance {
4
+ private readonly blockJSONManagingPlugin;
5
+ private static jsdomInstance?;
6
+ private static domParser?;
7
+ private static xmlSerializer?;
8
+ private readonly parsedDocumentsCache;
9
+ constructor(blockJSONManagingPlugin: BlockJSONManagingPlugin);
10
+ apply(compiler: Compiler): void;
11
+ private static getJSDOMInstance;
12
+ private static getDOMParser;
13
+ private static getXMLSerializer;
14
+ private static prettyPrintXML;
15
+ private loadWPMLConfigXML;
16
+ }