Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f369287
chore: update some deps
alexander-akait Dec 23, 2025
dbf4522
chore: update execa
alexander-akait Dec 23, 2025
c4b3f75
chore: update script
alexander-akait Dec 23, 2025
372f2b7
chore: revert del-cli
alexander-akait Dec 23, 2025
50c0f52
chore: fix path to jest
alexander-akait Dec 23, 2025
e5312c2
test: fix
alexander-akait Dec 25, 2025
90a0c9c
test: more fixes
alexander-akait Dec 25, 2025
f3b0d16
ci: fix test workflow
alexander-akait Dec 25, 2025
cd4f1f2
test: fix
alexander-akait Dec 25, 2025
80f9479
test: rewrite
alexander-akait Dec 25, 2025
3b9dbb4
test: fix
alexander-akait Dec 25, 2025
172a5cf
test: fix more
alexander-akait Dec 25, 2025
620b5b1
test: fix more
alexander-akait Dec 25, 2025
de2196d
test: fix
alexander-akait Dec 25, 2025
f582544
test: fix
alexander-akait Dec 25, 2025
7d8371a
test: fix
alexander-akait Dec 26, 2025
f999b2f
test: fix
alexander-akait Dec 26, 2025
b5f6f60
test: fix
alexander-akait Jan 12, 2026
0926223
test: fix
alexander-akait Jan 12, 2026
47d2a9e
test: snapshot update
alexander-akait Jan 12, 2026
e223236
test: debug windows
alexander-akait Jan 12, 2026
8f67888
test: debug windows
alexander-akait Jan 12, 2026
c8fee92
test: debug windows
alexander-akait Jan 12, 2026
601030c
test: debug windows
alexander-akait Jan 12, 2026
bae1715
test: debug windows
alexander-akait Jan 12, 2026
4019a0a
test: debug windows
alexander-akait Jan 12, 2026
4faef45
test: refactor count of tests
alexander-akait Jan 13, 2026
4286d3c
test: avoid extra output
alexander-akait Jan 13, 2026
7da2f15
test: improve perf by install common deps
alexander-akait Jan 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
run: npm run build:ci

- name: Run tests and generate coverage
run: npm run test:coverage --ci --shard=${{ matrix.shard }}
run: npm run test:coverage -- --ci --shard=${{ matrix.shard }}

