@build-script/heft-esbuild-plugin
Version:
lowlevel esbuild plugin for [heft]
86 lines (69 loc) • 2.51 kB
text/typescript
import type { IHeftTaskSession } from '@rushstack/heft';
import type { Metafile } from 'esbuild';
import { mkdir, rm, writeFile } from 'node:fs/promises';
import { dirname, resolve } from 'node:path';
import type { FilterdBuildOptions } from './config.js';
import type { IOutputModifier } from './type.js';
import { OutputFile } from './write.helper.js';
export interface IProjectEmitterProps {
readonly metafile: Metafile;
readonly outputFiles: import('esbuild').OutputFile[];
readonly options: FilterdBuildOptions;
readonly session: IHeftTaskSession;
}
export type IProjectEmitter = (props: IProjectEmitterProps) => Promise<IInternalReturn> | IInternalReturn;
interface IInternalCache {
writeFile: Map<string, string>;
custom: any;
}
export function createEmitter(onEmit?: IOutputModifier): IProjectEmitter {
const cache: IInternalCache = {
custom: undefined,
writeFile: new Map(),
};
return async ({ metafile, outputFiles, options, session }) => {
const files: OutputFile[] = [];
let writtenFiles = 0;
Object.assign(metafile, { root: options.outdir });
const metaOut = resolve(options.outdir, 'metafile.json');
files.push(new OutputFile(metaOut, JSON.stringify(metafile, null, 4)));
for (const file of outputFiles) {
files.push(new OutputFile(file.path, file.contents, file.hash));
}
if (onEmit) {
cache.custom = await onEmit(files, options, cache.custom);
}
const lastCache = cache.writeFile;
cache.writeFile = new Map();
for (const item of files) {
if (!item.path || !item.contents) {
throw new Error(`invalid file: ${JSON.stringify(item)}`);
}
const content = item.contents || Buffer.from(item.text, 'utf-8');
cache.writeFile.set(item.path, item.hash);
if (lastCache.get(item.path) === cache.writeFile.get(item.path)) {
session.logger.terminal.writeDebugLine('write file: ', item.path, ' - unchange');
continue;
}
try {
await mkdir(dirname(item.path), { recursive: true });
await writeFile(item.path, content);
writtenFiles++;
session.logger.terminal.writeLine('write file: ', item.path, ' - ok');
} catch (e) {
session.logger.terminal.writeWarningLine('write file: ', item.path, ' - failed');
throw e;
}
}
for (const file of lastCache.keys()) {
if (!cache.writeFile.has(file)) {
session.logger.terminal.writeLine('write file: ', file, ' - deleted');
await rm(file);
}
}
return { writtenFiles };
};
}
interface IInternalReturn {
readonly writtenFiles: number;
}