@plaudit/webpack-extensions 2.28.0 → 2.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/wordpress-scripts-wrapper/BlockJSONManagingPlugin.d.ts +7 -5
- package/build/wordpress-scripts-wrapper/BlockJSONManagingPlugin.js +180 -177
- package/build/wordpress-scripts-wrapper/ExtensionsConfigFileGeneratorPlugin.js +3 -3
- package/build/wordpress-scripts-wrapper.js +116 -59
- package/package.json +1 -1
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { type Compiler, type WebpackPluginInstance } from "webpack";
|
|
1
|
+
import { type 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
|
private static readonly sourceToOutputMapping;
|
|
6
|
-
private static readonly
|
|
6
|
+
private static readonly blockJsonToEntrypointsMap;
|
|
7
|
+
private static readonly blockJSONAssetSources;
|
|
7
8
|
constructor(standaloneBlocks: boolean, processingModules: boolean);
|
|
8
9
|
apply(compiler: Compiler): void;
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
static resolveDestinationBySourceExtension(srcPath: string, entrypoint: Compilation['asyncEntrypoints'][number]): string | undefined;
|
|
11
|
+
static findCommonAncestor(...paths: string[]): string[];
|
|
12
|
+
static findRelativeRouteBetween(path1: string, path2: string): string;
|
|
11
13
|
private static hashThingForAsset;
|
|
12
|
-
private static
|
|
14
|
+
private static stripFilePrefix;
|
|
13
15
|
}
|
|
@@ -6,192 +6,221 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const php_serializer_1 = __importDefault(require("./php-serializer"));
|
|
10
9
|
const webpack_1 = require("webpack");
|
|
10
|
+
const php_serializer_1 = __importDefault(require("./php-serializer"));
|
|
11
11
|
class BlockJSONManagingPlugin {
|
|
12
12
|
standaloneBlocks;
|
|
13
13
|
processingModules;
|
|
14
14
|
static sourceToOutputMapping = new Map();
|
|
15
|
-
static
|
|
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(
|
|
22
|
-
compilation.hooks.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
42
|
-
|
|
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 = BlockJSONManagingPlugin.resolveDestinationBySourceExtension(srcPath, entrypoint);
|
|
44
|
+
if (!destPath) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const entryMeta = { hash: entrypoint.getEntrypointChunk().hash ?? destPath, path: destPath };
|
|
48
|
+
const currentEntrypoints = BlockJSONManagingPlugin.blockJsonToEntrypointsMap.get(name);
|
|
49
|
+
if (currentEntrypoints) {
|
|
50
|
+
currentEntrypoints.set(srcPath, entryMeta);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
BlockJSONManagingPlugin.blockJsonToEntrypointsMap.set(name, new Map([[srcPath, entryMeta]]));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
43
56
|
}
|
|
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
57
|
}
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
compilation.hooks.afterProcessAssets.tap(`${this.constructor.name}_ProcessBlockJSONFiles`, compilationAssets => {
|
|
61
|
+
// We start by trimming away the unused metadata files that WebPack creates.
|
|
62
|
+
for (const name of Object.keys(compilationAssets)) {
|
|
63
|
+
if (name.endsWith("block.json.asset.php")) {
|
|
64
|
+
compilation.deleteAsset(name);
|
|
65
|
+
compilation.deleteAsset(name.substring(0, name.length - 10) + ".js"); // This removes the block.json.js and block.json.js.map files
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (this.processingModules) {
|
|
69
|
+
// 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.
|
|
70
|
+
for (const name of BlockJSONManagingPlugin.blockJSONAssetSources.keys()) {
|
|
71
|
+
compilation.deleteAsset(name); // While the method is called, "deleteAsset", it doesn't actually delete it - just halts emission.
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const blockDirConfigData = {};
|
|
76
|
+
const mappableKeys = ["editorStyle", "style", "viewStyle", "viewScript", "script", "editorScript", "viewScriptModule", "scriptModule"];
|
|
51
77
|
const remapValue = (value, name) => {
|
|
52
78
|
if (value.startsWith("file:")) {
|
|
53
79
|
let res = BlockJSONManagingPlugin.sourceToOutputMapping.get(`${name};${value}`);
|
|
54
80
|
if (res !== undefined) {
|
|
55
81
|
return res;
|
|
56
82
|
}
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
if (styleOutputPath !== undefined) {
|
|
83
|
+
const sourceDir = node_path_1.default.dirname(BlockJSONManagingPlugin.blockJSONAssetSources.get(name) ?? name);
|
|
84
|
+
const inputPath = node_path_1.default.normalize(node_path_1.default.join(sourceDir, value.substring(5)));
|
|
85
|
+
const output = BlockJSONManagingPlugin.blockJsonToEntrypointsMap.get(name)?.get(inputPath);
|
|
86
|
+
if (output !== undefined) {
|
|
62
87
|
const prefix = value.startsWith("./", 5) ? "./" : "";
|
|
63
|
-
const relativePath = node_path_1.default.relative(node_path_1.default.dirname(name),
|
|
64
|
-
const res = [`file:${prefix}${relativePath}`,
|
|
88
|
+
const relativePath = node_path_1.default.relative(node_path_1.default.dirname(name), output.path);
|
|
89
|
+
const res = [`file:${prefix}${relativePath}`, output.hash];
|
|
65
90
|
BlockJSONManagingPlugin.sourceToOutputMapping.set(`${name};${value}`, res);
|
|
66
91
|
return res;
|
|
67
92
|
}
|
|
68
93
|
}
|
|
69
94
|
return [value, ""];
|
|
70
95
|
};
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
96
|
+
for (const [name, source] of BlockJSONManagingPlugin.blockJSONAssetSources.entries()) {
|
|
97
|
+
const sourceDir = node_path_1.default.dirname(source);
|
|
98
|
+
const asset = compilation.assets[name]?.buffer().toString();
|
|
99
|
+
if (!asset) {
|
|
100
|
+
continue;
|
|
74
101
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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)}`;
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
json["version"] = BlockJSONManagingPlugin.hashThingForAsset(compositeHash);
|
|
104
|
-
}
|
|
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;
|
|
102
|
+
blockDirConfigData[name] = true;
|
|
103
|
+
const json = JSON.parse(asset);
|
|
104
|
+
let compositeHash = "";
|
|
105
|
+
for (const mappableKey of mappableKeys) {
|
|
106
|
+
if (mappableKey in json) {
|
|
107
|
+
const unmappedValue = json[mappableKey];
|
|
108
|
+
if (Array.isArray(unmappedValue)) {
|
|
109
|
+
const remappedValue = unmappedValue.map(value => remapValue(value, name));
|
|
110
|
+
json[mappableKey] = remappedValue.map(([resource]) => resource);
|
|
111
|
+
compositeHash += "~" + remappedValue.map(([_, hash]) => hash).join("~");
|
|
135
112
|
}
|
|
136
|
-
if (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
else if (json["acf"]["render_template"]) {
|
|
142
|
-
json["render_template"] = json["acf"]["render_template"];
|
|
143
|
-
delete json["acf"]["render_template"];
|
|
144
|
-
}
|
|
113
|
+
else if (typeof unmappedValue === 'string') {
|
|
114
|
+
const remappedValue = remapValue(unmappedValue, name);
|
|
115
|
+
json[mappableKey] = remappedValue[0];
|
|
116
|
+
compositeHash += "~" + remappedValue[1];
|
|
145
117
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (json["version"]) {
|
|
121
|
+
json["version"] = `${json["version"]}-${BlockJSONManagingPlugin.hashThingForAsset(compositeHash)}`;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
json["version"] = BlockJSONManagingPlugin.hashThingForAsset(compositeHash);
|
|
125
|
+
}
|
|
126
|
+
const outputDir = node_path_1.default.join(compiler.outputPath, node_path_1.default.dirname(name));
|
|
127
|
+
const pathsNeedRemapping = !this.standaloneBlocks && json["plaudit"] !== "simple";
|
|
128
|
+
const rawSetupFiles = json["plaudit"]?.["setup"]
|
|
129
|
+
? (typeof json["plaudit"]["setup"] === 'string' ? [json["plaudit"]["setup"]] : json["plaudit"]["setup"])
|
|
130
|
+
: ["setup.php"];
|
|
131
|
+
const setupFiles = pathsNeedRemapping
|
|
132
|
+
? rawSetupFiles
|
|
133
|
+
.map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p))))
|
|
134
|
+
.filter(p => node_fs_1.default.existsSync(p))
|
|
135
|
+
.map(p => `file:./${BlockJSONManagingPlugin.findRelativeRouteBetween(outputDir, p)}`)
|
|
136
|
+
: rawSetupFiles
|
|
137
|
+
.filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p)))));
|
|
138
|
+
if (setupFiles.length === 0) {
|
|
139
|
+
if (json["plaudit"]?.["setup"] !== undefined) {
|
|
140
|
+
delete json["plaudit"]["setup"];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
if (typeof json["plaudit"] !== 'object') {
|
|
145
|
+
if (json["plaudit"] === "native") {
|
|
146
|
+
json["plaudit"] = { type: "native" };
|
|
161
147
|
}
|
|
162
148
|
else {
|
|
163
|
-
|
|
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
|
-
}
|
|
149
|
+
json["plaudit"] = {};
|
|
184
150
|
}
|
|
185
|
-
compilation.updateAsset(name, new webpack_1.sources.RawSource(JSON.stringify(json, undefined, " ")));
|
|
186
151
|
}
|
|
152
|
+
json["plaudit"]["setup"] = setupFiles.length === 1 ? setupFiles[0] : setupFiles;
|
|
187
153
|
}
|
|
154
|
+
if (json["acf"]) {
|
|
155
|
+
if (json["acf"]["renderTemplate"]) {
|
|
156
|
+
json["render_template"] = json["acf"]["renderTemplate"];
|
|
157
|
+
delete json["acf"]["renderTemplate"];
|
|
158
|
+
}
|
|
159
|
+
else if (json["acf"]["render_template"]) {
|
|
160
|
+
json["render_template"] = json["acf"]["render_template"];
|
|
161
|
+
delete json["acf"]["render_template"];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const blockName = json["name"]?.toString() || "non-existent/block-name";
|
|
165
|
+
let rawRenderTemplate = json["render"] ?? json["render_template"];
|
|
166
|
+
rawRenderTemplate = (rawRenderTemplate
|
|
167
|
+
? (typeof rawRenderTemplate === 'string' ? [rawRenderTemplate] : rawRenderTemplate)
|
|
168
|
+
: [`${blockName.substring(blockName.indexOf('/') + 1)}.php`, "template.php", "template.twig"]);
|
|
169
|
+
const renderTemplate = pathsNeedRemapping
|
|
170
|
+
? rawRenderTemplate
|
|
171
|
+
.map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p))))
|
|
172
|
+
.filter(p => node_fs_1.default.existsSync(p))
|
|
173
|
+
.map(p => `file:./${BlockJSONManagingPlugin.findRelativeRouteBetween(outputDir, p)}`)
|
|
174
|
+
: rawRenderTemplate
|
|
175
|
+
.filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, BlockJSONManagingPlugin.stripFilePrefix(p)))));
|
|
176
|
+
if (renderTemplate.length === 0) {
|
|
177
|
+
delete json["render_template"];
|
|
178
|
+
delete json["render"];
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
let validTemplateLocation, invalidTemplateLocation;
|
|
182
|
+
if (json["acf"] || (json["plaudit"] && (json["plaudit"] !== "native" && (typeof json["plaudit"] !== 'object' || json["plaudit"]?.["type"] !== "native")))) {
|
|
183
|
+
// ACF-like blocks need to have the template stored in render_template.
|
|
184
|
+
// Because we can statically detect ACF-like blocks, we can make the move here instead of at run-time.
|
|
185
|
+
validTemplateLocation = "render_template";
|
|
186
|
+
invalidTemplateLocation = "render";
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
validTemplateLocation = "render";
|
|
190
|
+
invalidTemplateLocation = "render_template";
|
|
191
|
+
}
|
|
192
|
+
delete json[invalidTemplateLocation];
|
|
193
|
+
if (renderTemplate.length > 1) {
|
|
194
|
+
const error = new webpack_1.WebpackError("Encountered a block with multiple possible render files");
|
|
195
|
+
error.file = node_path_1.default.join(sourceDir, 'block.json');
|
|
196
|
+
compilation.warnings.push(error);
|
|
197
|
+
json[validTemplateLocation] = renderTemplate.find(p => p.endsWith(".php")) ?? renderTemplate[0];
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
json[validTemplateLocation] = renderTemplate[0];
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
compilation[name in compilation.assets ? 'updateAsset' : 'emitAsset'](name, new webpack_1.sources.RawSource(JSON.stringify(json, undefined, " ")));
|
|
188
204
|
}
|
|
189
|
-
const sortedBlockDirConfigData = Object.fromEntries(Object.entries(blockDirConfigData)
|
|
205
|
+
const sortedBlockDirConfigData = Object.fromEntries(Object.entries(blockDirConfigData)
|
|
206
|
+
.sort(([a], [b]) => a.localeCompare(b)));
|
|
190
207
|
compilation.emitAsset("blockdir.config", new webpack_1.sources.RawSource((0, php_serializer_1.default)(sortedBlockDirConfigData)));
|
|
191
208
|
});
|
|
192
209
|
});
|
|
193
210
|
}
|
|
194
|
-
|
|
211
|
+
static resolveDestinationBySourceExtension(srcPath, entrypoint) {
|
|
212
|
+
const extensionMatch = /(m?)[jt]sx?$/i.exec(node_path_1.default.extname(srcPath));
|
|
213
|
+
if (extensionMatch === null) {
|
|
214
|
+
return entrypoint.getFiles().find(file => file.endsWith(".css"));
|
|
215
|
+
}
|
|
216
|
+
else if (extensionMatch[1]) {
|
|
217
|
+
return entrypoint.getFiles().find(file => file.endsWith(".mjs")) ?? entrypoint.getFiles().find(file => file.endsWith(".js"));
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
return entrypoint.getFiles().find(file => file.endsWith(".js"));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
static findCommonAncestor(...paths) {
|
|
195
224
|
return paths.map(p => node_path_1.default.normalize(p).split(node_path_1.default.sep)).reduce((prior, current) => {
|
|
196
225
|
for (let i = 0, limit = Math.min(prior.length, current.length); i < limit; i++) {
|
|
197
226
|
if (prior[i] !== current[i]) {
|
|
@@ -201,8 +230,8 @@ class BlockJSONManagingPlugin {
|
|
|
201
230
|
return current.length < prior.length ? current : prior;
|
|
202
231
|
});
|
|
203
232
|
}
|
|
204
|
-
findRelativeRouteBetween(path1, path2) {
|
|
205
|
-
const commonAncestor =
|
|
233
|
+
static findRelativeRouteBetween(path1, path2) {
|
|
234
|
+
const commonAncestor = BlockJSONManagingPlugin.findCommonAncestor(path1, path2);
|
|
206
235
|
const route = Array(path1.split(node_path_1.default.sep).length - commonAncestor.length).fill("..");
|
|
207
236
|
route.push(node_path_1.default.relative(commonAncestor.join(node_path_1.default.sep), path2));
|
|
208
237
|
return route.join(node_path_1.default.sep);
|
|
@@ -210,34 +239,8 @@ class BlockJSONManagingPlugin {
|
|
|
210
239
|
static hashThingForAsset(thing) {
|
|
211
240
|
return node_crypto_1.default.createHash('md5').update(thing).digest("hex").substring(0, 20).toLowerCase();
|
|
212
241
|
}
|
|
213
|
-
static
|
|
214
|
-
|
|
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;
|
|
242
|
+
static stripFilePrefix(file) {
|
|
243
|
+
return file.startsWith("file:./") ? file.substring(7) : file;
|
|
241
244
|
}
|
|
242
245
|
}
|
|
243
246
|
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(
|
|
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(
|
|
31
|
+
compiler.hooks.thisCompilation.tap(this.constructor.name, compilation => {
|
|
32
32
|
compilation.hooks.processAssets.tap({
|
|
33
|
-
name:
|
|
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,22 +17,19 @@ 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;
|
|
30
30
|
function isInTheme() {
|
|
31
31
|
return isInThemeCache ?? (isInThemeCache = node_fs_1.default.existsSync(node_path_1.default.join(process.cwd(), "theme.json")));
|
|
32
32
|
}
|
|
33
|
-
function isTruthy(value) {
|
|
34
|
-
return !!value;
|
|
35
|
-
}
|
|
36
33
|
function groupEntrypointsByAssetFile(entrypoints, entrypointNameExtractor) {
|
|
37
34
|
const seenPaths = new Map();
|
|
38
35
|
for (const entrypoint of entrypoints) {
|
|
@@ -129,64 +126,86 @@ function testForDuplicatedEntryPaths(config) {
|
|
|
129
126
|
process.exit(1);
|
|
130
127
|
}
|
|
131
128
|
}
|
|
132
|
-
function replaceDefaultURLProcessing(
|
|
129
|
+
function replaceDefaultURLProcessing(rules) {
|
|
133
130
|
const cssLoader = require.resolve('css-loader');
|
|
134
|
-
if (cssLoader
|
|
135
|
-
|
|
136
|
-
if (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
131
|
+
if (cssLoader) {
|
|
132
|
+
return rules.map(rule => {
|
|
133
|
+
if (rule && typeof rule === 'object' && "use" in rule && Array.isArray(rule.use)) {
|
|
134
|
+
return {
|
|
135
|
+
...rule,
|
|
136
|
+
use: rule.use.map(useElement => {
|
|
137
|
+
if (useElement && typeof useElement === 'object' && useElement.loader === cssLoader && typeof useElement.options === 'object') {
|
|
138
|
+
return {
|
|
139
|
+
...useElement,
|
|
140
|
+
options: {
|
|
141
|
+
...useElement.options,
|
|
142
|
+
url: {
|
|
143
|
+
filter(url) {
|
|
144
|
+
return !url.startsWith("/") && !!url.match(/\.(woff|woff2|eot|ttf|otf|png|jpe?g|svg|webp|avif|gif)[^.]*?(\?.*)?/i);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return useElement;
|
|
151
|
+
})
|
|
152
|
+
};
|
|
146
153
|
}
|
|
147
|
-
|
|
154
|
+
return rule;
|
|
155
|
+
});
|
|
148
156
|
}
|
|
157
|
+
return rules;
|
|
149
158
|
}
|
|
150
|
-
function injectPostcssConfigOverrides(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
function injectPostcssConfigOverrides(rules, variables, postcssFunctionsConfig, verbose) {
|
|
160
|
+
const postcssConfig = (0, static_configs_1.postcssConfigBuilder)(verbose, name => variables(name) ?? (name === 'ENV' ? '' : undefined), postcssFunctionsConfig);
|
|
161
|
+
return rules.map(rule => {
|
|
162
|
+
if (rule && typeof rule === 'object') {
|
|
163
|
+
if (Array.isArray(rule.use)) {
|
|
164
|
+
for (const useItem of rule.use) {
|
|
165
|
+
if (useItem && typeof useItem === 'object' && typeof useItem.options === 'object') {
|
|
166
|
+
if (useItem.options["sourceMap"] === false) {
|
|
167
|
+
useItem.options["sourceMap"] = true;
|
|
168
|
+
}
|
|
169
|
+
if (useItem.loader?.includes('postcss-loader')) {
|
|
170
|
+
if (useItem.options["postcssOptions"]) {
|
|
171
|
+
useItem.options["postcssOptions"] = { ...useItem.options["postcssOptions"], ...postcssConfig, sourceMap: true };
|
|
160
172
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
useItem.options["postcssOptions"] = { ...useItem.options["postcssOptions"], ...postcssConfig, sourceMap: true };
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
useItem.options["postcssOptions"] = { ...postcssConfig, sourceMap: true };
|
|
167
|
-
}
|
|
173
|
+
else {
|
|
174
|
+
useItem.options["postcssOptions"] = { ...postcssConfig, sourceMap: true };
|
|
168
175
|
}
|
|
169
176
|
}
|
|
170
177
|
}
|
|
171
|
-
if (rule.test instanceof RegExp && (rule.test.test("index.ts") || rule.test.test("index.mts"))) { // Then this is the javascript and typescript rule
|
|
172
|
-
rule.test = /\.m?[jt]sx?$/; // This hacks in support for mjs and mts files
|
|
173
|
-
}
|
|
174
178
|
}
|
|
175
|
-
if (rule.
|
|
176
|
-
rule.
|
|
177
|
-
rule.generator = { filename: "images/[name].[hash:8][ext]" };
|
|
179
|
+
if (rule.test instanceof RegExp && (rule.test.test("index.ts") || rule.test.test("index.mts"))) { // Then this is the javascript and typescript rule
|
|
180
|
+
rule.test = /\.m?[jt]sx?$/; // This hacks in support for mjs and mts files
|
|
178
181
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
}
|
|
183
|
+
if (rule.type === "asset/inline" && rule.test instanceof RegExp && rule.issuer instanceof RegExp && rule.test.test("test.svg") && rule.issuer.test("test.pcss")) {
|
|
184
|
+
rule.type = "asset/resource";
|
|
185
|
+
rule.generator = { filename: "images/[name].[hash:8][ext]" };
|
|
186
|
+
}
|
|
187
|
+
if (typeof rule.generator === 'object') {
|
|
188
|
+
const ruleGeneratorFilename = rule.generator["filename"];
|
|
189
|
+
if (typeof ruleGeneratorFilename === 'string' && (ruleGeneratorFilename.startsWith("images/") || ruleGeneratorFilename.startsWith("fonts/"))) {
|
|
190
|
+
rule.generator["filename"] = `../${ruleGeneratorFilename}`;
|
|
184
191
|
}
|
|
185
192
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
193
|
+
}
|
|
194
|
+
return rule;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function injectSupportForInliningSVGsAsStrings(rules) {
|
|
198
|
+
const svgRLoader = require.resolve('@svgr/webpack');
|
|
199
|
+
return rules.map(rule => {
|
|
200
|
+
if (rule && typeof rule === 'object' && "use" in rule && Array.isArray(rule.use) && (rule.use.includes('@svgr/webpack') || rule.use.includes(svgRLoader))) {
|
|
201
|
+
const { test, issuer, ...reactSpecific } = rule;
|
|
202
|
+
return { test, issuer, oneOf: [
|
|
203
|
+
{ type: 'asset/source', resourceQuery: /string/ }, // *.svg?string
|
|
204
|
+
reactSpecific
|
|
205
|
+
] };
|
|
206
|
+
}
|
|
207
|
+
return rule;
|
|
208
|
+
});
|
|
190
209
|
}
|
|
191
210
|
function parseEntrypointsJSON(dir) {
|
|
192
211
|
const entrypointsJSON = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dir, 'entrypoints.json'), 'utf8'));
|
|
@@ -227,8 +246,13 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
|
|
|
227
246
|
}
|
|
228
247
|
const { standaloneBlocks, variablesFilePath, verbose, externals } = config;
|
|
229
248
|
let currentVariables = config.currentVariables;
|
|
230
|
-
|
|
231
|
-
|
|
249
|
+
const fixedRules = [
|
|
250
|
+
replaceDefaultURLProcessing,
|
|
251
|
+
(rules) => {
|
|
252
|
+
return injectPostcssConfigOverrides(rules, name => currentVariables[name], config.postcss.functions ?? (() => ({})), verbose);
|
|
253
|
+
},
|
|
254
|
+
injectSupportForInliningSVGsAsStrings
|
|
255
|
+
].reduce((r, a) => a(r), webpackConfig.module?.rules ?? []);
|
|
232
256
|
return sources.map(([src, dest]) => {
|
|
233
257
|
const srcRoots = (typeof dest !== 'string' && dest.withLegacyBlocksIn
|
|
234
258
|
? [...src.split(','), ...resolveLegacyBlockScriptsInFolder(dest.withLegacyBlocksIn)]
|
|
@@ -240,7 +264,8 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
|
|
|
240
264
|
return undefined;
|
|
241
265
|
}
|
|
242
266
|
const copyFiles = srcIsDirectory && src !== dest;
|
|
243
|
-
const plugins = webpackConfig.plugins?.filter(
|
|
267
|
+
const plugins = webpackConfig.plugins?.filter(v => !!v)
|
|
268
|
+
.filter(plugin => plugin.constructor.name !== 'RtlCssPlugin') ?? [];
|
|
244
269
|
if (process.env["NO_TS_CHECKER"] !== "true") {
|
|
245
270
|
const include = (Array.isArray(srcRoot) ? srcRoot : [srcRoot])
|
|
246
271
|
.filter(sr => node_path_1.default.extname(sr).length === 0 || scriptOrStyleTest(sr, scriptExtension) === "script")
|
|
@@ -304,7 +329,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
|
|
|
304
329
|
requestToHandle(request) {
|
|
305
330
|
const possibleExternal = externals[request];
|
|
306
331
|
if (possibleExternal !== undefined && typeof possibleExternal !== 'string') {
|
|
307
|
-
return possibleExternal
|
|
332
|
+
return typeof possibleExternal.handle;
|
|
308
333
|
}
|
|
309
334
|
else {
|
|
310
335
|
return request;
|
|
@@ -336,11 +361,13 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
|
|
|
336
361
|
const res = [];
|
|
337
362
|
try {
|
|
338
363
|
const blockJSON = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dir, 'block.json'), 'utf8'));
|
|
364
|
+
const blockJSONChunkName = node_path_1.default.join(node_path_1.default.basename(dir), "block.json");
|
|
339
365
|
for (const key of entrypointFields) {
|
|
340
366
|
if (key in blockJSON) {
|
|
341
|
-
res.push(...mapToRealEntrypoints(blockJSON[key], dir, ep => ep.startsWith("file:") ? ep.substring(5) : ep));
|
|
367
|
+
res.push(...mapToRealEntrypoints(blockJSON[key], dir, ep => ep.startsWith("file:") ? ep.substring(5) : ep, blockJSONChunkName));
|
|
342
368
|
}
|
|
343
369
|
}
|
|
370
|
+
res.push([blockJSONChunkName, { import: node_path_1.default.join(dir, 'block.json') }]);
|
|
344
371
|
return res;
|
|
345
372
|
}
|
|
346
373
|
catch (e) {
|
|
@@ -373,6 +400,27 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
|
|
|
373
400
|
}
|
|
374
401
|
}
|
|
375
402
|
}
|
|
403
|
+
// This is used to allow for block.json dependencies to correctly account for name-deduplication
|
|
404
|
+
for (const [key, entry] of Object.entries(currentEntry)) {
|
|
405
|
+
if (typeof entry === 'object' && !Array.isArray(entry) && 'lazyDependent' in entry && typeof entry.lazyDependent === 'string') {
|
|
406
|
+
const target = currentEntry[entry.lazyDependent];
|
|
407
|
+
if (typeof target === 'object' && !Array.isArray(target)) {
|
|
408
|
+
let dependOn;
|
|
409
|
+
if (target.dependOn === undefined) {
|
|
410
|
+
dependOn = target.dependOn = [];
|
|
411
|
+
}
|
|
412
|
+
else if (typeof target.dependOn === 'string') {
|
|
413
|
+
dependOn = target.dependOn = [target.dependOn];
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
dependOn = target.dependOn;
|
|
417
|
+
}
|
|
418
|
+
if (!dependOn.includes(key)) {
|
|
419
|
+
dependOn.push(key);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
376
424
|
return currentEntry;
|
|
377
425
|
};
|
|
378
426
|
}
|
|
@@ -427,7 +475,16 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
|
|
|
427
475
|
},
|
|
428
476
|
module: {
|
|
429
477
|
...webpackConfig.module,
|
|
430
|
-
rules: fixedRules
|
|
478
|
+
rules: [...fixedRules, {
|
|
479
|
+
test: /block\.json/i,
|
|
480
|
+
type: 'asset/resource',
|
|
481
|
+
generator: {
|
|
482
|
+
filename(pathData) {
|
|
483
|
+
// This mess of a name-generator accounts for WebPack's calculated name changing when block.json has dependents.
|
|
484
|
+
return node_path_1.default.join(node_path_1.default.basename(node_path_1.default.dirname(pathData.filename ?? pathData.runtime?.toString() ?? "[name]")), "[name][ext]");
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}]
|
|
431
488
|
},
|
|
432
489
|
resolve: {
|
|
433
490
|
...webpackConfig.resolve,
|
|
@@ -437,7 +494,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
|
|
|
437
494
|
stats: config.stats,
|
|
438
495
|
plugins: copyFiles
|
|
439
496
|
? plugins.map(plugin => plugin.constructor.name === 'CopyPlugin'
|
|
440
|
-
? new copy_webpack_plugin_1.default({ patterns: [{ from: standaloneBlocks ? '**/(
|
|
497
|
+
? new copy_webpack_plugin_1.default({ patterns: [{ from: standaloneBlocks ? '**/(*.(php|twig|svg))' : '**/(*.(asset\.php|svg))',
|
|
441
498
|
context: srcRoot, noErrorOnMissing: true }] })
|
|
442
499
|
: plugin)
|
|
443
500
|
: (srcIsDirectory
|
|
@@ -451,7 +508,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
|
|
|
451
508
|
return entry();
|
|
452
509
|
}
|
|
453
510
|
};
|
|
454
|
-
}).filter(
|
|
511
|
+
}).filter(cfg => cfg !== undefined);
|
|
455
512
|
}
|
|
456
513
|
module.exports = function (config, webpackConfig = require("@wordpress/scripts/config/webpack.config")) {
|
|
457
514
|
testForDuplicatedEntryPaths(config);
|