@plaudit/webpack-extensions 2.28.0 → 2.29.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.
@@ -3,11 +3,12 @@ export default class BlockJSONManagingPlugin implements WebpackPluginInstance {
3
3
  private readonly standaloneBlocks;
4
4
  private readonly processingModules;
5
5
  private static readonly sourceToOutputMapping;
6
- private static readonly moduleSourcesToOutputs;
6
+ private static readonly blockJsonToEntrypointsMap;
7
+ private static readonly blockJSONAssetSources;
7
8
  constructor(standaloneBlocks: boolean, processingModules: boolean);
8
9
  apply(compiler: Compiler): void;
9
- findCommonAncestor(...paths: string[]): string[];
10
- findRelativeRouteBetween(path1: string, path2: string): string;
10
+ static findCommonAncestor(...paths: string[]): string[];
11
+ static findRelativeRouteBetween(path1: string, path2: string): string;
11
12
  private static hashThingForAsset;
12
- private static resolveFilesFromStats;
13
+ private static stripFilePrefix;
13
14
  }
@@ -12,186 +12,205 @@ class BlockJSONManagingPlugin {
12
12
  standaloneBlocks;
13
13
  processingModules;
14
14
  static sourceToOutputMapping = new Map();
15
- static moduleSourcesToOutputs = new Map();
15
+ static blockJsonToEntrypointsMap = new Map();
16
+ static blockJSONAssetSources = new Map();
16
17
  constructor(standaloneBlocks, processingModules) {
17
18
  this.standaloneBlocks = standaloneBlocks;
18
19
  this.processingModules = processingModules;
19
20
  }
20
21
  apply(compiler) {
21
- compiler.hooks.compilation.tap("BlockJSONManagingPlugin", compilation => {
22
- compilation.hooks.afterProcessAssets.tap("BlockJSONStyleRemappingPlugin_ProcessAssets", compilationAssets => {
23
- let assetSourceFilesCache = undefined;
24
- let singleFileInputToOutputNameAndHashCache = undefined;
25
- const sourceFileMappers = () => {
26
- if (singleFileInputToOutputNameAndHashCache === undefined || assetSourceFilesCache === undefined) {
27
- const stats = compilation.getStats().toJson({
28
- hash: true,
29
- publicPath: true,
30
- assets: true,
31
- moduleAssets: true,
32
- chunks: true,
33
- modules: true,
34
- source: true,
35
- errorDetails: false,
36
- timings: false
37
- });
38
- if (!stats.assets) {
39
- throw new Error("Stats did not include assets despite them being requested");
22
+ compiler.hooks.compilation.tap(this.constructor.name, compilation => {
23
+ compilation.hooks.processAssets.tap({ name: this.constructor.name, stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ANALYSE }, () => {
24
+ for (const blockEntrypoint of compilation.entrypoints.values()) {
25
+ if (blockEntrypoint.name?.endsWith("/block.json")) {
26
+ const source = blockEntrypoint.origins.map(origin => origin.request)[0];
27
+ const name = blockEntrypoint.getEntrypointChunk().name;
28
+ if (!source || !name) {
29
+ continue;
40
30
  }
41
- if (!stats.modules) {
42
- throw new Error("Stats did not include modules despite them being requested");
31
+ BlockJSONManagingPlugin.blockJSONAssetSources.set(name, source);
32
+ const dependencies = blockEntrypoint.getEntrypointChunk().getEntryOptions()?.dependOn;
33
+ if (dependencies) {
34
+ for (const dependency of dependencies) {
35
+ const entrypoint = compilation.entrypoints.get(dependency);
36
+ if (!entrypoint) {
37
+ continue;
38
+ }
39
+ const srcPath = entrypoint.origins.map(origin => origin.request)[0];
40
+ if (!srcPath) {
41
+ continue;
42
+ }
43
+ const destPath = /m?[jt]sx?$/i.test(node_path_1.default.extname(srcPath))
44
+ ? entrypoint.getFiles().find(file => file.endsWith(".mjs")) ?? entrypoint.getFiles().find(file => file.endsWith(".js"))
45
+ : entrypoint.getFiles().find(file => file.endsWith(".css"));
46
+ if (!destPath) {
47
+ continue;
48
+ }
49
+ const entryMeta = { hash: entrypoint.getEntrypointChunk().hash ?? destPath, path: destPath };
50
+ const currentEntrypoints = BlockJSONManagingPlugin.blockJsonToEntrypointsMap.get(name);
51
+ if (currentEntrypoints) {
52
+ currentEntrypoints.set(srcPath, entryMeta);
53
+ }
54
+ else {
55
+ BlockJSONManagingPlugin.blockJsonToEntrypointsMap.set(name, new Map([[srcPath, entryMeta]]));
56
+ }
57
+ }
43
58
  }
44
- singleFileInputToOutputNameAndHashCache = BlockJSONManagingPlugin.resolveFilesFromStats(compilationAssets, stats);
45
- assetSourceFilesCache = new Map(stats.assets
46
- .map(asset => [asset.name, asset.info?.sourceFilename])
47
- .filter((v) => v[0] !== undefined && v[1] !== undefined));
48
59
  }
49
- return { assetSourceFiles: assetSourceFilesCache, singleFileInputToOutputNameAndHash: singleFileInputToOutputNameAndHashCache };
50
- };
60
+ }
61
+ });
62
+ compilation.hooks.afterProcessAssets.tap(`${this.constructor.name}_ProcessBlockJSONFiles`, compilationAssets => {
63
+ // We start by trimming away the unused metadata files that WebPack creates.
64
+ for (const name of Object.keys(compilationAssets)) {
65
+ if (name.endsWith("block.json.asset.php")) {
66
+ compilation.deleteAsset(name);
67
+ compilation.deleteAsset(name.substring(0, name.length - 10) + ".js"); // This removes the block.json.js and block.json.js.map files
68
+ }
69
+ }
70
+ if (this.processingModules) {
71
+ // We perform the processing in the non-modules half ONLY because we don't necessarily have all the information we need during the modules half.
72
+ for (const name of BlockJSONManagingPlugin.blockJSONAssetSources.keys()) {
73
+ compilation.deleteAsset(name); // While the method is called, "deleteAsset", it doesn't actually delete it - just halts emission.
74
+ }
75
+ return;
76
+ }
77
+ const blockDirConfigData = {};
78
+ const mappableKeys = ["editorStyle", "style", "viewStyle", "viewScript", "script", "editorScript", "viewScriptModule", "scriptModule"];
51
79
  const remapValue = (value, name) => {
52
80
  if (value.startsWith("file:")) {
53
81
  let res = BlockJSONManagingPlugin.sourceToOutputMapping.get(`${name};${value}`);
54
82
  if (res !== undefined) {
55
83
  return res;
56
84
  }
57
- const { assetSourceFiles, singleFileInputToOutputNameAndHash } = sourceFileMappers();
58
- const dirname = node_path_1.default.dirname(assetSourceFiles.get(name) ?? name);
59
- const styleInputPath = node_path_1.default.normalize(node_path_1.default.join(compiler.context, dirname, value.substring(5)));
60
- const styleOutputPath = singleFileInputToOutputNameAndHash.get(styleInputPath);
61
- if (styleOutputPath !== undefined) {
85
+ const sourceDir = node_path_1.default.dirname(BlockJSONManagingPlugin.blockJSONAssetSources.get(name) ?? name);
86
+ const inputPath = node_path_1.default.normalize(node_path_1.default.join(sourceDir, value.substring(5)));
87
+ const output = BlockJSONManagingPlugin.blockJsonToEntrypointsMap.get(name)?.get(inputPath);
88
+ if (output !== undefined) {
62
89
  const prefix = value.startsWith("./", 5) ? "./" : "";
63
- const relativePath = node_path_1.default.relative(node_path_1.default.dirname(name), styleOutputPath[0]);
64
- const res = [`file:${prefix}${relativePath}`, typeof styleOutputPath[1] === 'string' ? styleOutputPath[1] : styleOutputPath[1]()];
90
+ const relativePath = node_path_1.default.relative(node_path_1.default.dirname(name), output.path);
91
+ const res = [`file:${prefix}${relativePath}`, output.hash];
65
92
  BlockJSONManagingPlugin.sourceToOutputMapping.set(`${name};${value}`, res);
66
93
  return res;
67
94
  }
68
95
  }
69
96
  return [value, ""];
70
97
  };
71
- if (this.processingModules) {
72
- for (const [key, value] of sourceFileMappers().singleFileInputToOutputNameAndHash.entries()) {
73
- BlockJSONManagingPlugin.moduleSourcesToOutputs.set(key, value);
98
+ for (const [name, source] of BlockJSONManagingPlugin.blockJSONAssetSources.entries()) {
99
+ const sourceDir = node_path_1.default.dirname(source);
100
+ const asset = compilation.assets[name]?.buffer().toString();
101
+ if (!asset) {
102
+ continue;
74
103
  }
75
- }
76
- const blockDirConfigData = {};
77
- const mappableKeys = ["editorStyle", "style", "viewStyle", "viewScript", "script", "editorScript", "viewScriptModule", "scriptModule"];
78
- for (const [name, asset] of Object.entries(compilationAssets)) {
79
- if (name.endsWith("block.json")) {
80
- let compositeHash = "";
81
- blockDirConfigData[name] = true;
82
- if (asset.constructor.name === 'RawSource') {
83
- const json = JSON.parse(asset.source().toString());
84
- for (const mappableKey of mappableKeys) {
85
- if (mappableKey in json) {
86
- const unmappedValue = json[mappableKey];
87
- if (Array.isArray(unmappedValue)) {
88
- const remappedValue = unmappedValue.map(value => remapValue(value, name));
89
- json[mappableKey] = remappedValue.map(([resource]) => resource);
90
- compositeHash += "~" + remappedValue.map(([_, hash]) => hash).join("~");
91
- }
92
- else if (typeof unmappedValue === 'string') {
93
- const remappedValue = remapValue(unmappedValue, name);
94
- json[mappableKey] = remappedValue[0];
95
- compositeHash += "~" + remappedValue[1];
96
- }
97
- }
98
- }
99
- if (json["version"]) {
100
- json["version"] = `${json["version"]}-${BlockJSONManagingPlugin.hashThingForAsset(compositeHash)}`;
104
+ blockDirConfigData[name] = true;
105
+ const json = JSON.parse(asset);
106
+ let compositeHash = "";
107
+ for (const mappableKey of mappableKeys) {
108
+ if (mappableKey in json) {
109
+ const unmappedValue = json[mappableKey];
110
+ if (Array.isArray(unmappedValue)) {
111
+ const remappedValue = unmappedValue.map(value => remapValue(value, name));
112
+ json[mappableKey] = remappedValue.map(([resource]) => resource);
113
+ compositeHash += "~" + remappedValue.map(([_, hash]) => hash).join("~");
101
114
  }
102
- else {
103
- json["version"] = BlockJSONManagingPlugin.hashThingForAsset(compositeHash);
115
+ else if (typeof unmappedValue === 'string') {
116
+ const remappedValue = remapValue(unmappedValue, name);
117
+ json[mappableKey] = remappedValue[0];
118
+ compositeHash += "~" + remappedValue[1];
104
119
  }
105
- const pathsNeedRemapping = !this.standaloneBlocks && json["plaudit"] !== "simple";
106
- const { assetSourceFiles } = sourceFileMappers();
107
- const sourceDir = node_path_1.default.join(compiler.context, node_path_1.default.dirname(assetSourceFiles.get(name) ?? name));
108
- const outputDir = node_path_1.default.join(compiler.outputPath, node_path_1.default.dirname(name));
109
- const stripFilePrefix = (file) => file.startsWith("file:./") ? file.substring(7) : file;
110
- const rawSetupFiles = json["plaudit"]?.["setup"]
111
- ? (typeof json["plaudit"]["setup"] === 'string' ? [json["plaudit"]["setup"]] : json["plaudit"]["setup"])
112
- : ["setup.php"];
113
- const setupFiles = pathsNeedRemapping
114
- ? rawSetupFiles
115
- .map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, stripFilePrefix(p))))
116
- .filter(p => node_fs_1.default.existsSync(p))
117
- .map(p => `file:./${this.findRelativeRouteBetween(outputDir, p)}`)
118
- : rawSetupFiles
119
- .filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, stripFilePrefix(p)))));
120
- if (setupFiles.length === 0) {
121
- if (json["plaudit"]?.["setup"] !== undefined) {
122
- delete json["plaudit"]["setup"];
123
- }
124
- }
125
- else {
126
- if (typeof json["plaudit"] !== 'object') {
127
- if (json["plaudit"] === "native") {
128
- json["plaudit"] = { type: "native" };
129
- }
130
- else {
131
- json["plaudit"] = {};
132
- }
133
- }
134
- json["plaudit"]["setup"] = setupFiles.length === 1 ? setupFiles[0] : setupFiles;
135
- }
136
- if (json["acf"]) {
137
- if (json["acf"]["renderTemplate"]) {
138
- json["render_template"] = json["acf"]["renderTemplate"];
139
- delete json["acf"]["renderTemplate"];
140
- }
141
- else if (json["acf"]["render_template"]) {
142
- json["render_template"] = json["acf"]["render_template"];
143
- delete json["acf"]["render_template"];
144
- }
145
- }
146
- const blockName = json["name"]?.toString() || "non-existent/block-name";
147
- let rawRenderTemplate = json["render"] ?? json["render_template"];
148
- rawRenderTemplate = (rawRenderTemplate
149
- ? (typeof rawRenderTemplate === 'string' ? [rawRenderTemplate] : rawRenderTemplate)
150
- : [`${blockName.substring(blockName.indexOf('/') + 1)}.php`, "template.php", "template.twig"]);
151
- const renderTemplate = pathsNeedRemapping
152
- ? rawRenderTemplate
153
- .map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, stripFilePrefix(p))))
154
- .filter(p => node_fs_1.default.existsSync(p))
155
- .map(p => `file:./${this.findRelativeRouteBetween(outputDir, p)}`)
156
- : rawRenderTemplate
157
- .filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, stripFilePrefix(p)))));
158
- if (renderTemplate.length === 0) {
159
- delete json["render_template"];
160
- delete json["render"];
120
+ }
121
+ }
122
+ if (json["version"]) {
123
+ json["version"] = `${json["version"]}-${BlockJSONManagingPlugin.hashThingForAsset(compositeHash)}`;
124
+ }
125
+ else {
126
+ json["version"] = BlockJSONManagingPlugin.hashThingForAsset(compositeHash);
127
+ }
128
+ const outputDir = node_path_1.default.join(compiler.outputPath, node_path_1.default.dirname(name));
129
+ const pathsNeedRemapping = !this.standaloneBlocks && json["plaudit"] !== "simple";
130
+ const rawSetupFiles = json["plaudit"]?.["setup"]
131
+ ? (typeof json["plaudit"]["setup"] === 'string' ? [json["plaudit"]["setup"]] : json["plaudit"]["setup"])
132
+ : ["setup.php"];
133
+ const setupFiles = pathsNeedRemapping
134
+ ? rawSetupFiles
135
+ .map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p))))
136
+ .filter(p => node_fs_1.default.existsSync(p))
137
+ .map(p => `file:./${BlockJSONManagingPlugin.findRelativeRouteBetween(outputDir, p)}`)
138
+ : rawSetupFiles
139
+ .filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p)))));
140
+ if (setupFiles.length === 0) {
141
+ if (json["plaudit"]?.["setup"] !== undefined) {
142
+ delete json["plaudit"]["setup"];
143
+ }
144
+ }
145
+ else {
146
+ if (typeof json["plaudit"] !== 'object') {
147
+ if (json["plaudit"] === "native") {
148
+ json["plaudit"] = { type: "native" };
161
149
  }
162
150
  else {
163
- let validTemplateLocation, invalidTemplateLocation;
164
- if (json["acf"] || (json["plaudit"] && (json["plaudit"] !== "native" && (typeof json["plaudit"] !== 'object' || json["plaudit"]?.["type"] !== "native")))) {
165
- // ACF-like blocks need to have the template stored in render_template.
166
- // Because we can statically detect ACF-like blocks, we can make the move here instead of at run-time.
167
- validTemplateLocation = "render_template";
168
- invalidTemplateLocation = "render";
169
- }
170
- else {
171
- validTemplateLocation = "render";
172
- invalidTemplateLocation = "render_template";
173
- }
174
- delete json[invalidTemplateLocation];
175
- if (renderTemplate.length > 1) {
176
- const error = new webpack_1.WebpackError("Encountered a block with multiple possible render files");
177
- error.file = node_path_1.default.join(sourceDir, 'block.json');
178
- compilation.warnings.push(error);
179
- json[validTemplateLocation] = renderTemplate.find(p => p.endsWith(".php")) ?? renderTemplate[0];
180
- }
181
- else {
182
- json[validTemplateLocation] = renderTemplate[0];
183
- }
151
+ json["plaudit"] = {};
184
152
  }
185
- compilation.updateAsset(name, new webpack_1.sources.RawSource(JSON.stringify(json, undefined, " ")));
186
153
  }
154
+ json["plaudit"]["setup"] = setupFiles.length === 1 ? setupFiles[0] : setupFiles;
187
155
  }
