Skip to content

Commit

Permalink
feat: allow to pass all chokidar options (#4025)
Browse files Browse the repository at this point in the history
  • Loading branch information
snitin315 committed Nov 25, 2021
1 parent 7e78bfa commit 5026601
Show file tree
Hide file tree
Showing 6 changed files with 1,344 additions and 172 deletions.
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,
};
};
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,
};
}

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

0 comments on commit 5026601

Please sign in to comment.