134 lines
2.9 KiB
TypeScript
134 lines
2.9 KiB
TypeScript
import { deleteSync } from "del";
|
|
import type { BuildOptions, BuildResult, Plugin } from "esbuild";
|
|
import path from "node:path";
|
|
|
|
export type PluginOptions = {
|
|
dry?: boolean;
|
|
initialCleanPatterns?: string[];
|
|
verbose?: boolean;
|
|
};
|
|
|
|
export class CleanPlugin {
|
|
private previousAssets: string[] = [];
|
|
|
|
public constructor(
|
|
private pluginOptions: PluginOptions,
|
|
private buildOptions: BuildOptions
|
|
) {
|
|
this.pluginOptions = {
|
|
dry: false,
|
|
initialCleanPatterns: ["**/*"],
|
|
verbose: false,
|
|
...pluginOptions,
|
|
};
|
|
}
|
|
|
|
public handleBuild(result: BuildResult): void {
|
|
const { outputs } = result.metafile ?? {};
|
|
|
|
if (!outputs) {
|
|
return;
|
|
}
|
|
|
|
const outputFiles = Object.keys(outputs);
|
|
const removePatterns = this.previousAssets
|
|
.filter((asset) => {
|
|
return !outputFiles.includes(asset);
|
|
})
|
|
.map((asset) => {
|
|
return path.basename(asset);
|
|
});
|
|
|
|
this.previousAssets = outputFiles;
|
|
|
|
try {
|
|
this.removeFiles(removePatterns);
|
|
} catch (e) {
|
|
const message = e instanceof Error ? e.message : "unknown error";
|
|
|
|
console.error(`esbuild-clean-plugin: ${message}`);
|
|
}
|
|
}
|
|
|
|
public initialClean(): void {
|
|
const { initialCleanPatterns } = this.pluginOptions;
|
|
|
|
if (!initialCleanPatterns) {
|
|
return;
|
|
}
|
|
|
|
this.removeFiles(initialCleanPatterns);
|
|
}
|
|
|
|
protected removeFiles(patterns: string[]): void {
|
|
const { outdir } = this.buildOptions;
|
|
|
|
if (!outdir) {
|
|
return;
|
|
}
|
|
|
|
const deletedFiles = deleteSync(patterns, {
|
|
cwd: path.resolve(process.cwd(), outdir),
|
|
dryRun: Boolean(this.pluginOptions.dry),
|
|
});
|
|
|
|
this.printStats(deletedFiles);
|
|
}
|
|
|
|
protected printStats(fileNames: string[]): void {
|
|
const { dry, verbose } = this.pluginOptions;
|
|
const { outdir } = this.buildOptions;
|
|
|
|
if (!verbose || !outdir) {
|
|
return;
|
|
}
|
|
|
|
const message = dry ? "dry" : "removed";
|
|
|
|
fileNames.forEach((fileName) => {
|
|
fileName = path.resolve(outdir, fileName);
|
|
|
|
console.log(`esbuild-clean-plugin: ${message} ${fileName}`);
|
|
});
|
|
}
|
|
|
|
public validateOptions(): boolean {
|
|
const { metafile, outdir } = this.buildOptions;
|
|
|
|
if (!metafile) {
|
|
console.warn(
|
|
'esbuild-clean-plugin: The esbuild "metafile" option was not set, please set it to true. Stopping.'
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
if (!outdir) {
|
|
console.warn(
|
|
'esbuild-clean-plugin: The esbuild "outdir" option was not set, please supply it. Stopping.'
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export const cleanPlugin = (pluginOptions: PluginOptions = {}): Plugin => {
|
|
return {
|
|
name: "clean",
|
|
setup(build): void {
|
|
const plugin = new CleanPlugin(pluginOptions, build.initialOptions);
|
|
|
|
if (plugin.validateOptions()) {
|
|
plugin.initialClean();
|
|
|
|
build.onEnd((result) => {
|
|
plugin.handleBuild(result);
|
|
});
|
|
}
|
|
},
|
|
};
|
|
};
|