156
+ if (json["acf"]) {
157
+ if (json["acf"]["renderTemplate"]) {
158
+ json["render_template"] = json["acf"]["renderTemplate"];
159
+ delete json["acf"]["renderTemplate"];
160
+ }
161
+ else if (json["acf"]["render_template"]) {
162
+ json["render_template"] = json["acf"]["render_template"];
163
+ delete json["acf"]["render_template"];
164
+ }
165
+ }
166
+ const blockName = json["name"]?.toString() || "non-existent/block-name";
167
+ let rawRenderTemplate = json["render"] ?? json["render_template"];
168
+ rawRenderTemplate = (rawRenderTemplate
169
+ ? (typeof rawRenderTemplate === 'string' ? [rawRenderTemplate] : rawRenderTemplate)
170
+ : [`${blockName.substring(blockName.indexOf('/') + 1)}.php`, "template.php", "template.twig"]);
171
+ const renderTemplate = pathsNeedRemapping
172
+ ? rawRenderTemplate
173
+ .map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p))))
174
+ .filter(p => node_fs_1.default.existsSync(p))
175
+ .map(p => `file:./${BlockJSONManagingPlugin.findRelativeRouteBetween(outputDir, p)}`)
176
+ : rawRenderTemplate
177
+ .filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p)))));
178
+ if (renderTemplate.length === 0) {
179
+ delete json["render_template"];
180
+ delete json["render"];
181
+ }
182
+ else {
183
+ let validTemplateLocation, invalidTemplateLocation;
184
+ if (json["acf"] || (json["plaudit"] && (json["plaudit"] !== "native" && (typeof json["plaudit"] !== 'object' || json["plaudit"]?.["type"] !== "native")))) {
185
+ // ACF-like blocks need to have the template stored in render_template.
186
+ // Because we can statically detect ACF-like blocks, we can make the move here instead of at run-time.
187
+ validTemplateLocation = "render_template";
188
+ invalidTemplateLocation = "render";
189
+ }
190
+ else {
191
+ validTemplateLocation = "render";
192
+ invalidTemplateLocation = "render_template";
193
+ }
194
+ delete json[invalidTemplateLocation];
195
+ if (renderTemplate.length > 1) {
196
+ const error = new webpack_1.WebpackError("Encountered a block with multiple possible render files");
197
+ error.file = node_path_1.default.join(sourceDir, 'block.json');
198
+ compilation.warnings.push(error);
199
+ json[validTemplateLocation] = renderTemplate.find(p => p.endsWith(".php")) ?? renderTemplate[0];
200
+ }
201
+ else {
202
+ json[validTemplateLocation] = renderTemplate[0];
203
+ }
204
+ }
205
+ compilation[name in compilation.assets ? 'updateAsset' : 'emitAsset'](name, new webpack_1.sources.RawSource(JSON.stringify(json, undefined, " ")));
188
206
  }
