Improve esbuild copyFilesPlugin

This commit is contained in:
hensm
2022-05-16 06:32:06 +01:00
parent 2629be4a01
commit 088c550987

View File

@@ -8,16 +8,21 @@ const fs = require("fs");
const esbuild = require("esbuild"); const esbuild = require("esbuild");
/** /**
* Escape meta characters in a regular expression. * Walks file tree from a given root path.
* * @param {string} rootPath
* @param {string} patternSource
* @returns {string} Escaped expression source
*/ */
function escapeRegExp(patternSource) { function* walk(rootPath) {
let metaChars = ".+*?()|[]{}^$\\"; const pathsToWalk = [rootPath];
return [...patternSource] while (pathsToWalk.length > 0) {
.map(c => (metaChars.includes(c) ? `\\${c}` : c)) const currentPath = pathsToWalk.pop();
.join(""); if (fs.statSync(currentPath).isFile()) {
yield currentPath;
} else {
for (const child of fs.readdirSync(currentPath)) {
pathsToWalk.push(path.join(currentPath, child));
}
}
}
} }
/** /**
@@ -33,64 +38,45 @@ function escapeRegExp(patternSource) {
* @type {(opts: CopyFilesPluginOpts) => esbuild.Plugin} * @type {(opts: CopyFilesPluginOpts) => esbuild.Plugin}
*/ */
exports.copyFilesPlugin = opts => { exports.copyFilesPlugin = opts => {
// Get matching file paths if (!fs.existsSync(opts.src)) {
const matchingFiles = (function getMatchingPaths(relPath = "") { throw new Error("copyFilesPlugin: src path not found!");
const fullPath = path.join(opts.src, relPath); }
// Must exist const matchingPaths = [];
if (!fs.existsSync(fullPath)) return; for (const path of walk(opts.src)) {
// Must not match exclude pattern if (!opts.excludePattern?.test(path)) {
if (opts.excludePattern?.test(fullPath)) return; matchingPaths.push(path);
if (fs.statSync(fullPath).isFile()) {
return [relPath];
} }
}
/** @type string[] */
let files = [];
for (const entry of fs.readdirSync(fullPath)) {
const matchingFiles = getMatchingPaths(path.join(relPath, entry));
if (matchingFiles) {
files = files.concat(matchingFiles);
}
}
return files;
})();
return { return {
name: "copy-files", name: "copy-files",
setup(build) { setup(build) {
/** First run for the set of import paths in each build. */ /** First run for the set of import paths in each build. */
let isFirstRun = true; let isFirstRun = true;
build.onResolve({ filter: /.*/ }, () => {
build.onResolve( /**
{ * Attach watch files to first resolve result.
filter: new RegExp(`^${escapeRegExp(opts.src + path.sep)}`) * Presumably there is a much better way of doing
}, * this?
() => { */
/** if (isFirstRun) {
* Attach watch files to first resolve result. isFirstRun = false;
* Presumably there is a much better way of doing return {
* this? watchFiles: matchingPaths
*/ };
if (isFirstRun) {
isFirstRun = false;
return {
watchFiles: matchingFiles.map(file =>
path.join(opts.src, file)
)
};
}
} }
); });
build.onEnd(() => { build.onEnd(() => {
isFirstRun = true; isFirstRun = true;
// Copy any watched files that changed // Copy any watched files that changed
for (const file of matchingFiles) { for (const srcPath of matchingPaths) {
const srcPath = path.join(opts.src, file); const destPath = path.resolve(
const destPath = path.join(opts.dest, file); opts.dest,
path.relative(opts.src, srcPath)
);
// Ignore if source file is missing // Ignore if source file is missing
if (!fs.existsSync(srcPath)) { if (!fs.existsSync(srcPath)) {