123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- import esbuild from 'esbuild';
- import { red } from 'kleur/colors';
- import fs from 'node:fs';
- import path from 'node:path';
- import { fileURLToPath, pathToFileURL } from 'node:url';
- import glob from 'tiny-glob';
- function escapeTemplateLiterals(str) {
- return str.replace(/\`/g, '\\`').replace(/\$\{/g, '\\${');
- }
- export default async function prebuild(...args) {
- let buildToString = args.indexOf('--to-string');
- if (buildToString !== -1) {
- args.splice(buildToString, 1);
- buildToString = true;
- }
- let minify = true;
- let minifyIdx = args.indexOf('--no-minify');
- if (minifyIdx !== -1) {
- minify = false;
- args.splice(minifyIdx, 1);
- }
- let patterns = args;
- let entryPoints = [].concat(
- ...(await Promise.all(
- patterns.map((pattern) => glob(pattern, { filesOnly: true, absolute: true }))
- ))
- );
- function getPrebuildURL(entryfilepath, dev = false) {
- const entryURL = pathToFileURL(entryfilepath);
- const basename = path.basename(entryfilepath);
- const ext = path.extname(entryfilepath);
- const name = basename.slice(0, basename.indexOf(ext));
- const outname = dev ? `${name}.prebuilt-dev${ext}` : `${name}.prebuilt${ext}`;
- const outURL = new URL('./' + outname, entryURL);
- return outURL;
- }
- async function prebuildFile(filepath) {
- let tscode = await fs.promises.readFile(filepath, 'utf-8');
- // If we're bundling a client directive, modify the code to match `packages/astro/src/core/client-directive/build.ts`.
- // If updating this code, make sure to also update that file.
- if (filepath.includes(`runtime${path.sep}client`)) {
- // `export default xxxDirective` is a convention used in the current client directives that we use
- // to make sure we bundle this right. We'll error below if this convention isn't followed.
- const newTscode = tscode.replace(
- /export default (.*?)Directive/,
- (_, name) =>
- `(self.Astro || (self.Astro = {})).${name} = ${name}Directive;window.dispatchEvent(new Event('astro:${name}'))`
- );
- if (newTscode === tscode) {
- console.error(
- red(
- `${filepath} doesn't follow the \`export default xxxDirective\` convention. The prebuilt output may be wrong. ` +
- `For more information, check out ${fileURLToPath(import.meta.url)}`
- )
- );
- }
- tscode = newTscode;
- }
- const esbuildOptions = {
- stdin: {
- contents: tscode,
- resolveDir: path.dirname(filepath),
- loader: 'ts',
- sourcefile: filepath,
- },
- format: 'iife',
- target: ['es2018'],
- minify,
- bundle: true,
- write: false,
- };
- const results = await Promise.all(
- [
- {
- build: await esbuild.build(esbuildOptions),
- dev: false,
- },
- filepath.includes('astro-island')
- ? {
- build: await esbuild.build({
- ...esbuildOptions,
- define: { 'process.env.NODE_ENV': '"development"' },
- }),
- dev: true,
- }
- : undefined,
- ].filter((entry) => entry)
- );
- for (const result of results) {
- const code = result.build.outputFiles[0].text.trim();
- const rootURL = new URL('../../', import.meta.url);
- const rel = path.relative(fileURLToPath(rootURL), filepath);
- const mod = `/**
- * This file is prebuilt from ${rel}
- * Do not edit this directly, but instead edit that file and rerun the prebuild
- * to generate this file.
- */
- export default \`${escapeTemplateLiterals(code)}\`;`;
- const url = getPrebuildURL(filepath, result.dev);
- await fs.promises.writeFile(url, mod, 'utf-8');
- }
- }
- await Promise.all(entryPoints.map(prebuildFile));
- }
|