189
- const sortedBlockDirConfigData = Object.fromEntries(Object.entries(blockDirConfigData).sort(([a], [b]) => a.localeCompare(b)));
207
+ const sortedBlockDirConfigData = Object.fromEntries(Object.entries(blockDirConfigData)
208
+ .sort(([a], [b]) => a.localeCompare(b)));
190
209
  compilation.emitAsset("blockdir.config", new webpack_1.sources.RawSource((0, php_serializer_1.default)(sortedBlockDirConfigData)));
191
210
  });
192
211
  });
193
212
  }
194
- findCommonAncestor(...paths) {
213
+ static findCommonAncestor(...paths) {
195
214
  return paths.map(p => node_path_1.default.normalize(p).split(node_path_1.default.sep)).reduce((prior, current) => {
196
215
  for (let i = 0, limit = Math.min(prior.length, current.length); i < limit; i++) {
197
216
  if (prior[i] !== current[i]) {
@@ -201,8 +220,8 @@ class BlockJSONManagingPlugin {
201
220
  return current.length < prior.length ? current : prior;
202
221
  });
203
222
  }
204
- findRelativeRouteBetween(path1, path2) {
205
- const commonAncestor = this.findCommonAncestor(path1, path2);
223
+ static findRelativeRouteBetween(path1, path2) {
224
+ const commonAncestor = BlockJSONManagingPlugin.findCommonAncestor(path1, path2);
206
225
  const route = Array(path1.split(node_path_1.default.sep).length - commonAncestor.length).fill("..");
207
226
  route.push(node_path_1.default.relative(commonAncestor.join(node_path_1.default.sep), path2));
208
227
  return route.join(node_path_1.default.sep);
@@ -210,34 +229,8 @@ class BlockJSONManagingPlugin {
210
229
  static hashThingForAsset(thing) {
211
230
  return node_crypto_1.default.createHash('md5').update(thing).digest("hex").substring(0, 20).toLowerCase();
212
231
  }
213
- static resolveFilesFromStats(compilationAssets, stats) {
214
- const singleFileChunkToOutputName = new Map(stats.assets
215
- .filter((asset) => asset.chunks?.length === 1)
216
- .filter(asset => !asset.name.endsWith("-rtl.css"))
217
- .filter(asset => !asset.name.endsWith('.asset.php'))
218
- .map(asset => {
219
- let assetHash = asset.info.contenthash ?? asset.info.fullhash;
220
- if (Array.isArray(assetHash)) {
221
- assetHash = BlockJSONManagingPlugin.hashThingForAsset(assetHash.join('~'));
222
- }
223
- return [asset.chunks[0], [asset.name, assetHash ?? (() => {
224
- const realAsset = compilationAssets[asset.name];
225
- return BlockJSONManagingPlugin.hashThingForAsset(realAsset ? realAsset.source().toString() : Date.now().toString());
226
- })]];
227
- }));
228
- const res = new Map(stats.modules
229
- .map(module => {
230
- if (module.nameForCondition !== undefined && module.chunks?.length === 1) {
231
- const output = singleFileChunkToOutputName.get(module.chunks[0]);
232
- return output !== undefined ? [module.nameForCondition, output] : undefined;
233
- }
234
- return undefined;
235
- })
236
- .filter((v) => v !== undefined));
237
- for (const [key, value] of BlockJSONManagingPlugin.moduleSourcesToOutputs.entries()) {
238
- res.set(key, value);
239
- }
240
- return res;
232
+ static stripFilePrefix(file) {
233
+ return file.startsWith("file:./") ? file.substring(7) : file;
241
234
  }
242
235
  }
243
236
  exports.default = BlockJSONManagingPlugin;
@@ -13,7 +13,7 @@ class ExtensionsConfigFileGeneratorPlugin {
13
13
  this.extensionsPath = extensionsPath;
14
14
  }
15
15
  apply(compiler) {
16
- compiler.hooks.make.tapPromise('ExtensionsConfigFileGeneratorPlugin', async (compilation) => {
16
+ compiler.hooks.make.tapPromise(this.constructor.name, async (compilation) => {
17
17
  if (!compilation.contextDependencies.has(this.extensionsPath)) {
18
18
  compilation.contextDependencies.add(this.extensionsPath);
19
19
  }
@@ -28,9 +28,9 @@ class ExtensionsConfigFileGeneratorPlugin {
28
28
  }
29
29
  await Promise.all(emissionPromises);
30
30
  });
31
- compiler.hooks.thisCompilation.tap("ExtensionsConfigFileGeneratorPlugin", compilation => {
31
+ compiler.hooks.thisCompilation.tap(this.constructor.name, compilation => {
32
32
  compilation.hooks.processAssets.tap({
33
- name: "ExtensionsConfigFileGeneratorPlugin_ProcessAssets",
33
+ name: `${this.constructor.name}_ProcessAssets`,
34
34
  stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ANALYSE
35
35
  }, compilationAssets => {
36
36
  const stats = compilation.getStats().toJson({
@@ -17,13 +17,13 @@ const webpack_remove_empty_scripts_1 = __importDefault(require("webpack-remove-e
17
17
  function joinPossiblyAbsolutePaths(...paths) {
18
18
  return paths.reduce((res, p) => !res || node_path_1.default.isAbsolute(p) ? p : node_path_1.default.join(res, p), '') || '.';
19
19
  }
20
- function mapToRealEntrypoints(entrypoint, dir, mapper = (entrypoint) => entrypoint) {
20
+ function mapToRealEntrypoints(entrypoint, dir, mapper = (entrypoint) => entrypoint, lazyDependent) {
21
21
  return (Array.isArray(entrypoint) ? entrypoint : [entrypoint])
22
22
  .map(ep => joinPossiblyAbsolutePaths(dir, mapper(ep)))
23
23
  .filter(ep => node_fs_1.default.statSync(ep, { throwIfNoEntry: false })?.isFile())
24
24
  .map(ep => {
25
25
  const parsedEntrypoint = node_path_1.default.parse(ep);
26
- return [joinPossiblyAbsolutePaths(node_path_1.default.basename(parsedEntrypoint.dir), parsedEntrypoint.name), { import: ep }];
26
+ return [joinPossiblyAbsolutePaths(node_path_1.default.basename(parsedEntrypoint.dir), parsedEntrypoint.name), { import: ep, lazyDependent }];
27
27
  });
28
28
  }
29
29
  let isInThemeCache = undefined;
@@ -228,7 +228,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
228
228
  const { standaloneBlocks, variablesFilePath, verbose, externals } = config;
229
229
  let currentVariables = config.currentVariables;
230
230
  replaceDefaultURLProcessing(webpackConfig);
231
- const fixedRules = injectPostcssConfigOverrides(webpackConfig, name => currentVariables[name], config.postcss.functions ?? (() => ({})), verbose);
231
+ const fixedRules = injectPostcssConfigOverrides(webpackConfig, name => currentVariables[name], config.postcss.functions ?? (() => ({})), verbose) ?? [];
232
232
  return sources.map(([src, dest]) => {
233
233
  const srcRoots = (typeof dest !== 'string' && dest.withLegacyBlocksIn
234
234
  ? [...src.split(','), ...resolveLegacyBlockScriptsInFolder(dest.withLegacyBlocksIn)]
@@ -304,7 +304,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
304
304
  requestToHandle(request) {
305
305
  const possibleExternal = externals[request];
306
306
  if (possibleExternal !== undefined && typeof possibleExternal !== 'string') {
307
- return possibleExternal['handle'];
307
+ return typeof possibleExternal.handle;
308
308
  }
309
309
  else {
310
310
  return request;
@@ -336,11 +336,13 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
336
336
  const res = [];
337
337
  try {
338
338
  const blockJSON = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dir, 'block.json'), 'utf8'));
339
+ const blockJSONChunkName = node_path_1.default.join(node_path_1.default.basename(dir), "block.json");
339
340
  for (const key of entrypointFields) {
340
341
  if (key in blockJSON) {
341
- res.push(...mapToRealEntrypoints(blockJSON[key], dir, ep => ep.startsWith("file:") ? ep.substring(5) : ep));
342
+ res.push(...mapToRealEntrypoints(blockJSON[key], dir, ep => ep.startsWith("file:") ? ep.substring(5) : ep, blockJSONChunkName));
342
343
  }
343
344
  }
345
+ res.push([blockJSONChunkName, { import: node_path_1.default.join(dir, 'block.json') }]);
344
346
  return res;
345
347
  }
346
348
  catch (e) {
@@ -373,6 +375,27 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
373
375
  }
374
376
  }
375
377
  }
378
+ // This is used to allow for block.json dependencies to correctly account for name-deduplication
379
+ for (const [key, entry] of Object.entries(currentEntry)) {
380
+ if (typeof entry === 'object' && !Array.isArray(entry) && 'lazyDependent' in entry && typeof entry.lazyDependent === 'string') {
381
+ const target = currentEntry[entry.lazyDependent];
382
+ if (typeof target === 'object' && !Array.isArray(target)) {
383
+ let dependOn;
384
+ if (target.dependOn === undefined) {
385
+ dependOn = target.dependOn = [];
386
+ }
387
+ else if (typeof target.dependOn === 'string') {
388
+ dependOn = target.dependOn = [target.dependOn];
389
+ }
390
+ else {
391
+ dependOn = target.dependOn;
392
+ }
393
+ if (!dependOn.includes(key)) {
394
+ dependOn.push(key);
395
+ }
396
+ }
397
+ }
398
+ }
376
399
  return currentEntry;
377
400
  };
378
401
  }
@@ -427,7 +450,16 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
427
450
  },
428
451
  module: {
429
452
  ...webpackConfig.module,
430
- rules: fixedRules
453
+ rules: [...fixedRules, {
454
+ test: /block\.json/i,
455
+ type: 'asset/resource',
456
+ generator: {
457
+ filename(pathData) {
458
+ // This mess of a name-generator accounts for WebPack's calculated name changing when block.json has dependents.
459
+ return node_path_1.default.join(node_path_1.default.basename(node_path_1.default.dirname(pathData.filename ?? pathData.runtime?.toString() ?? "[name]")), "[name][ext]");
460
+ }
461
+ }
462
+ }]
431
463
  },
432
464
  resolve: {
433
465
  ...webpackConfig.resolve,
@@ -437,7 +469,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
437
469
  stats: config.stats,
438
470
  plugins: copyFiles
439
471
  ? plugins.map(plugin => plugin.constructor.name === 'CopyPlugin'
440
- ? new copy_webpack_plugin_1.default({ patterns: [{ from: standaloneBlocks ? '**/(block.json|*.(php|twig|svg))' : '**/(block.json|*.(asset\.php|svg))',
472
+ ? new copy_webpack_plugin_1.default({ patterns: [{ from: standaloneBlocks ? '**/(*.(php|twig|svg))' : '**/(*.(asset\.php|svg))',
441
473
  context: srcRoot, noErrorOnMissing: true }] })
442
474
  : plugin)
443
475
  : (srcIsDirectory
@@ -451,7 +483,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
451
483
  return entry();
452
484
  }
453
485
  };
454
- }).filter((cfg) => cfg !== undefined);
486
+ }).filter(cfg => cfg !== undefined);
455
487
  }
456
488
  module.exports = function (config, webpackConfig = require("@wordpress/scripts/config/webpack.config")) {
457
489
  testForDuplicatedEntryPaths(config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plaudit/webpack-extensions",
3
- "version": "2.28.0",
3
+ "version": "2.29.0",
4
4
  "scripts": {
5
5
  "prepublishOnly": "rm -rf build && mkdir build && tsc",
6
6
  "build": "tsc",