@ideasonpurpose/build-tools-wordpress 2.9.1 → 2.10.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/AGENTS.md +11 -17
- package/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/boilerplate/composer.json +4 -3
- package/config/webpack.config.js +51 -13
- package/lib/AfterDoneReporterPlugin.js +29 -61
- package/lib/WatchRunReporterPlugin.js +45 -40
- package/lib/devserver-proxy.js +85 -81
- package/package.json +24 -23
- package/test/devserver-proxy.test.js +15 -14
package/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
Canonical AGENTS.md: https://gist.github.com/joemaller/d6154fbdb2e5f4670c0b9338d04189e9
|
|
3
|
-
Last Modified: 2026-06
|
|
3
|
+
Last Modified: 2026-07-06
|
|
4
4
|
-->
|
|
5
5
|
|
|
6
6
|
# AI Coding Assistant Guidelines
|
|
@@ -35,14 +35,13 @@ Before implementing:
|
|
|
35
35
|
|
|
36
36
|
**Minimum code that solves the problem. Nothing speculative.**
|
|
37
37
|
|
|
38
|
-
-
|
|
38
|
+
- Use standard libraries and native platform features first. Suggest popular, well-maintained alternatives.
|
|
39
39
|
- Prefer boring, obvious code over clever code.
|
|
40
40
|
- No features beyond what was asked.
|
|
41
41
|
- No abstractions for single-use code.
|
|
42
42
|
- Look for solutions in existing dependencies. If different than the first-choice solution, show pros and cons.
|
|
43
43
|
- No "flexibility" or "configurability" that wasn't requested.
|
|
44
44
|
- Only add error handling for realistically possible cases given current scope and style.
|
|
45
|
-
- Ask before introducing new dependencies.
|
|
46
45
|
- If you write 200 lines and it could be 50, rewrite it.
|
|
47
46
|
|
|
48
47
|
Ask yourself: "Would a senior engineer call this overcomplicated?" If yes, simplify.
|
|
@@ -53,33 +52,28 @@ Ask yourself: "Would a senior engineer call this overcomplicated?" If yes, simpl
|
|
|
53
52
|
|
|
54
53
|
When editing existing code:
|
|
55
54
|
|
|
56
|
-
- Preserve the spirit
|
|
55
|
+
- Preserve the codebase spirit conventions, and style.
|
|
57
56
|
- Don't "improve" adjacent code, comments, or formatting.
|
|
58
|
-
- Don't remove comments or
|
|
57
|
+
- Don't remove comments or dead code unless asked.
|
|
59
58
|
- Don't refactor code that isn't broken.
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
- Never run linters or formatters unless asked.
|
|
64
|
-
- Never add code which logs secrets, API keys, tokens, or .env values. If that code exists, say something.
|
|
65
|
-
|
|
66
|
-
When your changes create orphans:
|
|
67
|
-
|
|
68
|
-
- Remove imports/variables/functions that _your_ changes made unused.
|
|
69
|
-
- Do not remove pre-existing dead code unless asked.
|
|
59
|
+
- Never run tests, linters or formatters unless asked.
|
|
60
|
+
- Never log secrets, API keys, tokens, or .env values. If that code exists, say something.
|
|
61
|
+
- Remove imports/variables/functions that _your_ changes orphaned.
|
|
70
62
|
|
|
71
63
|
Every changed line should trace directly to the user's request.
|
|
72
64
|
|
|
65
|
+
**Security exception**: Allow sweeping changes to fix real security problems. Explain.
|
|
66
|
+
|
|
73
67
|
## 4. Documentation and Comments
|
|
74
68
|
|
|
75
69
|
- Prefer self-documenting code and descriptive names over comments.
|
|
76
70
|
- Add comments only where the _why_ is not obvious from the code.
|
|
77
71
|
- Update or remove comments directly invalidated by your changes.
|
|
78
72
|
- Follow the existing codebase's conventions for types, docstrings, and documentation style.
|
|
79
|
-
-
|
|
73
|
+
- Note conflicts with the system prompt and ask for guidance.
|
|
80
74
|
|
|
81
75
|
## 5. Additional Instructions
|
|
82
76
|
|
|
83
77
|
Look for sibling `AGENTS-*.md` files for further instructions on specific concerns (e.g. stylesheets, WordPress development, static site development)
|
|
84
78
|
|
|
85
|
-
Whenever this file is modified, update the timestamp in the top comment.
|
|
79
|
+
Whenever this file is modified, update the timestamp in the top comment.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
#### v2.9.1
|
|
8
|
+
|
|
9
|
+
> 26 June 2026
|
|
10
|
+
|
|
11
|
+
- bump deps, format action
|
|
12
|
+
|
|
7
13
|
#### v2.9.0
|
|
8
14
|
|
|
9
15
|
> 26 June 2026
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ideasonpurpose/build-tools-wordpress
|
|
2
2
|
|
|
3
|
-
#### Version 2.
|
|
3
|
+
#### Version 2.10.0
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@ideasonpurpose/build-tools-wordpress)
|
|
6
6
|
[](https://github.com/ideasonpurpose/build-tools-wordpress#readme)
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
}
|
|
9
9
|
],
|
|
10
10
|
"config": {
|
|
11
|
+
"discard-changes": "stash",
|
|
11
12
|
"optimize-autoloader": true,
|
|
12
|
-
"sort-packages": true,
|
|
13
|
-
"vendor-dir": "wp-content/themes/iop-theme/vendor",
|
|
14
13
|
"platform": {
|
|
15
14
|
"php": "8.4",
|
|
16
15
|
"ext-intl": "0"
|
|
17
|
-
}
|
|
16
|
+
},
|
|
17
|
+
"sort-packages": true,
|
|
18
|
+
"vendor-dir": "wp-content/themes/iop-theme/vendor"
|
|
18
19
|
},
|
|
19
20
|
"autoload": {
|
|
20
21
|
"psr-4": {
|
package/config/webpack.config.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import { posix as path } from "path";
|
|
2
4
|
|
|
3
5
|
import { statSync } from "fs";
|
|
@@ -34,7 +36,7 @@ if (process.env.WEBPACK_BUNDLE_ANALYZER) process.env.NODE_ENV = "production";
|
|
|
34
36
|
|
|
35
37
|
const isProduction = process.env.NODE_ENV === "production";
|
|
36
38
|
|
|
37
|
-
const
|
|
39
|
+
const __stats = {
|
|
38
40
|
preset: "normal",
|
|
39
41
|
cachedAssets: false,
|
|
40
42
|
assets: true,
|
|
@@ -79,6 +81,28 @@ const stats = {
|
|
|
79
81
|
loggingDebug: ["sass-loader"],
|
|
80
82
|
};
|
|
81
83
|
|
|
84
|
+
const stats = isProduction
|
|
85
|
+
? {
|
|
86
|
+
preset: "normal",
|
|
87
|
+
colors: true,
|
|
88
|
+
}
|
|
89
|
+
: {
|
|
90
|
+
all: false,
|
|
91
|
+
errors: true,
|
|
92
|
+
warnings: true,
|
|
93
|
+
errorDetails: false,
|
|
94
|
+
colors: true,
|
|
95
|
+
modules: false,
|
|
96
|
+
assets: false, // ← hides the long asset list on every rebuild
|
|
97
|
+
entrypoints: false,
|
|
98
|
+
hash: false,
|
|
99
|
+
version: false,
|
|
100
|
+
performance: false,
|
|
101
|
+
reasons: false,
|
|
102
|
+
timings: false,
|
|
103
|
+
children: false,
|
|
104
|
+
loggingDebug: false, // only enable sass debug when you really need it
|
|
105
|
+
};
|
|
82
106
|
/**
|
|
83
107
|
* @param {Record<string, any>} env - Environment variables from Webpack CLI
|
|
84
108
|
*/
|
|
@@ -92,7 +116,6 @@ export default async (env) => {
|
|
|
92
116
|
|
|
93
117
|
const proxy = isProduction ? {} : await devserverProxy(config);
|
|
94
118
|
|
|
95
|
-
|
|
96
119
|
/**
|
|
97
120
|
* Simple helper for encoding SVGs as data urls with proper encoding for special characters
|
|
98
121
|
* @param {Buffer} content
|
|
@@ -121,12 +144,12 @@ export default async (env) => {
|
|
|
121
144
|
|
|
122
145
|
const devtool = config.devtool || false;
|
|
123
146
|
|
|
124
|
-
// Debug: Log the watchFiles paths
|
|
125
147
|
const watchPath =
|
|
126
148
|
path.resolve(config.src, "..") + "/**/*.{php,html,svg,json}";
|
|
127
|
-
console.log(chalk.cyan("🔍 Watching
|
|
149
|
+
console.log(chalk.cyan("🔍"), chalk.bold("Watching:"), watchPath);
|
|
128
150
|
console.log(
|
|
129
|
-
chalk.cyan("📁
|
|
151
|
+
chalk.cyan("📁"),
|
|
152
|
+
chalk.bold("Theme:"),
|
|
130
153
|
path.resolve(config.src, ".."),
|
|
131
154
|
);
|
|
132
155
|
|
|
@@ -323,7 +346,11 @@ export default async (env) => {
|
|
|
323
346
|
// hot: "only",
|
|
324
347
|
static: [
|
|
325
348
|
{ directory: config.dist, watch: false },
|
|
326
|
-
{
|
|
349
|
+
{
|
|
350
|
+
directory: config.src,
|
|
351
|
+
publicPath: config.publicPath.replace("/dist/", "/src/"),
|
|
352
|
+
watch: false,
|
|
353
|
+
},
|
|
327
354
|
],
|
|
328
355
|
|
|
329
356
|
client: {
|
|
@@ -344,7 +371,9 @@ export default async (env) => {
|
|
|
344
371
|
|
|
345
372
|
devMiddleware: {
|
|
346
373
|
index: false, // enable root proxying
|
|
347
|
-
|
|
374
|
+
infrastructureLogging: {
|
|
375
|
+
level: "warn", // or "error" for even stricter
|
|
376
|
+
},
|
|
348
377
|
writeToDisk: (filePath) => {
|
|
349
378
|
// // // SHORT_CIRCUIT FOR TESTING
|
|
350
379
|
// // console.log("DEBUG writeToDisk:", { filePath });
|
|
@@ -418,7 +447,11 @@ export default async (env) => {
|
|
|
418
447
|
devServer.server.address().port;
|
|
419
448
|
devServer.compiler._devServer = devServer;
|
|
420
449
|
|
|
421
|
-
console.log(
|
|
450
|
+
console.log(
|
|
451
|
+
chalk.cyan("●"),
|
|
452
|
+
chalk.bold("Listening:"),
|
|
453
|
+
chalk.blue.underline(`http://localhost:${port}`),
|
|
454
|
+
);
|
|
422
455
|
},
|
|
423
456
|
|
|
424
457
|
/**
|
|
@@ -435,7 +468,9 @@ export default async (env) => {
|
|
|
435
468
|
* `/inform` requests with 404s, filling logs and cluttering
|
|
436
469
|
* terminals. So that's why this is here. I hate it.
|
|
437
470
|
*/
|
|
438
|
-
devServer.app.all("/inform", () =>
|
|
471
|
+
devServer.app.all("/inform", (req, res) => {
|
|
472
|
+
res.status(204).end();
|
|
473
|
+
});
|
|
439
474
|
|
|
440
475
|
/**
|
|
441
476
|
* The "/webpack/reload" endpoint will trigger a full devServer refresh
|
|
@@ -448,7 +483,9 @@ export default async (env) => {
|
|
|
448
483
|
*/
|
|
449
484
|
devServer.app.get("/webpack/reload", (req, res) => {
|
|
450
485
|
console.log(
|
|
451
|
-
chalk.yellow("
|
|
486
|
+
chalk.yellow("↻"),
|
|
487
|
+
chalk.yellow.bold("Reload:"),
|
|
488
|
+
"/webpack/reload",
|
|
452
489
|
);
|
|
453
490
|
|
|
454
491
|
devServer.sendMessage(
|
|
@@ -529,12 +566,13 @@ export default async (env) => {
|
|
|
529
566
|
manifestFile: config.manifestFile,
|
|
530
567
|
}),
|
|
531
568
|
|
|
532
|
-
new
|
|
569
|
+
new WatchRunReporterPlugin({
|
|
533
570
|
echo: env && env.WEBPACK_SERVE,
|
|
534
|
-
// message:
|
|
535
|
-
// "Dev site " + chalk.blue.bold(`http://localhost:${process.env.PORT}`),
|
|
536
571
|
}),
|
|
537
572
|
|
|
573
|
+
new AfterDoneReporterPlugin({
|
|
574
|
+
echo: env && env.WEBPACK_SERVE,
|
|
575
|
+
}),
|
|
538
576
|
new BundleAnalyzerPlugin({
|
|
539
577
|
analyzerMode: isProduction ? "static" : "disabled",
|
|
540
578
|
openAnalyzer: false,
|
|
@@ -1,78 +1,46 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import chalk from "chalk";
|
|
2
4
|
import humanizeDuration from "humanize-duration";
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Messages should be configured in an argument object:
|
|
8
|
-
*
|
|
9
|
-
* new AfterDoneReporterPlugin({message: "Your Message Here"})
|
|
7
|
+
* Clean post-compilation summary for dev server.
|
|
8
|
+
* Shows status, duration, and the local URL without placeholder text or setTimeout hacks.
|
|
10
9
|
*/
|
|
11
10
|
export class AfterDoneReporterPlugin {
|
|
12
11
|
constructor(options = {}) {
|
|
13
12
|
const defaults = {
|
|
14
13
|
echo: true,
|
|
15
|
-
prefix: `🟢${chalk.gray("(iop)")}:`,
|
|
16
|
-
message: "",
|
|
17
14
|
};
|
|
18
15
|
this.config = { ...defaults, ...options };
|
|
19
|
-
this.name = "IOP Reporter
|
|
20
|
-
this.messages = [];
|
|
16
|
+
this.name = "IOP AfterDone Reporter";
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
apply(compiler) {
|
|
24
|
-
compiler.hooks.done.
|
|
25
|
-
if (this.config.echo)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const messages = [
|
|
47
|
-
// `Compiled ${mCount} input modules into ${aCount} files in ${time}`,
|
|
48
|
-
// "Dev site " + chalk.blue(`http://${hostname}:${chalk.bold(port)}`),
|
|
49
|
-
"Dev site " + chalk.blue(`http://${hostname}:${chalk.bold(port)}`),
|
|
50
|
-
this.config.message,
|
|
51
|
-
]
|
|
52
|
-
.filter((m) => m.length)
|
|
53
|
-
.join("\n" + this.config.prefix + " ");
|
|
54
|
-
|
|
55
|
-
setTimeout(() =>
|
|
56
|
-
// console.log("\n" + this.config.prefix + " " + messages),
|
|
57
|
-
console.log( "🚧 " + messages),
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
setTimeout(() => {
|
|
61
|
-
// console.log(Object.keys(compiler));
|
|
62
|
-
// console.log(compiler.options);
|
|
63
|
-
});
|
|
20
|
+
compiler.hooks.done.tap(this.name, (stats) => {
|
|
21
|
+
if (!this.config.echo) return;
|
|
22
|
+
|
|
23
|
+
const devServer = compiler.options.devServer || {};
|
|
24
|
+
const host = devServer.host === "0.0.0.0" ? "localhost" : devServer.host || "localhost";
|
|
25
|
+
const port = devServer.port || "auto";
|
|
26
|
+
const url = chalk.blue.underline(`http://${host}:${port}`);
|
|
27
|
+
|
|
28
|
+
const durationMs = stats.endTime && stats.startTime ? stats.endTime - stats.startTime : 0;
|
|
29
|
+
const time = humanizeDuration(durationMs, { units: ["s", "ms"], round: true });
|
|
30
|
+
|
|
31
|
+
const hasErrors = stats.hasErrors();
|
|
32
|
+
const hasWarnings = stats.hasWarnings();
|
|
33
|
+
|
|
34
|
+
let statusLine;
|
|
35
|
+
if (hasErrors) {
|
|
36
|
+
statusLine = `${chalk.red.bold("✖ Failed")} in ${chalk.yellow(time)}`;
|
|
37
|
+
} else if (hasWarnings) {
|
|
38
|
+
statusLine = `${chalk.yellow.bold("⚠ Compiled with warnings")} in ${chalk.yellow(time)}`;
|
|
39
|
+
} else {
|
|
40
|
+
statusLine = `${chalk.green.bold("✔ Compiled")} in ${chalk.yellow(time)}`;
|
|
64
41
|
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// compiler.hooks.done.tapPromise("webpack-dev-server", async (stats) => {
|
|
69
|
-
// await stats;
|
|
70
|
-
// setTimeout(() => {
|
|
71
|
-
// console.log(chalk.bold.magenta("in webpack-dev-server hook"), {
|
|
72
|
-
// stats, thing: Object.keys( compiler.options),
|
|
73
|
-
// });
|
|
74
|
-
// });
|
|
75
|
-
// });
|
|
76
42
|
|
|
43
|
+
console.log(`\n${statusLine} → ${url}`);
|
|
44
|
+
});
|
|
77
45
|
}
|
|
78
|
-
}
|
|
46
|
+
}
|
|
@@ -1,56 +1,61 @@
|
|
|
1
|
+
import path from "path";
|
|
1
2
|
import chalk from "chalk";
|
|
3
|
+
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Messages should be configured in an argument object:
|
|
5
|
+
* Clean file-change reporting for watch/dev mode.
|
|
6
|
+
* Shows what triggered the recompile without flooding the terminal.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* Tracks compiler.hooks.invalid to capture the triggering filename,
|
|
9
|
+
* falling back to compiler.modifiedFiles when available.
|
|
9
10
|
*/
|
|
10
11
|
export class WatchRunReporterPlugin {
|
|
11
12
|
constructor(options = {}) {
|
|
12
13
|
const defaults = {
|
|
13
14
|
echo: true,
|
|
14
|
-
|
|
15
|
-
message: chalk.bold("Compiling...", ""),
|
|
15
|
+
message: chalk.gray("recompiling..."),
|
|
16
16
|
};
|
|
17
17
|
this.config = { ...defaults, ...options };
|
|
18
|
-
this.name = "IOP Reporter
|
|
18
|
+
this.name = "IOP WatchRun Reporter";
|
|
19
|
+
this.invalidFile = null;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
apply(compiler) {
|
|
22
|
-
compiler.hooks.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
23
|
+
compiler.hooks.invalid.tap(this.name, (fileName) => {
|
|
24
|
+
this.invalidFile = fileName;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
compiler.hooks.watchRun.tap(this.name, () => {
|
|
28
|
+
if (!this.config.echo) return;
|
|
29
|
+
|
|
30
|
+
const root = compiler.context || process.cwd();
|
|
31
|
+
const modFiles = compiler.modifiedFiles?.size
|
|
32
|
+
? Array.from(compiler.modifiedFiles)
|
|
33
|
+
: null;
|
|
34
|
+
const changed =
|
|
35
|
+
modFiles || (this.invalidFile ? [this.invalidFile] : null);
|
|
36
|
+
|
|
37
|
+
this.invalidFile = null;
|
|
38
|
+
|
|
39
|
+
if (!changed) return;
|
|
40
|
+
|
|
41
|
+
const relFiles = changed
|
|
42
|
+
.map((p) => path.relative(root, p) || p)
|
|
43
|
+
.sort();
|
|
44
|
+
|
|
45
|
+
let changeMsg;
|
|
46
|
+
if (relFiles.length === 1) {
|
|
47
|
+
changeMsg = chalk.bold.yellow(relFiles[0]);
|
|
48
|
+
} else if (relFiles.length <= 3) {
|
|
49
|
+
changeMsg = chalk.bold.yellow(relFiles.join(", "));
|
|
50
|
+
} else {
|
|
51
|
+
changeMsg = chalk.bold.yellow(
|
|
52
|
+
`${relFiles.slice(0, 2).join(", ")} +${relFiles.length - 2} more`,
|
|
53
|
+
);
|
|
53
54
|
}
|
|
55
|
+
|
|
56
|
+
console.log(
|
|
57
|
+
`\n${chalk.cyan("⟳")} Changed: ${changeMsg} ${this.config.message}`,
|
|
58
|
+
);
|
|
54
59
|
});
|
|
55
60
|
}
|
|
56
|
-
}
|
|
61
|
+
}
|
package/lib/devserver-proxy.js
CHANGED
|
@@ -19,13 +19,12 @@ export async function devserverProxy(config) {
|
|
|
19
19
|
if (config.proxy === true) {
|
|
20
20
|
const localPort = await findLocalPort();
|
|
21
21
|
// console.log({ localPort });
|
|
22
|
-
|
|
22
|
+
if (localPort && localPort.hostname && localPort.port) {
|
|
23
23
|
target = new URL(`http://${localPort.hostname}:${localPort.port}`);
|
|
24
24
|
console.log(
|
|
25
|
-
chalk.cyan
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
),
|
|
25
|
+
chalk.cyan("↔"),
|
|
26
|
+
chalk.bold("Proxy:"),
|
|
27
|
+
chalk.blue.underline(target.origin),
|
|
29
28
|
);
|
|
30
29
|
}
|
|
31
30
|
} else if (!!isIP(config.proxy)) {
|
|
@@ -46,10 +45,11 @@ export async function devserverProxy(config) {
|
|
|
46
45
|
if (localPort && localPort.hostname && localPort.port) {
|
|
47
46
|
target = new URL(`http://${localPort.hostname}:${localPort.port}`);
|
|
48
47
|
console.log(
|
|
49
|
-
"
|
|
48
|
+
chalk.cyan("↔"),
|
|
49
|
+
chalk.bold("Proxy:"),
|
|
50
50
|
chalk.cyan(config.proxy),
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
"→",
|
|
52
|
+
chalk.blue.underline(target.origin),
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -64,7 +64,6 @@ export async function devserverProxy(config) {
|
|
|
64
64
|
context: [
|
|
65
65
|
"**",
|
|
66
66
|
"!/ws",
|
|
67
|
-
"!/sockjs-node",
|
|
68
67
|
"!/__webpack_dev_server__",
|
|
69
68
|
"!/webpack-dev-server",
|
|
70
69
|
],
|
|
@@ -76,84 +75,89 @@ export async function devserverProxy(config) {
|
|
|
76
75
|
cookieDomainRewrite: "", // was `${config.host}:8080` ??
|
|
77
76
|
headers: { "Accept-Encoding": "identity" },
|
|
78
77
|
ws: true,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
socket.on("error", (err) => {
|
|
92
|
-
if (err.code !== "EPIPE") {
|
|
93
|
-
console.error("WebSocket proxy error:", err);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
onProxyRes: function (proxyRes, req, res) {
|
|
99
|
-
/**
|
|
100
|
-
* Update urls in files with these content-types
|
|
101
|
-
*/
|
|
102
|
-
const contentTypes = [
|
|
103
|
-
"application/javascript",
|
|
104
|
-
"application/json",
|
|
105
|
-
"multipart/form-data",
|
|
106
|
-
"text/css",
|
|
107
|
-
"text/html",
|
|
108
|
-
"text/plain",
|
|
109
|
-
];
|
|
110
|
-
|
|
111
|
-
let originalBody = [];
|
|
112
|
-
|
|
113
|
-
proxyRes.on("data", (data) => originalBody.push(data));
|
|
114
|
-
|
|
115
|
-
proxyRes.on("end", () => {
|
|
116
|
-
res.statusCode = proxyRes.statusCode;
|
|
117
|
-
if (proxyRes.statusMessage) {
|
|
118
|
-
res.statusMessage = proxyRes.statusMessage;
|
|
78
|
+
// prevent WDS from injecting its logger (stops per-request [HPM] GET spam)
|
|
79
|
+
logger: { info: () => {}, warn: () => {}, error: () => {} },
|
|
80
|
+
|
|
81
|
+
// http-proxy-middleware v3+ event API (webpack-dev-server v6)
|
|
82
|
+
on: {
|
|
83
|
+
error: (err, req, res) => {
|
|
84
|
+
if (err.code === "ECONNRESET") {
|
|
85
|
+
console.log(chalk.yellow("Proxy: connection reset, ignoring"));
|
|
86
|
+
} else {
|
|
87
|
+
console.log(chalk.red("Proxy error:"), req.url, err, err.stack);
|
|
88
|
+
res.writeHead(500, { "Content-Type": "text-plain" });
|
|
89
|
+
res.end("Webpack DevServer Proxy Error: " + err);
|
|
119
90
|
}
|
|
91
|
+
},
|
|
120
92
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
new RegExp(target.host, "gi"),
|
|
126
|
-
req.headers.host,
|
|
127
|
-
);
|
|
93
|
+
proxyReqWs: (proxyReq, req, socket, options, head) => {
|
|
94
|
+
socket.on("error", (err) => {
|
|
95
|
+
if (err.code !== "EPIPE") {
|
|
96
|
+
console.error(chalk.red("WebSocket proxy error:"), err);
|
|
128
97
|
}
|
|
129
|
-
res.setHeader(String(key).trim(), header);
|
|
130
98
|
});
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
proxyRes: function (proxyRes, req, res) {
|
|
102
|
+
/**
|
|
103
|
+
* Update urls in files with these content-types
|
|
104
|
+
*/
|
|
105
|
+
const contentTypes = [
|
|
106
|
+
"application/javascript",
|
|
107
|
+
"application/json",
|
|
108
|
+
"multipart/form-data",
|
|
109
|
+
"text/css",
|
|
110
|
+
"text/html",
|
|
111
|
+
"text/plain",
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
let originalBody = [];
|
|
115
|
+
|
|
116
|
+
proxyRes.on("data", (data) => originalBody.push(data));
|
|
117
|
+
|
|
118
|
+
proxyRes.on("end", () => {
|
|
119
|
+
res.statusCode = proxyRes.statusCode;
|
|
120
|
+
if (proxyRes.statusMessage) {
|
|
121
|
+
res.statusMessage = proxyRes.statusMessage;
|
|
122
|
+
}
|
|
131
123
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
124
|
+
Object.keys(proxyRes.headers).forEach((key) => {
|
|
125
|
+
let header = proxyRes.headers[key];
|
|
126
|
+
if (typeof header == "string") {
|
|
127
|
+
header = header.replace(
|
|
128
|
+
new RegExp(target.host, "gi"),
|
|
129
|
+
req.headers.host,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
res.setHeader(String(key).trim(), header);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
originalBody = Buffer.concat(originalBody);
|
|
136
|
+
let newBody;
|
|
137
|
+
|
|
138
|
+
// const type = proxyRes.headers["content-type"]?.split(";")[0].trim() ?? null;
|
|
139
|
+
const type = proxyRes.headers["content-type"]?.split(";")[0].trim();
|
|
140
|
+
|
|
141
|
+
const wpRegexp = new RegExp(
|
|
142
|
+
"^/wp-(?:admin|includes|content/plugins).*(?:css|js|map)$",
|
|
143
|
+
);
|
|
144
|
+
const originRegExp = new RegExp(
|
|
145
|
+
`(http:\\\\/\\\\/|http://)${target.host}`,
|
|
146
|
+
"gi",
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (contentTypes.includes(type) && !wpRegexp.test(req.path)) {
|
|
150
|
+
newBody = originalBody
|
|
151
|
+
.toString("utf8")
|
|
152
|
+
.replace(originRegExp, `$1${req.headers.host}`);
|
|
153
|
+
res.setHeader("Content-Length", Buffer.byteLength(newBody));
|
|
154
|
+
} else {
|
|
155
|
+
newBody = originalBody;
|
|
156
|
+
}
|
|
154
157
|
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
res.end(newBody);
|
|
159
|
+
});
|
|
160
|
+
},
|
|
157
161
|
},
|
|
158
162
|
},
|
|
159
163
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ideasonpurpose/build-tools-wordpress",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"description": "Build scripts and dependencies for IOP's WordPress development environments.",
|
|
5
5
|
"homepage": "https://github.com/ideasonpurpose/build-tools-wordpress#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -41,38 +41,37 @@
|
|
|
41
41
|
"@rollup/plugin-json": "^6.1.0",
|
|
42
42
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
43
43
|
"@svgr/webpack": "^8.1.0",
|
|
44
|
-
"@wordpress/dependency-extraction-webpack-plugin": "^6.
|
|
44
|
+
"@wordpress/dependency-extraction-webpack-plugin": "^6.51.0",
|
|
45
45
|
"ansi-html": "^0.0.9",
|
|
46
46
|
"archiver": "^8.0.0",
|
|
47
|
-
"autoprefixer": "^10.5.
|
|
47
|
+
"autoprefixer": "^10.5.3",
|
|
48
48
|
"babel-loader": "^10.1.1",
|
|
49
|
-
"caniuse-lite": "^1.0.
|
|
49
|
+
"caniuse-lite": "^1.0.30001805",
|
|
50
50
|
"chalk": "^5.6.2",
|
|
51
51
|
"chalk-cli": "^6.0.0",
|
|
52
52
|
"classnames": "^2.5.1",
|
|
53
|
-
"cli-truncate": "^6.
|
|
53
|
+
"cli-truncate": "^6.1.1",
|
|
54
54
|
"copy-webpack-plugin": "^14.0.0",
|
|
55
55
|
"cosmiconfig": "^9.0.2",
|
|
56
56
|
"css-loader": "^7.1.4",
|
|
57
57
|
"cssnano": "^8.0.2",
|
|
58
58
|
"dotenv": "^17.4.2",
|
|
59
59
|
"esbuild-loader": "^4.5.0",
|
|
60
|
-
"eslint": "^10.
|
|
61
|
-
"filesize": "^11.0.
|
|
62
|
-
"fs-extra": "^11.3.
|
|
63
|
-
"globby": "^16.2.
|
|
60
|
+
"eslint": "^10.7.0",
|
|
61
|
+
"filesize": "^11.0.22",
|
|
62
|
+
"fs-extra": "^11.3.6",
|
|
63
|
+
"globby": "^16.2.1",
|
|
64
64
|
"html-webpack-plugin": "^5.6.7",
|
|
65
|
-
"
|
|
66
|
-
"humanize-duration": "^3.33.2",
|
|
65
|
+
"humanize-duration": "^3.34.0",
|
|
67
66
|
"image-minimizer-webpack-plugin": "^5.0.0",
|
|
68
67
|
"is-text-path": "^3.0.0",
|
|
69
68
|
"lodash": "^4.18.1",
|
|
70
69
|
"mini-css-extract-plugin": "^2.10.2",
|
|
71
70
|
"ora": "^9.4.1",
|
|
72
|
-
"postcss": "^8.5.
|
|
71
|
+
"postcss": "^8.5.19",
|
|
73
72
|
"postcss-loader": "^8.2.1",
|
|
74
73
|
"postcss-scss": "^4.0.9",
|
|
75
|
-
"prettier": "^3.
|
|
74
|
+
"prettier": "^3.9.5",
|
|
76
75
|
"pretty-hrtime": "^1.0.3",
|
|
77
76
|
"read-package-up": "^12.0.0",
|
|
78
77
|
"replacestream": "^4.0.3",
|
|
@@ -80,25 +79,27 @@
|
|
|
80
79
|
"sass-embedded": "^1.100.0",
|
|
81
80
|
"sass-loader": "^17.0.0",
|
|
82
81
|
"semver": "^7.8.5",
|
|
83
|
-
"sharp": "^0.35.
|
|
82
|
+
"sharp": "^0.35.3",
|
|
84
83
|
"sort-package-json": "^4.0.0",
|
|
85
84
|
"string-length": "^7.0.1",
|
|
86
85
|
"style-loader": "^4.0.0",
|
|
87
|
-
"svgo": "^4.0.
|
|
86
|
+
"svgo": "^4.0.2",
|
|
88
87
|
"svgo-loader": "^5.0.0",
|
|
89
88
|
"version-everything": "^0.12.2",
|
|
90
|
-
"webpack": "^5.108.
|
|
91
|
-
"webpack-bundle-analyzer": "^5.3.
|
|
92
|
-
"webpack-dev-
|
|
93
|
-
"webpack-dev-server": "^5.2.5",
|
|
89
|
+
"webpack": "^5.108.4",
|
|
90
|
+
"webpack-bundle-analyzer": "^5.3.1",
|
|
91
|
+
"webpack-dev-server": "^6.0.0",
|
|
94
92
|
"webpack-manifest-plugin": "^6.0.1"
|
|
95
93
|
},
|
|
96
94
|
"peerDependencies": {
|
|
97
95
|
"webpack-cli": "^6.0.1"
|
|
98
96
|
},
|
|
97
|
+
"engines": {
|
|
98
|
+
"node": ">=22.15.0"
|
|
99
|
+
},
|
|
99
100
|
"devDependencies": {
|
|
100
|
-
"@vitest/coverage-v8": "^4.1.
|
|
101
|
-
"vitest": "^4.1.
|
|
101
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
102
|
+
"vitest": "^4.1.10"
|
|
102
103
|
},
|
|
103
104
|
"version-everything": {
|
|
104
105
|
"files": [
|
|
@@ -106,8 +107,8 @@
|
|
|
106
107
|
]
|
|
107
108
|
},
|
|
108
109
|
"allowScripts": {
|
|
109
|
-
"@parcel/watcher@2.5.1": true,
|
|
110
110
|
"esbuild@0.28.1": true,
|
|
111
|
-
"fsevents@2.3.3": true
|
|
111
|
+
"fsevents@2.3.3": true,
|
|
112
|
+
"@parcel/watcher@2.5.6": true
|
|
112
113
|
}
|
|
113
114
|
}
|
|
@@ -82,15 +82,15 @@ test("Proxy boolean false", async () => {
|
|
|
82
82
|
expect(await devserverProxy({ proxy })).toStrictEqual({ proxy: [] });
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
test("test the returned proxy
|
|
85
|
+
test("test the returned proxy on.error handler", async () => {
|
|
86
86
|
const logSpy = vi.spyOn(console, "log");
|
|
87
87
|
const actual = await devserverProxy({ proxy: true });
|
|
88
88
|
|
|
89
89
|
const err = { code: "ECONNRESET" };
|
|
90
90
|
|
|
91
|
-
actual.proxy[0].
|
|
91
|
+
actual.proxy[0].on.error(err, "req", "res");
|
|
92
92
|
expect(logSpy).toHaveBeenLastCalledWith(
|
|
93
|
-
expect.stringContaining("
|
|
93
|
+
expect.stringContaining("connection reset"),
|
|
94
94
|
);
|
|
95
95
|
|
|
96
96
|
err.code = "Unknown Error Code";
|
|
@@ -99,10 +99,10 @@ test("test the returned proxy onError handler", async () => {
|
|
|
99
99
|
const req = { url: "url" };
|
|
100
100
|
const res = { writeHead: vi.fn(), end: vi.fn() };
|
|
101
101
|
|
|
102
|
-
actual.proxy[0].
|
|
102
|
+
actual.proxy[0].on.error(err, req, res);
|
|
103
103
|
|
|
104
104
|
expect(logSpy).toHaveBeenLastCalledWith(
|
|
105
|
-
expect.stringContaining("
|
|
105
|
+
expect.stringContaining("Proxy error"),
|
|
106
106
|
req.url,
|
|
107
107
|
expect.any(Object),
|
|
108
108
|
err.stack,
|
|
@@ -114,10 +114,10 @@ test("test the returned proxy onError handler", async () => {
|
|
|
114
114
|
);
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
test("
|
|
117
|
+
test("on.proxyRes Handler", async () => {
|
|
118
118
|
const config = { proxy: "http://localhost:3000" };
|
|
119
119
|
const result = await devserverProxy(config);
|
|
120
|
-
const onProxyRes = result.proxy[0].
|
|
120
|
+
const onProxyRes = result.proxy[0].on.proxyRes;
|
|
121
121
|
|
|
122
122
|
const mockProxyRes = new EventEmitter();
|
|
123
123
|
mockProxyRes.statusCode = 200;
|
|
@@ -152,10 +152,10 @@ test("onProxyRes Handler", async () => {
|
|
|
152
152
|
);
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
test("
|
|
155
|
+
test("on.proxyRes Handler passthrough", async () => {
|
|
156
156
|
const config = { proxy: "http://localhost:3000" };
|
|
157
157
|
const result = await devserverProxy(config);
|
|
158
|
-
const onProxyRes = result.proxy[0].
|
|
158
|
+
const onProxyRes = result.proxy[0].on.proxyRes;
|
|
159
159
|
|
|
160
160
|
const mockProxyRes = new EventEmitter();
|
|
161
161
|
mockProxyRes.statusCode = 200;
|
|
@@ -190,9 +190,9 @@ test("onProxyRes Handler passthrough", async () => {
|
|
|
190
190
|
);
|
|
191
191
|
});
|
|
192
192
|
|
|
193
|
-
test("
|
|
193
|
+
test("on.proxyReqWs handler", async () => {
|
|
194
194
|
const result = await devserverProxy({ proxy: "http://example.com" });
|
|
195
|
-
const onProxyReqWs = result.proxy[0].
|
|
195
|
+
const onProxyReqWs = result.proxy[0].on.proxyReqWs;
|
|
196
196
|
|
|
197
197
|
const socket = new EventEmitter();
|
|
198
198
|
const errSpy = vi.spyOn(console, "error");
|
|
@@ -202,7 +202,8 @@ test("onProxyReqWs handler", async () => {
|
|
|
202
202
|
expect(errSpy).not.toHaveBeenCalled();
|
|
203
203
|
|
|
204
204
|
socket.emit("error", { code: "OTHER" });
|
|
205
|
-
expect(errSpy).toHaveBeenCalledWith(
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
expect(errSpy).toHaveBeenCalledWith(
|
|
206
|
+
expect.stringContaining("WebSocket proxy error"),
|
|
207
|
+
{ code: "OTHER" },
|
|
208
|
+
);
|
|
208
209
|
});
|