@jsenv/core
Version:
Tool to develop, test and build js projects
120 lines (115 loc) • 4.09 kB
JavaScript
import {
lookupPackageDirectory,
registerDirectoryLifecycle,
} from "@jsenv/filesystem";
import { urlToRelativeUrl } from "@jsenv/urls";
import { readFileSync } from "node:fs";
export const getDirectoryWatchPatterns = (
directoryUrl,
watchedDirectoryUrl,
{ sourceFilesConfig },
) => {
const directoryUrlRelativeToWatchedDirectory = urlToRelativeUrl(
directoryUrl,
watchedDirectoryUrl,
);
const watchPatterns = {
[`${directoryUrlRelativeToWatchedDirectory}**/*`]: true, // by default watch everything inside the source directory
[`${directoryUrlRelativeToWatchedDirectory}**/.*`]: false, // file starting with a dot -> do not watch
[`${directoryUrlRelativeToWatchedDirectory}**/.*/`]: false, // directory starting with a dot -> do not watch
[`${directoryUrlRelativeToWatchedDirectory}**/node_modules/`]: false, // node_modules directory -> do not watch
};
for (const key of Object.keys(sourceFilesConfig)) {
watchPatterns[`${directoryUrlRelativeToWatchedDirectory}${key}`] =
sourceFilesConfig[key];
}
return watchPatterns;
};
export const watchSourceFiles = (
sourceDirectoryUrl,
callback,
{ sourceFilesConfig = {}, keepProcessAlive, cooldownBetweenFileEvents },
) => {
// Project should use a dedicated directory (usually "src/")
// passed to the dev server via "sourceDirectoryUrl" param
// In that case all files inside the source directory should be watched
// But some project might want to use their root directory as source directory
// In that case source directory might contain files matching "node_modules/*" or ".git/*"
// And jsenv should not consider these as source files and watch them (to not hurt performances)
const watchPatterns = {};
let watchedDirectoryUrl = "";
const addDirectoryToWatch = (directoryUrl) => {
Object.assign(
watchPatterns,
getDirectoryWatchPatterns(directoryUrl, watchedDirectoryUrl, {
sourceFilesConfig,
}),
);
};
const watch = () => {
const stopWatchingSourceFiles = registerDirectoryLifecycle(
watchedDirectoryUrl,
{
watchPatterns,
cooldownBetweenFileEvents,
keepProcessAlive,
recursive: true,
added: ({ relativeUrl }) => {
callback({
url: new URL(relativeUrl, watchedDirectoryUrl).href,
event: "added",
});
},
updated: ({ relativeUrl }) => {
callback({
url: new URL(relativeUrl, watchedDirectoryUrl).href,
event: "modified",
});
},
removed: ({ relativeUrl }) => {
callback({
url: new URL(relativeUrl, watchedDirectoryUrl).href,
event: "removed",
});
},
},
);
stopWatchingSourceFiles.watchPatterns = watchPatterns;
return stopWatchingSourceFiles;
};
npm_workspaces: {
const packageDirectoryUrl = lookupPackageDirectory(sourceDirectoryUrl);
let packageContent;
try {
packageContent = JSON.parse(
readFileSync(new URL("package.json", packageDirectoryUrl), "utf8"),
);
} catch {
break npm_workspaces;
}
const { workspaces } = packageContent;
if (!workspaces || !Array.isArray(workspaces) || workspaces.length === 0) {
break npm_workspaces;
}
watchedDirectoryUrl = packageDirectoryUrl;
for (const workspace of workspaces) {
if (workspace.endsWith("*")) {
const workspaceDirectoryUrl = new URL(
workspace.slice(0, -1),
packageDirectoryUrl,
);
addDirectoryToWatch(workspaceDirectoryUrl);
} else {
const workspaceRelativeUrl = new URL(workspace, packageDirectoryUrl);
addDirectoryToWatch(workspaceRelativeUrl);
}
}
// we are updating the root directory
// we must make the patterns relative to source directory relative to the new root directory
addDirectoryToWatch(sourceDirectoryUrl);
return watch();
}
watchedDirectoryUrl = sourceDirectoryUrl;
addDirectoryToWatch(sourceDirectoryUrl);
return watch();
};