0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-01-20 22:12:38 -05:00

fix: load seed file separately for build

This commit is contained in:
bholmesdev 2024-01-09 16:01:48 -05:00 committed by Nate Moore
parent 93675795e1
commit aa1b66f5cf
3 changed files with 120 additions and 4 deletions

View file

@ -3,15 +3,20 @@ import { vitePluginDb } from './vite-plugin-db.js';
import { vitePluginInjectEnvTs } from './vite-plugin-inject-env-ts.js';
import { typegen } from './typegen.js';
import { collectionsSchema } from './types.js';
import { seed } from './seed.js';
export function integration(): AstroIntegration {
return {
name: 'astro:db',
hooks: {
async 'astro:config:setup'({ updateConfig, config }) {
async 'astro:config:setup'({ updateConfig, config, command }) {
// TODO: refine where we load collections
// @matthewp: may want to load collections by path at runtime
const collections = collectionsSchema.parse(config.db?.collections ?? {});
const isDev = command === 'dev';
if (!isDev) {
await seed({ collections, root: config.root });
}
updateConfig({
vite: {
plugins: [
@ -20,6 +25,7 @@ export function integration(): AstroIntegration {
vitePluginDb({
collections,
root: config.root,
isDev,
}),
// @ts-ignore
vitePluginInjectEnvTs(config),

106
packages/db/src/seed.ts Normal file
View file

@ -0,0 +1,106 @@
import { existsSync, unlinkSync, writeFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { type BuildOptions, build as esbuild } from 'esbuild';
import { SUPPORTED_SEED_FILES, VIRTUAL_MODULE_ID } from './consts.js';
import { getVirtualModContents } from './vite-plugin-db.js';
import type { DBCollections } from './types.js';
export async function seed({ collections, root }: { collections: DBCollections; root: URL }) {
let seedFileUrl: URL | undefined;
for (const filename of SUPPORTED_SEED_FILES) {
const fileUrl = new URL(filename, root);
if (!existsSync(fileUrl)) continue;
seedFileUrl = fileUrl;
break;
}
if (!seedFileUrl) return;
const { code } = await bundleFile(seedFileUrl, [
{
name: 'resolve-astro-db',
setup(build) {
build.onResolve({ filter: /^astro:db$/ }, ({ path }) => {
return { path, namespace: VIRTUAL_MODULE_ID };
});
build.onLoad({ namespace: VIRTUAL_MODULE_ID, filter: /.*/ }, () => {
return {
contents: getVirtualModContents({
collections,
root,
isDev: false,
}),
// Needed to resolve `@packages/studio` internals
resolveDir: process.cwd(),
};
});
},
},
]);
// seed file supports top-level await. Runs when config is loaded!
await loadBundledFile({ code, root });
console.info('Seeding complete 🌱');
}
/**
* Bundle config file to support `.ts` files. Simplified fork from Vite's `bundleConfigFile`
* function:
*
* @see https://github.com/vitejs/vite/blob/main/packages/vite/src/node/config.ts#L961
*/
async function bundleFile(
fileUrl: URL,
esbuildPlugins?: BuildOptions['plugins']
): Promise<{ code: string; dependencies: string[] }> {
const result = await esbuild({
absWorkingDir: process.cwd(),
entryPoints: [fileURLToPath(fileUrl)],
outfile: 'out.js',
packages: 'external',
write: false,
target: ['node16'],
platform: 'node',
bundle: true,
format: 'esm',
sourcemap: 'inline',
metafile: true,
plugins: esbuildPlugins,
});
const file = result.outputFiles[0];
if (!file) {
throw new Error(`Unexpected: no output file`);
}
return {
code: file.text,
dependencies: Object.keys(result.metafile.inputs),
};
}
/**
* Forked from Vite config loader, replacing CJS-based path concat with ESM only
*
* @see https://github.com/vitejs/vite/blob/main/packages/vite/src/node/config.ts#L1074
*/
async function loadBundledFile({
code,
root,
}: {
root: URL;
code: string;
}): Promise<{ default?: unknown }> {
// Write it to disk, load it with native Node ESM, then delete the file.
const tmpFileUrl = new URL(`studio.seed.timestamp-${Date.now()}.mjs`, root);
writeFileSync(tmpFileUrl, code);
try {
return await import(tmpFileUrl.pathname);
} finally {
try {
unlinkSync(tmpFileUrl);
} catch {
// already removed if this function is called twice simultaneously
}
}
}

View file

@ -15,9 +15,11 @@ const resolvedVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
export function vitePluginDb({
collections,
root,
isDev: isDev,
}: {
collections: DBCollections;
root: URL;
isDev: boolean;
}): VitePlugin {
return {
name: 'astro:db',
@ -29,7 +31,7 @@ export function vitePluginDb({
},
load(id) {
if (id !== resolvedVirtualModuleId) return;
return getLocalVirtualModuleContents({ collections, root });
return getVirtualModContents({ collections, root, isDev });
},
};
}
@ -38,12 +40,14 @@ const seedErrorMessage = `${red(
'⚠️ Failed to seed data.'
)} Is the seed file out-of-date with recent schema changes?`;
export function getLocalVirtualModuleContents({
export function getVirtualModContents({
collections,
root,
isDev,
}: {
collections: DBCollections;
root: URL;
isDev: boolean;
}) {
const seedFile = SUPPORTED_SEED_FILES.map((f) => fileURLToPath(new URL(f, root))).find((f) =>
existsSync(f)
@ -57,7 +61,7 @@ export * from ${DRIZZLE_MOD_IMPORT};
${getStringifiedCollectionExports(collections)}
${
seedFile
seedFile && isDev
? `try {
await import(${JSON.stringify(seedFile)});
} catch {