Skip to content
  • Sponsor webpack/webpack-dev-server

  • Notifications You must be signed in to change notification settings
  • Fork 1.5k

chore(deps): update chokidar to v4 #5374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -6,3 +6,4 @@ node_modules
examples/**/main.js
examples/client/trusted-types-overlay/app.js
test/fixtures/reload-config/foo.js
test/fixtures/worker-config-dev-server-false/public/worker-bundle.js
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ yarn-error.log

test/fixtures/static-config/public/assets/non-exist.txt
test/fixtures/watch-files-config/public/assets/non-exist.txt
test/fixtures/watch-files-config/public/non-existant/non-exist.txt
test/fixtures/reload-config/main.css
test/fixtures/reload-config-2/main.css
test/fixtures/worker-config-dev-server-false/public
35 changes: 32 additions & 3 deletions lib/Server.js
Original file line number Diff line number Diff line change
@@ -8,6 +8,10 @@ const fs = require("graceful-fs");
const ipaddr = require("ipaddr.js");
const { validate } = require("schema-utils");
const schema = require("./options.json");
const {
getGlobbedWatcherPaths,
getIgnoreMatchers,
} = require("./getGlobMatchers");

/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
/** @typedef {import("webpack").Compiler} Compiler */
@@ -18,7 +22,7 @@ const schema = require("./options.json");
/** @typedef {import("webpack").Stats} Stats */
/** @typedef {import("webpack").MultiStats} MultiStats */
/** @typedef {import("os").NetworkInterfaceInfo} NetworkInterfaceInfo */
/** @typedef {import("chokidar").WatchOptions} WatchOptions */
/** @typedef {import("chokidar").ChokidarOptions & { disableGlobbing?: boolean }} WatchOptions */
/** @typedef {import("chokidar").FSWatcher} FSWatcher */
/** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */
/** @typedef {import("bonjour-service").Bonjour} Bonjour */
@@ -312,6 +316,19 @@ function useFn(route, fn) {
* @property {typeof useFn} use
*/

/**
* @template {Record<string, any>} T
* @param {T} obj
* @returns {T}
*/
function removeUndefinedValues(obj) {
return /** @type {T} **/ (
Object.fromEntries(
Object.entries(obj).filter(([, value]) => typeof value !== "undefined"),
)
);
}

/**
* @template {BasicApplication} [A=ExpressApplication]
* @template {BasicServer} [S=HTTPServer]
@@ -3255,9 +3272,21 @@ class Server {
* @param {string | string[]} watchPath
* @param {WatchOptions} [watchOptions]
*/
watchFiles(watchPath, watchOptions) {
watchFiles(watchPath, watchOptions = {}) {
const chokidar = require("chokidar");
const watcher = chokidar.watch(watchPath, watchOptions);

const [watchPaths, ignoreFunction] = getGlobbedWatcherPaths(
watchPath,
watchOptions,
);

watchOptions.ignored = getIgnoreMatchers(watchOptions, ignoreFunction);

const watcher = chokidar.watch(
watchPaths,
// https://github.com/paulmillr/chokidar/issues/1394
removeUndefinedValues(watchOptions),
);

// disabling refreshing on changing the content
if (this.options.liveReload) {
76 changes: 76 additions & 0 deletions lib/getGlobMatchers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"use strict";

module.exports = {
/**
* @param {string[] | string} _watchPaths
* @param {import("./Server").WatchOptions} watchOptions
* @returns {[string[], import("chokidar").MatchFunction | null]}*/
getGlobbedWatcherPaths(_watchPaths, { disableGlobbing, cwd }) {
const watchPaths = Array.isArray(_watchPaths) ? _watchPaths : [_watchPaths];

if (disableGlobbing === true) {
return [watchPaths, null];
}

const picomatch = require("picomatch");
const isGlob = require("is-glob");
const watchPathGlobs = watchPaths.filter((p) => isGlob(p));

if (watchPathGlobs.length === 0) {
return [watchPaths, null];
}

const globParent = require("glob-parent");

watchPathGlobs.forEach((p) => {
watchPaths[watchPaths.indexOf(p)] = globParent(p);
});

const matcher = picomatch(watchPathGlobs, { cwd, dot: true });

/** @type {import("chokidar").MatchFunction} */
const ignoreFunction = (p) => !watchPaths.includes(p) && !matcher(p);

// Ignore all paths that don't match any of the globs
return [watchPaths, ignoreFunction];
},

/**
*
* @param {import("./Server").WatchOptions} watchOptions
* @param {import("chokidar").MatchFunction | null } ignoreFunction
* @returns {import("chokidar").Matcher[]}
*/
getIgnoreMatchers({ disableGlobbing, ignored, cwd }, ignoreFunction) {
const _ignored = /** @type {import("chokidar").Matcher[]}**/ (
typeof ignored === "undefined" ? [] : [ignored]
);
const matchers = Array.isArray(ignored) ? ignored : _ignored;

if (disableGlobbing === true) {
return matchers;
}

if (ignoreFunction) {
matchers.push(ignoreFunction);
}

const picomatch = require("picomatch");
const isGlob = require("is-glob");

// Double filter to satisfy typescript. Otherwise nasty casting is required
const ignoredGlobs = matchers
.filter((s) => typeof s === "string")
.filter((s) => isGlob(s));

if (ignoredGlobs.length === 0) {
return matchers;
}

const matcher = picomatch(ignoredGlobs, { cwd, dot: true });

matchers.push(matcher);

return matchers.filter((s) => typeof s !== "string" || !isGlob(s));
},
};
208 changes: 153 additions & 55 deletions package-lock.json
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -55,17 +55,20 @@
"@types/ws": "^8.5.10",
"ansi-html-community": "^0.0.8",
"bonjour-service": "^1.2.1",
"chokidar": "^3.6.0",
"chokidar": "^4.0.3",
"colorette": "^2.0.10",
"compression": "^1.7.4",
"connect-history-api-fallback": "^2.0.0",
"express": "^4.21.2",
"glob-parent": "^6.0.2",
"graceful-fs": "^4.2.6",
"http-proxy-middleware": "^2.0.7",
"ipaddr.js": "^2.1.0",
"is-glob": "^4.0.3",
"launch-editor": "^2.6.1",
"open": "^10.0.3",
"p-retry": "^6.2.0",
"picomatch": "^4.0.2",
"schema-utils": "^4.2.0",
"selfsigned": "^2.4.1",
"serve-index": "^1.9.1",
@@ -86,8 +89,11 @@
"@commitlint/config-conventional": "^19.5.0",
"@hono/node-server": "^1.13.3",
"@types/compression": "^1.7.2",
"@types/glob-parent": "^5.1.3",
"@types/is-glob": "^4.0.4",
"@types/node": "^22.8.4",
"@types/node-forge": "^1.3.1",
"@types/picomatch": "^3.0.1",
"@types/sockjs-client": "^1.5.1",
"@types/trusted-types": "^2.0.2",
"acorn": "^8.14.0",
34 changes: 20 additions & 14 deletions test/e2e/__snapshots__/watch-files.test.js.snap.webpack5
Original file line number Diff line number Diff line change
@@ -20,6 +20,16 @@ exports[`watchFiles option should work with array config should reload when file

exports[`watchFiles option should work with array config should reload when file content is changed: response status 1`] = `200`;

exports[`watchFiles option should work with glob when creating nested directory should reload when file content is changed: console messages 1`] = `
[
"Hey.",
]
`;

exports[`watchFiles option should work with glob when creating nested directory should reload when file content is changed: page errors 1`] = `[]`;

exports[`watchFiles option should work with glob when creating nested directory should reload when file content is changed: response status 1`] = `200`;

exports[`watchFiles option should work with object with multiple paths should reload when file content is changed: console messages 1`] = `
[
"Hey.",
@@ -47,7 +57,7 @@ exports[`watchFiles option should work with options {"interval":400,"poll":200}
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"ignored": [],
"interval": 400,
"persistent": true,
"usePolling": true,
@@ -71,7 +81,7 @@ exports[`watchFiles option should work with options {"poll":200} should reload w
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"ignored": [],
"interval": 200,
"persistent": true,
"usePolling": true,
@@ -95,8 +105,7 @@ exports[`watchFiles option should work with options {"poll":true} should reload
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"interval": undefined,
"ignored": [],
"persistent": true,
"usePolling": true,
}
@@ -119,7 +128,7 @@ exports[`watchFiles option should work with options {"usePolling":false,"interva
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"ignored": [],
"interval": 200,
"persistent": true,
"usePolling": false,
@@ -143,7 +152,7 @@ exports[`watchFiles option should work with options {"usePolling":false,"poll":2
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"ignored": [],
"interval": 200,
"persistent": true,
"usePolling": false,
@@ -167,8 +176,7 @@ exports[`watchFiles option should work with options {"usePolling":false,"poll":t
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"interval": undefined,
"ignored": [],
"persistent": true,
"usePolling": false,
}
@@ -191,8 +199,7 @@ exports[`watchFiles option should work with options {"usePolling":false} should
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"interval": undefined,
"ignored": [],
"persistent": true,
"usePolling": false,
}
@@ -215,7 +222,7 @@ exports[`watchFiles option should work with options {"usePolling":true,"interval
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"ignored": [],
"interval": 200,
"persistent": true,
"usePolling": true,
@@ -239,7 +246,7 @@ exports[`watchFiles option should work with options {"usePolling":true,"poll":20
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"ignored": [],
"interval": 200,
"persistent": true,
"usePolling": true,
@@ -263,8 +270,7 @@ exports[`watchFiles option should work with options {"usePolling":true} should r
"followSymlinks": false,
"ignoreInitial": true,
"ignorePermissionErrors": true,
"ignored": undefined,
"interval": undefined,
"ignored": [],
"persistent": true,
"usePolling": true,
}
83 changes: 83 additions & 0 deletions test/e2e/watch-files.test.js
Original file line number Diff line number Diff line change
@@ -309,6 +309,89 @@ describe("watchFiles option", () => {
});
});

describe("should work with glob when creating nested directory", () => {
const nonExistFile = path.join(watchDir, "non-existant/non-exist.txt");
let compiler;
let server;
let page;
let browser;
let pageErrors;
let consoleMessages;

beforeEach(async () => {
try {
fs.unlinkSync(nonExistFile);
fs.rmdirSync(path.join(watchDir, "non-existant"));
} catch (error) {
// ignore
}

compiler = webpack(config);

server = new Server(
{
watchFiles: `${watchDir}/**/*`,
port,
},
compiler,
);

await server.start();

({ page, browser } = await runBrowser());

pageErrors = [];
consoleMessages = [];
});

afterEach(async () => {
await browser.close();
await server.stop();
});

it("should reload when file content is changed", async () => {
page
.on("console", (message) => {
consoleMessages.push(message);
})
.on("pageerror", (error) => {
pageErrors.push(error);
});

const response = await page.goto(`http://127.0.0.1:${port}/`, {
waitUntil: "networkidle0",
});

expect(response.status()).toMatchSnapshot("response status");

expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
"console messages",
);

expect(pageErrors).toMatchSnapshot("page errors");

await new Promise((resolve) => {
server.staticWatchers[0].on("change", async (changedPath) => {
// page reload
await page.waitForNavigation({ waitUntil: "networkidle0" });

expect(changedPath).toBe(nonExistFile);
resolve();
});

// create file content
setTimeout(() => {
fs.mkdirSync(path.join(watchDir, "non-existant"));
fs.writeFileSync(nonExistFile, "Kurosaki Ichigo", "utf8");
// change file content
setTimeout(() => {
fs.writeFileSync(nonExistFile, "Kurosaki Ichigo", "utf8");
}, 1000);
}, 1000);
});
});
});

describe("should work with object with single path", () => {
const file = path.join(watchDir, "assets/example.txt");
let compiler;
159 changes: 159 additions & 0 deletions test/unit/globIgnoreMatchers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
"use strict";

const { getIgnoreMatchers } = require("../../lib/getGlobMatchers");

describe("getIgnoreMatchers", () => {
it("should return an array of matchers for glob strings", () => {
const watchOptions = {
cwd: process.cwd(),
ignored: ["src/*.js", "tests/*.spec.js"],
};
const matchers = getIgnoreMatchers(watchOptions, null);

expect(matchers).toHaveLength(1);
expect(typeof matchers[0]).toBe("function");
});

it("should return the original value for non-glob strings", () => {
const watchOptions = { cwd: process.cwd(), ignored: "src/file.txt" };
const matchers = getIgnoreMatchers(watchOptions, null);

expect(matchers).toHaveLength(1);
expect(matchers[0]).toBe("src/file.txt");
});

it("should return empty array if ignored is not defined", () => {
const watchOptions = { cwd: process.cwd() };
const matchers = getIgnoreMatchers(watchOptions, null);

expect(matchers).toEqual([]);
});

it("should return an array that includes the passed matcher function", () => {
const watchOptions = { cwd: process.cwd() };
const ignoreFunction = () => true;
const matchers = getIgnoreMatchers(watchOptions, ignoreFunction);

expect(matchers).toHaveLength(1);
expect(matchers[0]).toBe(ignoreFunction);
});

it("should return all original value and only replace all globs with one function", () => {
const ignoreFunction = () => true;
const regex = /src\/.*\.js/;
const watchOptions = {
cwd: process.cwd(),
ignored: [
"src/*.js",
"src/file.txt",
"src/**/*.js",
ignoreFunction,
regex,
],
};

const matchers = getIgnoreMatchers(watchOptions, ignoreFunction);

expect(matchers).toHaveLength(5);
expect(matchers[0]).toBe("src/file.txt");
expect(matchers[1]).toBe(ignoreFunction);
expect(matchers[2]).toBe(regex);
expect(matchers[3]).toBe(ignoreFunction);
expect(typeof matchers[4]).toBe("function");
});

it("should work with complicated glob", () => {
const watchOptions = {
cwd: process.cwd(),
ignored: ["src/**/components/*.js"],
};
const matchers = getIgnoreMatchers(watchOptions, null);

expect(matchers).toHaveLength(1);
expect(typeof matchers[0]).toBe("function");

const filePath = "src/components/file.txt";
expect(matchers[0](filePath)).toBe(false);

const jsFilePath = "src/components/file.js";
expect(matchers[0](jsFilePath)).toBe(true);

const jsFilePath2 = "src/other/components/file.js";
expect(matchers[0](jsFilePath2)).toBe(true);

const nestedJsFilePath = "src/components/nested/file.js";
expect(matchers[0](nestedJsFilePath)).toBe(false);
});

it("should work with negated glob", () => {
const watchOptions = {
cwd: process.cwd(),
ignored: ["src/**/components/!(*.spec).js"],
};
const matchers = getIgnoreMatchers(watchOptions, null);

expect(matchers).toHaveLength(1);
expect(typeof matchers[0]).toBe("function");

const filePath = "src/components/file.txt";
expect(matchers[0](filePath)).toBe(false);

const jsFilePath = "src/components/file.js";
expect(matchers[0](jsFilePath)).toBe(true);

const specJsFilePath = "src/components/file.spec.js";
expect(matchers[0](specJsFilePath)).toBe(false);
});

it("should work with directory glob", () => {
const watchOptions = { cwd: process.cwd(), ignored: ["src/**"] };
const matchers = getIgnoreMatchers(watchOptions, null);

expect(matchers).toHaveLength(1);
expect(typeof matchers[0]).toBe("function");

const filePath = "src/file.txt";
expect(matchers[0](filePath)).toBe(true);

const dirPath = "src/subdir";
expect(matchers[0](dirPath)).toBe(true);

const nestedFilePath = "src/subdir/nested/file.txt";
expect(matchers[0](nestedFilePath)).toBe(true);

const wrongPath = "foo/bar";
expect(matchers[0](wrongPath)).toBe(false);
});

it("should work with directory glob and file extension", () => {
const watchOptions = { cwd: process.cwd(), ignored: ["src/**/*.{js,ts}"] };
const matchers = getIgnoreMatchers(watchOptions, null);

expect(matchers).toHaveLength(1);
expect(typeof matchers[0]).toBe("function");

const jsFilePath = "src/file.js";
expect(matchers[0](jsFilePath)).toBe(true);

const tsFilePath = "src/file.ts";
expect(matchers[0](tsFilePath)).toBe(true);

const txtFilePath = "src/file.txt";
expect(matchers[0](txtFilePath)).toBe(false);

const nestedJsFilePath = "src/subdir/nested/file.js";
expect(matchers[0](nestedJsFilePath)).toBe(true);
});

it("should return the input as array when globbing is disabled", () => {
const watchOptions = {
cwd: process.cwd(),
disableGlobbing: true,
ignored: "src/**/*.{js,ts}",
};
const matchers = getIgnoreMatchers(watchOptions, null);

expect(matchers).toHaveLength(1);
expect(matchers[0]).toBe("src/**/*.{js,ts}");
});
});
140 changes: 140 additions & 0 deletions test/unit/globWatchers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
"use strict";

const { getGlobbedWatcherPaths } = require("../../lib/getGlobMatchers");

describe("getGlobbedWatcherPaths", () => {
it("should watch the parent directory of the glob", () => {
const glob = "src/*.js";
const watchOptions = { cwd: process.cwd() };
const [watchPaths] = getGlobbedWatcherPaths(glob, watchOptions);

expect(watchPaths).toEqual(["src"]);
});

it("should ignore files that are not part of the glob", () => {
const glob = "src/*.js";
const watchOptions = { cwd: process.cwd() };
const [, ignoreFunction] = getGlobbedWatcherPaths(glob, watchOptions);

const filePath = "src/file.txt";
expect(ignoreFunction(filePath)).toBe(true);

const jsFilePath = "src/file.js";
expect(ignoreFunction(jsFilePath)).toBe(false);
});

it("should work with multiple globs", () => {
const globs = ["src/*.js", "tests/*.spec.js"];
const watchOptions = { cwd: process.cwd() };
const [watchPaths, ignoreFunction] = getGlobbedWatcherPaths(
globs,
watchOptions,
);

expect(watchPaths).toEqual(["src", "tests"]);

const filePath = "src/file.txt";
expect(ignoreFunction(filePath)).toBe(true);

const jsFilePath = "src/file.js";
expect(ignoreFunction(jsFilePath)).toBe(false);

const specFilePath = "tests/file.spec.js";
expect(ignoreFunction(specFilePath)).toBe(false);
});

it("should work with complicated glob", () => {
const glob = "src/**/components/*.js";
const watchOptions = { cwd: process.cwd() };
const [watchPaths, ignoreFunction] = getGlobbedWatcherPaths(
glob,
watchOptions,
);

expect(watchPaths).toEqual(["src"]);

const filePath = "src/components/file.txt";
expect(ignoreFunction(filePath)).toBe(true);

const jsFilePath = "src/components/file.js";
expect(ignoreFunction(jsFilePath)).toBe(false);

const nestedJsFilePath = "src/components/nested/file.js";
expect(ignoreFunction(nestedJsFilePath)).toBe(true);
});

it("should work with negated glob", () => {
const glob = "src/**/components/!(*.spec).js";
const watchOptions = { cwd: process.cwd() };
const [watchPaths, ignoreFunction] = getGlobbedWatcherPaths(
glob,
watchOptions,
);

expect(watchPaths).toEqual(["src"]);

const filePath = "src/components/file.txt";
expect(ignoreFunction(filePath)).toBe(true);

const jsFilePath = "src/components/file.js";
expect(ignoreFunction(jsFilePath)).toBe(false);

const specJsFilePath = "src/components/file.spec.js";
expect(ignoreFunction(specJsFilePath)).toBe(true);
});

it("should work with directory glob", () => {
const glob = "src/**";
const watchOptions = { cwd: process.cwd() };
const [watchPaths, ignoreFunction] = getGlobbedWatcherPaths(
glob,
watchOptions,
);

expect(watchPaths).toEqual(["src"]);

const filePath = "src/file.txt";
expect(ignoreFunction(filePath)).toBe(false);

const dirPath = "src/subdir";
expect(ignoreFunction(dirPath)).toBe(false);

const nestedFilePath = "src/subdir/nested/file.txt";
expect(ignoreFunction(nestedFilePath)).toBe(false);
});

it("should work with directory glob and file extension", () => {
const glob = "src/**/*.{js,ts}";
const watchOptions = { cwd: process.cwd() };
const [watchPaths, ignoreFunction] = getGlobbedWatcherPaths(
glob,
watchOptions,
);

expect(watchPaths).toEqual(["src"]);

const jsFilePath = "src/file.js";
expect(ignoreFunction(jsFilePath)).toBe(false);

const tsFilePath = "src/file.ts";
expect(ignoreFunction(tsFilePath)).toBe(false);

const txtFilePath = "src/file.txt";
expect(ignoreFunction(txtFilePath)).toBe(true);

const nestedJsFilePath = "src/subdir/nested/file.js";
expect(ignoreFunction(nestedJsFilePath)).toBe(false);
});

it("should return the input as array when globbing is disabled", () => {
const glob = "src/**/*.{js,ts}";
const watchOptions = { cwd: process.cwd(), disableGlobbing: true };
const [watchPaths, ignoreFunction] = getGlobbedWatcherPaths(
glob,
watchOptions,
);

expect(watchPaths).toEqual(["src/**/*.{js,ts}"]);
expect(ignoreFunction).toBe(null);
});
});
68 changes: 57 additions & 11 deletions types/lib/Server.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
export = Server;
/**
* @typedef {Object} BasicApplication
* @property {typeof useFn} use
*/
/**
* @template {BasicApplication} [A=ExpressApplication]
* @template {BasicServer} [S=HTTPServer]
@@ -1402,6 +1398,7 @@ declare class Server<
declare namespace Server {
export {
DEFAULT_STATS,
BasicApplication,
Schema,
Compiler,
MultiCompiler,
@@ -1469,12 +1466,14 @@ declare namespace Server {
Middleware,
BasicServer,
Configuration,
BasicApplication,
};
}
declare class DEFAULT_STATS {
private constructor();
}
type BasicApplication = {
use: typeof useFn;
};
type Schema = import("schema-utils/declarations/validate").Schema;
type Compiler = import("webpack").Compiler;
type MultiCompiler = import("webpack").MultiCompiler;
@@ -1484,7 +1483,9 @@ type StatsCompilation = import("webpack").StatsCompilation;
type Stats = import("webpack").Stats;
type MultiStats = import("webpack").MultiStats;
type NetworkInterfaceInfo = import("os").NetworkInterfaceInfo;
type WatchOptions = import("chokidar").WatchOptions;
type WatchOptions = import("chokidar").ChokidarOptions & {
disableGlobbing?: boolean;
};
type FSWatcher = import("chokidar").FSWatcher;
type ConnectHistoryApiFallbackOptions =
import("connect-history-api-fallback").Options;
@@ -1550,7 +1551,31 @@ type Port = number | string | "auto";
type WatchFiles = {
paths: string | string[];
options?:
| (import("chokidar").WatchOptions & {
| (Partial<
{
persistent: boolean;
ignoreInitial: boolean;
followSymlinks: boolean;
cwd?: string;
usePolling: boolean;
interval: number;
binaryInterval: number;
alwaysStat?: boolean;
depth?: number;
ignorePermissionErrors: boolean;
atomic: boolean | number;
} & {
ignored: import("chokidar").Matcher | import("chokidar").Matcher[];
awaitWriteFinish:
| boolean
| Partial<{
stabilityThreshold: number;
pollInterval: number;
}>;
}
> & {
disableGlobbing?: boolean;
} & {
aggregateTimeout?: number;
ignored?: WatchOptions["ignored"];
poll?: number | boolean;
@@ -1568,7 +1593,31 @@ type Static = {
| undefined;
watch?:
| boolean
| (import("chokidar").WatchOptions & {
| (Partial<
{
persistent: boolean;
ignoreInitial: boolean;
followSymlinks: boolean;
cwd?: string;
usePolling: boolean;
interval: number;
binaryInterval: number;
alwaysStat?: boolean;
depth?: number;
ignorePermissionErrors: boolean;
atomic: boolean | number;
} & {
ignored: import("chokidar").Matcher | import("chokidar").Matcher[];
awaitWriteFinish:
| boolean
| Partial<{
stabilityThreshold: number;
pollInterval: number;
}>;
}
> & {
disableGlobbing?: boolean;
} & {
aggregateTimeout?: number;
ignored?: WatchOptions["ignored"];
poll?: number | boolean;
@@ -1763,9 +1812,6 @@ type Configuration<
| ((middlewares: Middleware[], devServer: Server<A, S>) => Middleware[])
| undefined;
};
type BasicApplication = {
use: typeof useFn;
};
/**
* @overload
* @param {NextHandleFunction} fn
18 changes: 18 additions & 0 deletions types/lib/getGlobMatchers.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @param {string[] | string} _watchPaths
* @param {import("./Server").WatchOptions} watchOptions
* @returns {[string[], import("chokidar").MatchFunction | null]}*/
export function getGlobbedWatcherPaths(
_watchPaths: string[] | string,
{ disableGlobbing, cwd }: import("./Server").WatchOptions,
): [string[], import("chokidar").MatchFunction | null];
/**
*
* @param {import("./Server").WatchOptions} watchOptions
* @param {import("chokidar").MatchFunction | null } ignoreFunction
* @returns {import("chokidar").Matcher[]}
*/
export function getIgnoreMatchers(
{ disableGlobbing, ignored, cwd }: import("./Server").WatchOptions,
ignoreFunction: import("chokidar").MatchFunction | null,
): import("chokidar").Matcher[];