Skip to content
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

feat: allow to pass all options from chokidar #4025

Merged
merged 8 commits into from Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
207 changes: 135 additions & 72 deletions lib/Server.js
Expand Up @@ -444,14 +444,125 @@ class Server {

const compilerOptions = this.getCompilerOptions();
// TODO remove `{}` after drop webpack v4 support
const watchOptions = compilerOptions.watchOptions || {};
const defaultOptionsForStatic = {
directory: path.join(process.cwd(), "public"),
staticOptions: {},
publicPath: ["/"],
serveIndex: { icons: true },
// Respect options from compiler watchOptions
watch: watchOptions,
const compilerWatchOptions = compilerOptions.watchOptions || {};
const getWatchOptions = (watchOptions = {}) => {
const getPolling = () => {
if (typeof watchOptions.usePolling !== "undefined") {
return watchOptions.usePolling;
}

if (typeof watchOptions.poll !== "undefined") {
return Boolean(watchOptions.poll);
}

if (typeof compilerWatchOptions.poll !== "undefined") {
return Boolean(compilerWatchOptions.poll);
}

return false;
};
const getInterval = () => {
if (typeof watchOptions.interval !== "undefined") {
return watchOptions.interval;
}

if (typeof watchOptions.poll === "number") {
return watchOptions.poll;
}

if (typeof compilerWatchOptions.poll === "number") {
return compilerWatchOptions.poll;
}
};

const usePolling = getPolling();
const interval = getInterval();
const { poll, ...rest } = watchOptions;

return {
ignoreInitial: true,
persistent: true,
followSymlinks: false,
atomic: false,
alwaysStat: true,
ignorePermissionErrors: true,
// Respect options from compiler watchOptions
usePolling,
interval,
ignored: watchOptions.ignored,
// TODO: we respect these options for all watch options and allow developers to pass them to chokidar, but chokidar doesn't have these options maybe we need revisit that in future
...rest,
};
};
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
const getStaticItem = (optionsForStatic) => {
const getDefaultStaticOptions = () => {
return {
directory: path.join(process.cwd(), "public"),
staticOptions: {},
publicPath: ["/"],
serveIndex: { icons: true },
watch: getWatchOptions(),
};
};

let item;

if (typeof optionsForStatic === "undefined") {
item = getDefaultStaticOptions();
} else if (typeof optionsForStatic === "string") {
item = {
...getDefaultStaticOptions(),
directory: optionsForStatic,
};
} else {
const def = getDefaultStaticOptions();

item = {
directory:
typeof optionsForStatic.directory !== "undefined"
? optionsForStatic.directory
: def.directory,
// TODO: do merge in the next major release
staticOptions:
typeof optionsForStatic.staticOptions !== "undefined"
? optionsForStatic.staticOptions
: def.staticOptions,
publicPath:
typeof optionsForStatic.publicPath !== "undefined"
? optionsForStatic.publicPath
: def.publicPath,
// TODO: do merge in the next major release
serveIndex:
// eslint-disable-next-line no-nested-ternary
typeof optionsForStatic.serveIndex !== "undefined"
? typeof optionsForStatic.serveIndex === "boolean" &&
optionsForStatic.serveIndex
? def.serveIndex
: optionsForStatic.serveIndex
: def.serveIndex,
watch:
// eslint-disable-next-line no-nested-ternary
typeof optionsForStatic.watch !== "undefined"
? // eslint-disable-next-line no-nested-ternary
typeof optionsForStatic.watch === "boolean"
? optionsForStatic.watch
? def.watch
: false
: getWatchOptions(optionsForStatic.watch)
: def.watch,
};
}
snitin315 marked this conversation as resolved.
Show resolved Hide resolved

if (Server.isAbsoluteURL(item.directory)) {
throw new Error("Using a URL as static.directory is not supported");
}

// ensure that publicPath is an array
if (typeof item.publicPath === "string") {
item.publicPath = [item.publicPath];
}

return item;
};

if (typeof options.allowedHosts === "undefined") {
Expand Down Expand Up @@ -921,50 +1032,27 @@ class Server {
}

if (typeof options.static === "undefined") {
options.static = [defaultOptionsForStatic];
options.static = [getStaticItem()];
} else if (typeof options.static === "boolean") {
options.static = options.static ? [defaultOptionsForStatic] : false;
options.static = options.static ? [getStaticItem()] : false;
} else if (typeof options.static === "string") {
options.static = [
{ ...defaultOptionsForStatic, directory: options.static },
];
options.static = [getStaticItem(options.static)];
} else if (Array.isArray(options.static)) {
options.static = options.static.map((item) => {
if (typeof item === "string") {
return { ...defaultOptionsForStatic, directory: item };
return getStaticItem(item);
}

return { ...defaultOptionsForStatic, ...item };
return getStaticItem(item);
});
} else {
options.static = [{ ...defaultOptionsForStatic, ...options.static }];
}

if (options.static) {
options.static.forEach((staticOption) => {
if (Server.isAbsoluteURL(staticOption.directory)) {
throw new Error("Using a URL as static.directory is not supported");
}

// ensure that publicPath is an array
if (typeof staticOption.publicPath === "string") {
staticOption.publicPath = [staticOption.publicPath];
}

// ensure that watch is an object if true
if (staticOption.watch === true) {
staticOption.watch = defaultOptionsForStatic.watch;
}

// ensure that serveIndex is an object if true
if (staticOption.serveIndex === true) {
staticOption.serveIndex = defaultOptionsForStatic.serveIndex;
}
});
options.static = [getStaticItem(options.static)];
}

if (typeof options.watchFiles === "string") {
options.watchFiles = [{ paths: options.watchFiles, options: {} }];
options.watchFiles = [
{ paths: options.watchFiles, options: getWatchOptions() },
];
} else if (
typeof options.watchFiles === "object" &&
options.watchFiles !== null &&
Expand All @@ -973,16 +1061,19 @@ class Server {
options.watchFiles = [
{
paths: options.watchFiles.paths,
options: options.watchFiles.options || {},
options: getWatchOptions(options.watchFiles.options || {}),
},
];
} else if (Array.isArray(options.watchFiles)) {
options.watchFiles = options.watchFiles.map((item) => {
if (typeof item === "string") {
return { paths: item, options: {} };
return { paths: item, options: getWatchOptions() };
}

return { paths: item.paths, options: item.options || {} };
return {
paths: item.paths,
options: getWatchOptions(item.options || {}),
};
});
} else {
options.watchFiles = [];
Expand Down Expand Up @@ -2124,36 +2215,8 @@ class Server {
}

watchFiles(watchPath, watchOptions) {
// duplicate the same massaging of options that watchpack performs
// https://github.com/webpack/watchpack/blob/master/lib/DirectoryWatcher.js#L49
// this isn't an elegant solution, but we'll improve it in the future
const usePolling =
typeof watchOptions.usePolling !== "undefined"
? watchOptions.usePolling
: Boolean(watchOptions.poll);
const interval =
// eslint-disable-next-line no-nested-ternary
typeof watchOptions.interval !== "undefined"
? watchOptions.interval
: typeof watchOptions.poll === "number"
? watchOptions.poll
: // eslint-disable-next-line no-undefined
undefined;

const finalWatchOptions = {
ignoreInitial: true,
persistent: true,
followSymlinks: false,
atomic: false,
alwaysStat: true,
ignorePermissionErrors: true,
ignored: watchOptions.ignored,
usePolling,
interval,
};

const chokidar = require("chokidar");
const watcher = chokidar.watch(watchPath, finalWatchOptions);
const watcher = chokidar.watch(watchPath, watchOptions);

// disabling refreshing on changing the content
if (this.options.liveReload) {
Expand Down