- name: Upload coverage to Codecov
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
Expand Down
4 changes: 2 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ module.exports = {
transform: {
"^.+\\.(ts)?$": "ts-jest",
},
testRegex: ["/test/.*\\.(test.js|test.ts)$"],
moduleFileExtensions: ["ts", "js", "json"],
testRegex: ["/test/.*\\.(test.js|test.cjs|test.mjs|test.ts|test.cts|test.mts)$"],
moduleFileExtensions: ["ts", "cts", "mts", "js", "cjs", "mjs", "json"],
snapshotResolver: "<rootDir>/scripts/snapshot-resolver.js",
setupFilesAfterEnv: ["<rootDir>/scripts/setup-test.js"],
globalTeardown: "<rootDir>/scripts/cleanup-test.js",
Expand Down
1,092 changes: 552 additions & 540 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 7 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,10 @@
"fix": "npm run fix:code",
"fix:code": "npm run lint:code -- --fix",
"pretest": "npm run build && npm run lint",
"test": "jest --reporters=default",
"test": "npm run test:base",
"test:base": "node --experimental-vm-modules ./node_modules/jest-cli/bin/jest",
"test:smoketests": "nyc node smoketests",
"test:coverage": "nyc --no-clean jest",
"test:cli": "jest test --reporters=default",
"test:packages": "jest packages/ --reporters=default",
"test:ci": "npm run test:cli && npm run test:packages",
"test:coverage": "nyc --no-clean npm run test:base -- --coverage",
"publish:monorepo": "npm run build && lerna version && lerna publish from-git",
"update:docs": "node ./scripts/update-docs",
"prepare": "husky"
Expand All @@ -63,7 +61,7 @@
"coffeescript": "^2.7.0",
"colorette": "^2.0.16",
"concat-stream": "^2.0.0",
"cspell": "^8.3.2",
"cspell": "^9.4.0",
"css-loader": "^7.1.2",
"del-cli": "^6.0.0",
"eslint": "^9.29.0",
Expand All @@ -75,13 +73,13 @@
"eslint-plugin-n": "^17.19.0",
"eslint-plugin-prettier": "^5.4.1",
"eslint-plugin-unicorn": "^62.0.0",
"execa": "^5.0.0",
"get-port": "^5.1.1",
"execa": "^9.6.1",
"get-port": "^7.1.0",
"globals": "^16.2.0",
"husky": "^9.1.4",
"jest": "^30.2.0",
"lerna": "^9.0.3",
"lint-staged": "^15.2.9",
"lint-staged": "^16.2.7",
"mini-css-extract-plugin": "^2.6.1",
"nyc": "^17.1.0",
"prettier": "^3.6.0",
Expand Down
6 changes: 3 additions & 3 deletions packages/create-webpack-app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ program
if (generator === undefined) {
logger.warn(`${templateOption} is not a valid template, please select one from below`);
const template = await select<string>({
message: "Select a valid template from below",
message: "Select a valid template from below: (Use arrow keys)",
choices: Object.keys(initGenerators).map((key) => ({
name: key,
value: key.toLowerCase(),
Expand Down Expand Up @@ -140,7 +140,7 @@ program
if (generator === undefined) {
logger.warn(`${templateOption} is not a valid template, please select one from below`);
const template = await select<string>({
message: "Select a valid template from below",
message: "Select a valid template from below: (Use arrow keys)",
choices: Object.keys(loaderGenerators).map((key) => ({
name: key,
value: key.toLowerCase(),
Expand Down Expand Up @@ -181,7 +181,7 @@ program
if (generator === undefined) {
logger.warn(`${templateOption} is not a valid template, please select one from below`);
const template = await select<string>({
message: "Select a valid template from below",
message: "Select a valid template from below: (Use arrow keys)",
choices: Object.keys(pluginGenerators).map((key) => ({
name: key,
value: key.toLowerCase(),
Expand Down
20 changes: 14 additions & 6 deletions scripts/update-docs.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
const { writeFileSync } = require("node:fs");
const { resolve } = require("node:path");
const { sync } = require("execa");
const { version } = require("webpack-dev-server/package.json");

const [majorDevServerVersion] = version.split(".");

try {
const { stdout: cliOptions } = sync(
/**
* @returns {Promise<void>}
*/
async function updateDocs() {
const { execa } = await import("execa");
const { stdout: cliOptions } = await execa(
resolve(__dirname, "../packages/webpack-cli/bin/cli.js"),
["--help=verbose", "--no-color"],
{
Expand All @@ -16,13 +19,13 @@ try {
);

// format output for markdown
const mdContent = ["```\n", cliOptions, "\n```"].join("");
const mdContent = ["```\n", cliOptions, "\n```\n"].join("");

// create OPTIONS.md
writeFileSync("OPTIONS.md", mdContent);

// serve options
const { stdout: serveOptions } = sync(
const { stdout: serveOptions } = await execa(
resolve(__dirname, "../packages/webpack-cli/bin/cli.js"),
["serve", "--help", "--no-color"],
{
Expand All @@ -32,12 +35,17 @@ try {
);

// format output for markdown
const serveContent = ["```\n", serveOptions, "\n```"].join("");
const serveContent = ["```\n", serveOptions, "\n```\n"].join("");

// create SERVE.md
writeFileSync(`SERVE-OPTIONS-v${majorDevServerVersion}.md`, serveContent);

console.log(`Successfully updated "OPTIONS.md" and "SERVE-OPTIONS-v${majorDevServerVersion}.md"`);
}

try {
// eslint-disable-next-line unicorn/prefer-top-level-await
updateDocs();
} catch (err) {
console.error(err);
}
34 changes: 24 additions & 10 deletions smoketests/helpers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const fs = require("node:fs");
const path = require("node:path");
const { stripVTControlCharacters } = require("node:util");
const execa = require("execa");

const ROOT_PATH = process.env.GITHUB_WORKSPACE || path.resolve(__dirname, "..");

Expand All @@ -22,12 +21,16 @@ const swapPkgName = (current, isSubPackage = false) => {

const CLI_ENTRY_PATH = path.resolve(ROOT_PATH, "./packages/webpack-cli/bin/cli.js");

const runTest = (pkg, cliArgs = [], logMessage = undefined, isSubPackage = false) => {
const runTest = async (pkg, cliArgs = [], logMessage = undefined, isSubPackage = false) => {
// Simulate package missing
swapPkgName(pkg, isSubPackage);

const { execa } = await import("execa");
const abortController = new AbortController();
const proc = execa(CLI_ENTRY_PATH, cliArgs, {
cwd: __dirname,
reject: false,
cancelSignal: abortController.signal,
});

proc.stdin.setDefaultEncoding("utf8");
Expand Down Expand Up @@ -61,8 +64,8 @@ const runTest = (pkg, cliArgs = [], logMessage = undefined, isSubPackage = false
}

if (hasLogMessage && hasPrompt) {
abortController.abort();
hasPassed = true;
proc.kill();
}
});

Expand All @@ -80,12 +83,16 @@ const runTest = (pkg, cliArgs = [], logMessage = undefined, isSubPackage = false
});
};

const runTestStdout = ({ packageName, cliArgs, logMessage, isSubPackage } = {}) => {
const runTestStdout = async ({ packageName, cliArgs, logMessage, isSubPackage } = {}) => {
// Simulate package missing
swapPkgName(packageName, isSubPackage);

const { execa } = await import("execa");
const abortController = new AbortController();
const proc = execa(CLI_ENTRY_PATH, cliArgs, {
cwd: __dirname,
reject: false,
cancelSignal: abortController.signal,
});

proc.stdin.setDefaultEncoding("utf8");
Expand All @@ -105,7 +112,7 @@ const runTestStdout = ({ packageName, cliArgs, logMessage, isSubPackage } = {})

if (data.includes(logMessage)) {
hasPassed = true;
proc.kill();
abortController.abort();
}
});

Expand All @@ -128,7 +135,7 @@ const runTestStdout = ({ packageName, cliArgs, logMessage, isSubPackage } = {})
});
};

const runTestStdoutWithInput = ({
const runTestStdoutWithInput = async ({
packageName,
cliArgs,
inputs,
Expand All @@ -138,8 +145,12 @@ const runTestStdoutWithInput = ({
// Simulate package missing
swapPkgName(packageName, isSubPackage);

const { execa } = await import("execa");
const abortController = new AbortController();
const proc = execa(CLI_ENTRY_PATH, cliArgs, {
cwd: __dirname,
reject: false,
cancelSignal: abortController.signal,
});

proc.stdin.setDefaultEncoding("utf8");
Expand All @@ -158,7 +169,7 @@ const runTestStdoutWithInput = ({

if (data.includes(logMessage)) {
hasPassed = true;
proc.kill();
abortController.abort();
}

for (const input of Object.keys(inputs)) {
Expand Down Expand Up @@ -187,16 +198,19 @@ const runTestStdoutWithInput = ({
});
};

const runTestWithHelp = (pkg, cliArgs = [], logMessage = undefined, isSubPackage = false) => {
const runTestWithHelp = async (pkg, cliArgs = [], logMessage = undefined, isSubPackage = false) => {
// Simulate package missing
swapPkgName(pkg, isSubPackage);

const { execa } = await import("execa");
const abortController = new AbortController();
const proc = execa(CLI_ENTRY_PATH, cliArgs, {
cwd: __dirname,
reject: false,
cancelSignal: abortController.signal,
});

proc.stdin.setDefaultEncoding("utf8");

proc.stdout.on("data", (chunk) => {
console.log(` stdout: ${chunk.toString()}`);
});
Expand Down Expand Up @@ -228,7 +242,7 @@ const runTestWithHelp = (pkg, cliArgs = [], logMessage = undefined, isSubPackage

if (hasLogMessage || hasUndefinedLogMessage) {
hasPassed = true;
proc.kill();
abortController.abort();
}
});

Expand Down
9 changes: 5 additions & 4 deletions smoketests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ const tests = [
const passResults = [];
const failResults = [];

for await (const test of tests) {
console.log(`\nRUN ${test.name}`);
for (const test of tests) {
console.log(`RUN ${test.name}`);

let isPass = true;

for await (const testCase of test.run) {
for (const testCase of test.run) {
console.log(`RUN case ${testCase.name}`);
isPass &&= await testCase();
}

Expand All @@ -34,7 +35,7 @@ const tests = [
}
}

console.log("\n\nSummary of smoketest run:");
console.log("\nSummary of smoke tests run:");
console.log(`${failResults.length} tests failed, ${passResults.length} tests passed`);

for (const result of failResults) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
const { existsSync, unlinkSync } = require("node:fs");
const { resolve } = require("node:path");

const execa = require("execa");
const { run } = require("../../../utils/test-utils");

const { sync: spawnSync } = execa;

describe("webpack cli", () => {
it('should work with the "disable-interpret" option from flags', async () => {
const configFileName = "webpack.config";
const configFilePath = resolve(__dirname, `${configFileName}.ts`);
const buildScripts = spawnSync("yarn", ["tsc", configFilePath]);
const { execa } = await import("execa");
const buildScripts = await execa("yarn", ["tsc", configFilePath]);
expect(buildScripts.stdout).toBeTruthy();

const { exitCode, stderr, stdout } = await run(__dirname, ["--disable-interpret"]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"type": "module",
"type": "commonjs",
"engines": {
"node": ">=18.12.0"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"target": "esnext",
"allowImportingTsExtensions": true,
"rewriteRelativeImportExtensions": true,
"module": "esnext"
"module": "commonjs"
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
const { existsSync } = require("node:fs");
const { resolve } = require("node:path");
const { run } = require("../../../utils/test-utils");
import { existsSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { run } from "../../../utils/test-utils.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

describe("webpack cli", () => {
it("should support typescript esnext file", async () => {
Expand All @@ -15,7 +19,7 @@ describe("webpack cli", () => {
WEBPACK_CLI_FORCE_LOAD_ESM_CONFIG: true,
},
// Fallback to `ts-node/esm` for old Node.js versions
nodeOptions: major >= 24 ? [] : ["--experimental-loader=ts-node/esm"],
nodeOptions: major >= 24 ? [] : ["--require=ts-node/register"],
},
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as path from "node:path";
const path = require("node:path");

/* eslint-disable no-useless-concat */

Expand All @@ -13,4 +13,4 @@ const config = {
},
};

export default config;
module.exports = config;
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
const { existsSync } = require("node:fs");
const { resolve } = require("node:path");
const { run } = require("../../../utils/test-utils");
import { existsSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { run } from "../../../utils/test-utils.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

describe("webpack cli", () => {
it("should support typescript esnext file", async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
const { existsSync } = require("node:fs");
const { resolve } = require("node:path");
const { run } = require("../../../utils/test-utils");
import { existsSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { run } from "../../../utils/test-utils.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

describe("webpack cli", () => {
it("should support typescript esnext file", async () => {
Expand Down
Loading
Loading