0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-02-24 22:46:02 -05:00

feat: file watching for db/config.ts dependencies

This commit is contained in:
bholmesdev 2024-02-29 13:02:52 -05:00
parent 783c22d891
commit 4f8e2754fa
7 changed files with 61 additions and 34 deletions

View file

@ -13,3 +13,5 @@ export const DB_TYPES_FILE = 'db-types.d.ts';
export const VIRTUAL_MODULE_ID = 'astro:db';
export const DB_PATH = '.astro/content.db';
export const CONFIG_FILE_NAMES = ['config.ts', 'config.js', 'config.mts', 'config.mjs'];

View file

@ -4,10 +4,10 @@ import { vitePluginInjectEnvTs } from './vite-plugin-inject-env-ts.js';
import { typegen } from './typegen.js';
import { existsSync } from 'fs';
import { mkdir, rm, writeFile } from 'fs/promises';
import { DB_PATH } from '../consts.js';
import { CONFIG_FILE_NAMES, DB_PATH } from '../consts.js';
import { createLocalDatabaseClient } from '../../runtime/db-client.js';
import { dbConfigSchema, type DBTables } from '../types.js';
import { type VitePlugin } from '../utils.js';
import { getDbDirUrl, type VitePlugin } from '../utils.js';
import { UNSAFE_DISABLE_STUDIO_WARNING } from '../errors.js';
import { errorMap } from './error-map.js';
import { dirname } from 'path';
@ -20,6 +20,8 @@ import { loadConfigFile } from '../load-file.js';
function astroDBIntegration(): AstroIntegration {
let connectToStudio = false;
let configFileDependencies: string[] = [];
let root: URL;
let appToken: ManagedAppToken | undefined;
let schemas = {
tables(): DBTables {
@ -32,6 +34,7 @@ function astroDBIntegration(): AstroIntegration {
hooks: {
'astro:config:setup': async ({ updateConfig, config, command: _command, logger }) => {
command = _command;
root = config.root;
if (_command === 'preview') return;
let dbPlugin: VitePlugin | undefined = undefined;
@ -72,8 +75,10 @@ function astroDBIntegration(): AstroIntegration {
'astro:config:done': async ({ config, logger }) => {
// TODO: refine where we load tables
// @matthewp: may want to load tables by path at runtime
const configFile = await loadConfigFile(config.root);
const { tables = {} } = dbConfigSchema.parse(configFile?.default ?? {}, { errorMap });
const { mod, dependencies } = await loadConfigFile(config.root);
configFileDependencies = dependencies;
const { tables = {} } = dbConfigSchema.parse(mod?.default ?? {}, { errorMap });
// Redefine getTables so our integration can grab them
schemas.tables = () => tables;
@ -102,6 +107,18 @@ function astroDBIntegration(): AstroIntegration {
);
}, 100);
},
'astro:server:setup': async ({ server }) => {
const filesToWatch = [
...CONFIG_FILE_NAMES.map((c) => new URL(c, getDbDirUrl(root))),
...configFileDependencies.map((c) => new URL(c, root)),
];
server.watcher.on('all', (event, relativeEntry) => {
const entry = new URL(relativeEntry, root);
if (filesToWatch.some((f) => entry.href === f.href)) {
server.restart();
}
});
},
'astro:build:start': async ({ logger }) => {
logger.info('database: ' + (connectToStudio ? yellow('remote') : blue('local database.')));
},

View file

@ -42,15 +42,20 @@ export async function executeFile(params: ExecuteFileParams): Promise<void> {
await importBundledFile({ code, root: params.root });
}
export async function loadConfigFile(root: URL): Promise<{ default?: unknown } | undefined> {
export async function loadConfigFile(
root: URL
): Promise<{ mod: { default?: unknown } | undefined; dependencies: string[] }> {
// TODO: support any file extension
const fileUrl = new URL('config.ts', getDbDirUrl(root));
const { code } = await bundleFile({
const { code, dependencies } = await bundleFile({
virtualModContents: getConfigVirtualModContents(),
root,
fileUrl,
});
return await importBundledFile({ code, root });
return {
mod: await importBundledFile({ code, root }),
dependencies,
};
}
/**
@ -67,7 +72,7 @@ async function bundleFile({
fileUrl: URL;
root: URL;
virtualModContents: string;
}): Promise<{ code: string }> {
}) {
const result = await esbuild({
absWorkingDir: process.cwd(),
entryPoints: [fileURLToPath(fileUrl)],
@ -109,6 +114,7 @@ async function bundleFile({
return {
code: file.text,
dependencies: Object.keys(result.metafile.inputs),
};
}

View file

@ -1,31 +1,7 @@
import db, { defineTable, column, sql, NOW } from '@astrojs/db';
import db from '@astrojs/db';
import { defineConfig } from 'astro/config';
const Author = defineTable({
columns: {
name: column.text(),
},
});
// TODO: add back integration test
const Themes = defineTable({
columns: {
name: column.text(),
added: column.date({
default: sql`CURRENT_TIMESTAMP`,
}),
updated: column.date({
default: NOW,
}),
isDark: column.boolean({ default: sql`TRUE` }),
owner: column.text({ optional: true, default: sql`NULL` }),
},
});
// https://astro.build/config
export default defineConfig({
integrations: [db()],
db: {
tables: { Author, Themes },
},
});

View file

@ -0,0 +1,12 @@
import { defineDB, defineTable, column } from 'astro:db';
import { Themes } from './theme';
const Author = defineTable({
columns: {
name: column.text(),
},
});
export default defineDB({
tables: { Author, Themes },
});

View file

@ -1,4 +1,3 @@
/// <reference path="../.astro/db-types.d.ts" />
import { db, Author, Themes } from 'astro:db';
await db.batch([

View file

@ -0,0 +1,15 @@
import { defineTable, column, NOW, sql } from 'astro:db';
export const Themes = defineTable({
columns: {
name: column.text(),
added: column.date({
default: sql`CURRENT_TIMESTAMP`,
}),
updated: column.date({
default: NOW,
}),
isDark: column.boolean({ default: sql`TRUE` }),
owner: column.text({ optional: true, default: sql`NULL` }),
},
});