diff --git a/.changeset/clever-moles-listen.md b/.changeset/clever-moles-listen.md new file mode 100644 index 000000000000..96eede5a797d --- /dev/null +++ b/.changeset/clever-moles-listen.md @@ -0,0 +1,5 @@ +--- +"@astrojs/db": patch +--- + +Seed database on dev server startup, and log whenever the seed file is reloaded. diff --git a/packages/db/src/core/integration/index.ts b/packages/db/src/core/integration/index.ts index df03df9df44a..c24eba560ea4 100644 --- a/packages/db/src/core/integration/index.ts +++ b/packages/db/src/core/integration/index.ts @@ -13,8 +13,9 @@ import { type ManagedAppToken, getManagedAppTokenOrExit } from '../tokens.js'; import { type VitePlugin, getDbDirectoryUrl } from '../utils.js'; import { fileURLIntegration } from './file-url.js'; import { typegenInternal } from './typegen.js'; -import { type LateSeedFiles, type LateTables, vitePluginDb } from './vite-plugin-db.js'; +import { type LateSeedFiles, type LateTables, vitePluginDb, resolved } from './vite-plugin-db.js'; import { vitePluginInjectEnvTs } from './vite-plugin-inject-env-ts.js'; +import { SEED_DEV_FILE_NAME } from '../../runtime/queries.js'; function astroDBIntegration(): AstroIntegration { let connectToStudio = false; @@ -94,15 +95,7 @@ function astroDBIntegration(): AstroIntegration { await typegenInternal({ tables: tables.get() ?? {}, root: config.root }); }, - 'astro:server:start': async ({ logger }) => { - // Wait for the server startup to log, so that this can come afterwards. - setTimeout(() => { - logger.info( - connectToStudio ? 'Connected to remote database.' : 'New local database created.' - ); - }, 100); - }, - 'astro:server:setup': async ({ server }) => { + 'astro:server:setup': async ({ server, logger }) => { const filesToWatch = [ ...CONFIG_FILE_NAMES.map((c) => new URL(c, getDbDirectoryUrl(root))), ...configFileDependencies.map((c) => new URL(c, root)), @@ -113,6 +106,51 @@ function astroDBIntegration(): AstroIntegration { server.restart(); } }); + // Wait for dev server log before showing "connected". + setTimeout(() => { + logger.info( + connectToStudio ? 'Connected to remote database.' : 'New local database created.' + ); + if (connectToStudio) return; + + const localSeedPaths = SEED_DEV_FILE_NAME.map( + (name) => new URL(name, getDbDirectoryUrl(root)) + ); + let seedInFlight = false; + // Load seed file on dev server startup. + if (seedFiles.get().length || localSeedPaths.find((path) => existsSync(path))) { + loadSeedModule(); + } + const eagerReloadIntegrationSeedPaths = seedFiles + .get() + // Map integration seed paths to URLs, if possible. + // Module paths like `@example/seed` will be ignored + // from eager reloading. + .map((s) => (typeof s === 'string' && s.startsWith('.') ? new URL(s, root) : s)) + .filter((s): s is URL => s instanceof URL); + const eagerReloadSeedPaths = [...eagerReloadIntegrationSeedPaths, ...localSeedPaths]; + server.watcher.on('all', (event, relativeEntry) => { + if (event === 'unlink' || event === 'unlinkDir') return; + // When a seed file changes, load manually + // to track when seeding finishes and log a message. + const entry = new URL(relativeEntry, root); + if (eagerReloadSeedPaths.find((path) => entry.href === path.href)) { + loadSeedModule(); + } + }); + + function loadSeedModule() { + if (seedInFlight) return; + + seedInFlight = true; + const mod = server.moduleGraph.getModuleById(resolved.seedVirtual); + if (mod) server.moduleGraph.invalidateModule(mod); + server.ssrLoadModule(resolved.seedVirtual).then(() => { + seedInFlight = false; + logger.info('Seeded database.'); + }); + } + }, 100); }, 'astro:build:start': async ({ logger }) => { if ( diff --git a/packages/db/src/core/integration/vite-plugin-db.ts b/packages/db/src/core/integration/vite-plugin-db.ts index 148be3137ac0..511c1454b669 100644 --- a/packages/db/src/core/integration/vite-plugin-db.ts +++ b/packages/db/src/core/integration/vite-plugin-db.ts @@ -7,7 +7,7 @@ import { type VitePlugin, getDbDirectoryUrl, getRemoteDatabaseUrl } from '../uti const WITH_SEED_VIRTUAL_MODULE_ID = 'astro:db:seed'; -const resolved = { +export const resolved = { virtual: '\0' + VIRTUAL_MODULE_ID, seedVirtual: '\0' + WITH_SEED_VIRTUAL_MODULE_ID, };