Files
server/scripts/generate-vendor-shims.ts
2026-02-10 18:46:11 -05:00

96 lines
2.8 KiB
TypeScript

import { mkdir, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
const require = createRequire(import.meta.url);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const OUTPUT_DIR = path.resolve(__dirname, '../public/vendor');
interface LibraryDefinition {
packageName: string;
globalName: string;
outputFile: string;
}
interface WriteShimOptions {
outputDir: string;
silent: boolean;
}
type ShimSource = Pick<LibraryDefinition, 'packageName' | 'globalName'>;
const libraries: LibraryDefinition[] = [
{ packageName: 'vue', globalName: 'Vue', outputFile: 'vue.mjs' },
{ packageName: 'vue-router', globalName: 'VueRouter', outputFile: 'vue-router.mjs' },
{ packageName: 'pinia', globalName: 'Pinia', outputFile: 'pinia.mjs' },
];
const formatLines = (globalName: string, exports: readonly string[]): string => {
const lines: string[] = [];
lines.push(`const ${globalName} = window.${globalName};`);
lines.push(`if (!${globalName}) {`);
lines.push(` throw new Error('${globalName} runtime is not available on window.');`);
lines.push('}');
lines.push(`export default ${globalName};`);
for (const name of exports) {
lines.push(`export const ${name} = ${globalName}.${name};`);
}
lines.push('');
return lines.join('\n');
};
const generateShim = ({ packageName, globalName }: ShimSource): string => {
const mod = require(packageName) as Record<string, unknown>;
const exportNames = Object.keys(mod)
.filter((key) => key !== 'default')
.sort();
return formatLines(globalName, exportNames);
};
const writeShim = async (
{ packageName, globalName, outputFile }: LibraryDefinition,
{ outputDir, silent }: WriteShimOptions,
): Promise<void> => {
const content = generateShim({ packageName, globalName });
await writeFile(path.join(outputDir, outputFile), content, 'utf8');
if (!silent) {
console.log(`Generated ${outputFile}`);
}
};
export interface GenerateVendorShimsOptions {
outputDir?: string;
silent?: boolean;
}
export type GenerateVendorShims = (options?: GenerateVendorShimsOptions) => Promise<void>;
export const generateVendorShims: GenerateVendorShims = async (options = {}) => {
const { outputDir = OUTPUT_DIR, silent = false } = options;
await mkdir(outputDir, { recursive: true });
await Promise.all(libraries.map((library) => writeShim(library, { outputDir, silent })));
if (!silent) {
console.log(`[generate-vendor-shims] Vendor shims updated in ${outputDir}`);
}
};
const isCliExecution = Boolean(process.argv[1] && path.resolve(process.argv[1]) === __filename);
if (isCliExecution) {
void generateVendorShims().catch((error) => {
console.error('[generate-vendor-shims] Failed to generate shims', error);
process.exitCode = 1;
});
}