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:
parent
93675795e1
commit
aa1b66f5cf
3 changed files with 120 additions and 4 deletions
|
@ -3,15 +3,20 @@ import { vitePluginDb } from './vite-plugin-db.js';
|
||||||
import { vitePluginInjectEnvTs } from './vite-plugin-inject-env-ts.js';
|
import { vitePluginInjectEnvTs } from './vite-plugin-inject-env-ts.js';
|
||||||
import { typegen } from './typegen.js';
|
import { typegen } from './typegen.js';
|
||||||
import { collectionsSchema } from './types.js';
|
import { collectionsSchema } from './types.js';
|
||||||
|
import { seed } from './seed.js';
|
||||||
|
|
||||||
export function integration(): AstroIntegration {
|
export function integration(): AstroIntegration {
|
||||||
return {
|
return {
|
||||||
name: 'astro:db',
|
name: 'astro:db',
|
||||||
hooks: {
|
hooks: {
|
||||||
async 'astro:config:setup'({ updateConfig, config }) {
|
async 'astro:config:setup'({ updateConfig, config, command }) {
|
||||||
// TODO: refine where we load collections
|
// TODO: refine where we load collections
|
||||||
// @matthewp: may want to load collections by path at runtime
|
// @matthewp: may want to load collections by path at runtime
|
||||||
const collections = collectionsSchema.parse(config.db?.collections ?? {});
|
const collections = collectionsSchema.parse(config.db?.collections ?? {});
|
||||||
|
const isDev = command === 'dev';
|
||||||
|
if (!isDev) {
|
||||||
|
await seed({ collections, root: config.root });
|
||||||
|
}
|
||||||
updateConfig({
|
updateConfig({
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [
|
plugins: [
|
||||||
|
@ -20,6 +25,7 @@ export function integration(): AstroIntegration {
|
||||||
vitePluginDb({
|
vitePluginDb({
|
||||||
collections,
|
collections,
|
||||||
root: config.root,
|
root: config.root,
|
||||||
|
isDev,
|
||||||
}),
|
}),
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
vitePluginInjectEnvTs(config),
|
vitePluginInjectEnvTs(config),
|
||||||
|
|
106
packages/db/src/seed.ts
Normal file
106
packages/db/src/seed.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,9 +15,11 @@ const resolvedVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
|
||||||
export function vitePluginDb({
|
export function vitePluginDb({
|
||||||
collections,
|
collections,
|
||||||
root,
|
root,
|
||||||
|
isDev: isDev,
|
||||||
}: {
|
}: {
|
||||||
collections: DBCollections;
|
collections: DBCollections;
|
||||||
root: URL;
|
root: URL;
|
||||||
|
isDev: boolean;
|
||||||
}): VitePlugin {
|
}): VitePlugin {
|
||||||
return {
|
return {
|
||||||
name: 'astro:db',
|
name: 'astro:db',
|
||||||
|
@ -29,7 +31,7 @@ export function vitePluginDb({
|
||||||
},
|
},
|
||||||
load(id) {
|
load(id) {
|
||||||
if (id !== resolvedVirtualModuleId) return;
|
if (id !== resolvedVirtualModuleId) return;
|
||||||
return getLocalVirtualModuleContents({ collections, root });
|
return getVirtualModContents({ collections, root, isDev });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -38,12 +40,14 @@ const seedErrorMessage = `${red(
|
||||||
'⚠️ Failed to seed data.'
|
'⚠️ Failed to seed data.'
|
||||||
)} Is the seed file out-of-date with recent schema changes?`;
|
)} Is the seed file out-of-date with recent schema changes?`;
|
||||||
|
|
||||||
export function getLocalVirtualModuleContents({
|
export function getVirtualModContents({
|
||||||
collections,
|
collections,
|
||||||
root,
|
root,
|
||||||
|
isDev,
|
||||||
}: {
|
}: {
|
||||||
collections: DBCollections;
|
collections: DBCollections;
|
||||||
root: URL;
|
root: URL;
|
||||||
|
isDev: boolean;
|
||||||
}) {
|
}) {
|
||||||
const seedFile = SUPPORTED_SEED_FILES.map((f) => fileURLToPath(new URL(f, root))).find((f) =>
|
const seedFile = SUPPORTED_SEED_FILES.map((f) => fileURLToPath(new URL(f, root))).find((f) =>
|
||||||
existsSync(f)
|
existsSync(f)
|
||||||
|
@ -57,7 +61,7 @@ export * from ${DRIZZLE_MOD_IMPORT};
|
||||||
${getStringifiedCollectionExports(collections)}
|
${getStringifiedCollectionExports(collections)}
|
||||||
|
|
||||||
${
|
${
|
||||||
seedFile
|
seedFile && isDev
|
||||||
? `try {
|
? `try {
|
||||||
await import(${JSON.stringify(seedFile)});
|
await import(${JSON.stringify(seedFile)});
|
||||||
} catch {
|
} catch {
|
||||||
|
|
Loading…
Add table
Reference in a new issue