From 17bfac37cbce566ba4d0ad476198499208039dce Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 4 Jul 2024 16:17:38 +0200 Subject: [PATCH 01/19] feat: work on astro sync cleanup --- packages/astro/src/cli/check/index.ts | 9 ++-- packages/astro/src/cli/sync/index.ts | 19 ++++++-- packages/astro/src/core/build/index.ts | 17 +++---- packages/astro/src/core/index.ts | 11 ++++- packages/astro/src/core/sync/index.ts | 64 +++++++++++--------------- 5 files changed, 66 insertions(+), 54 deletions(-) diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts index 721a0bf6911b..db1d376121c5 100644 --- a/packages/astro/src/cli/check/index.ts +++ b/packages/astro/src/cli/check/index.ts @@ -3,6 +3,7 @@ import type { Arguments } from 'yargs-parser'; import { ensureProcessNodeEnv } from '../../core/util.js'; import { createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js'; import { getPackage } from '../install-package.js'; +import { resolveConfig } from '../../core/config/config.js'; export async function check(flags: Arguments) { ensureProcessNodeEnv('production'); @@ -29,9 +30,11 @@ export async function check(flags: Arguments) { // For now, we run this once as usually `astro check --watch` is ran alongside `astro dev` which also calls `astro sync`. const { default: sync } = await import('../../core/sync/index.js'); const inlineConfig = flagsToAstroInlineConfig(flags); - const exitCode = await sync(inlineConfig); - if (exitCode !== 0) { - process.exit(exitCode); + const { astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); + try { + await sync({ astroConfig, logger }); + } catch (_) { + return process.exit(1); } const { check: checker, parseArgsAsCheckConfig } = checkPackage; diff --git a/packages/astro/src/cli/sync/index.ts b/packages/astro/src/cli/sync/index.ts index 8650bf904655..28324cf439a0 100644 --- a/packages/astro/src/cli/sync/index.ts +++ b/packages/astro/src/cli/sync/index.ts @@ -2,12 +2,18 @@ import type yargs from 'yargs-parser'; import { printHelp } from '../../core/messages.js'; import _sync from '../../core/sync/index.js'; import { flagsToAstroInlineConfig } from '../flags.js'; +import { resolveConfig } from '../../core/config/config.js'; +import { createNodeLogger } from '../../core/config/logging.js'; +import { telemetry } from '../../events/index.js'; +import { eventCliSession } from '../../events/session.js'; + +type ProcessExit = 0 | 1; interface SyncOptions { flags: yargs.Arguments; } -export async function sync({ flags }: SyncOptions) { +export async function sync({ flags }: SyncOptions): Promise { if (flags?.help || flags?.h) { printHelp({ commandName: 'astro sync', @@ -21,7 +27,14 @@ export async function sync({ flags }: SyncOptions) { } const inlineConfig = flagsToAstroInlineConfig(flags); + const logger = createNodeLogger(inlineConfig); + const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); + telemetry.record(eventCliSession('sync', userConfig)); - const exitCode = await _sync(inlineConfig); - return exitCode; + try { + await _sync({ astroConfig, logger }); + return 0; + } catch (_) { + return 1; + } } diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index d4c23b7c6dc4..08fe4bf227fc 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -17,7 +17,6 @@ import { runHookBuildDone, runHookBuildStart, runHookConfigDone, - runHookConfigSetup, } from '../../integrations/hooks.js'; import { resolveConfig } from '../config/config.js'; import { createNodeLogger } from '../config/logging.js'; @@ -119,10 +118,14 @@ class AstroBuilder { this.logger.debug('build', 'Initial setup...'); const { logger } = this; this.timer.init = performance.now(); - this.settings = await runHookConfigSetup({ + + const { default: sync } = await import('../sync/index.js'); + + this.settings = await sync({ settings: this.settings, - command: 'build', - logger: logger, + logger, + astroConfig: this.settings.config, + fs, }); if (isServerLikeOutput(this.settings.config)) { @@ -143,12 +146,6 @@ class AstroBuilder { ); await runHookConfigDone({ settings: this.settings, logger: logger }); - const { syncContentCollections } = await import('../sync/index.js'); - const syncRet = await syncContentCollections(this.settings, { logger: logger, fs }); - if (syncRet !== 0) { - return process.exit(syncRet); - } - return { viteConfig }; } diff --git a/packages/astro/src/core/index.ts b/packages/astro/src/core/index.ts index 31d868311455..8771b7334f5c 100644 --- a/packages/astro/src/core/index.ts +++ b/packages/astro/src/core/index.ts @@ -3,6 +3,10 @@ import type { AstroInlineConfig } from '../@types/astro.js'; import { default as _build } from './build/index.js'; import { default as _sync } from './sync/index.js'; +import { resolveConfig } from './config/config.js'; +import { createNodeLogger } from './config/logging.js'; +import { telemetry } from '../events/index.js'; +import { eventCliSession } from '../events/session.js'; export { default as dev } from './dev/index.js'; export { default as preview } from './preview/index.js'; @@ -23,4 +27,9 @@ export const build = (inlineConfig: AstroInlineConfig) => _build(inlineConfig); * @experimental The JavaScript API is experimental */ // Wrap `_sync` to prevent exposing the second internal options parameter -export const sync = (inlineConfig: AstroInlineConfig) => _sync(inlineConfig); +export const sync = async (inlineConfig: AstroInlineConfig) => { + const logger = createNodeLogger(inlineConfig); + const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); + telemetry.record(eventCliSession('sync', userConfig)); + return await _sync({ astroConfig, logger }); +}; diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 1e43884ac0a7..84f96fad49b6 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -1,20 +1,16 @@ +import { dim } from 'kleur/colors'; import fsMod from 'node:fs'; import { performance } from 'node:perf_hooks'; import { fileURLToPath } from 'node:url'; -import { dim } from 'kleur/colors'; import { type HMRPayload, createServer } from 'vite'; -import type { AstroConfig, AstroInlineConfig, AstroSettings } from '../../@types/astro.js'; +import type { AstroConfig, AstroSettings } from '../../@types/astro.js'; import { getPackage } from '../../cli/install-package.js'; import { createContentTypesGenerator } from '../../content/index.js'; import { globalContentConfigObserver } from '../../content/utils.js'; import { syncAstroEnv } from '../../env/sync.js'; -import { telemetry } from '../../events/index.js'; -import { eventCliSession } from '../../events/session.js'; import { runHookConfigSetup } from '../../integrations/hooks.js'; import { setUpEnvTs } from '../../vite-plugin-inject-env-ts/index.js'; import { getTimeStat } from '../build/util.js'; -import { resolveConfig } from '../config/config.js'; -import { createNodeLogger } from '../config/logging.js'; import { createSettings } from '../config/settings.js'; import { createVite } from '../create-vite.js'; import { collectErrorMetadata } from '../errors/dev/utils.js'; @@ -29,17 +25,14 @@ import type { Logger } from '../logger/core.js'; import { formatErrorMessage } from '../messages.js'; import { ensureProcessNodeEnv } from '../util.js'; -export type ProcessExit = 0 | 1; - export type SyncOptions = { /** * @internal only used for testing */ fs?: typeof fsMod; -}; - -export type SyncInternalOptions = SyncOptions & { logger: Logger; + astroConfig: AstroConfig; + settings?: AstroSettings; }; type DBPackage = { @@ -52,20 +45,20 @@ type DBPackage = { * * @experimental The JavaScript API is experimental */ -export default async function sync( - inlineConfig: AstroInlineConfig, - options?: SyncOptions -): Promise { +export default async function sync({ + astroConfig, + logger, + fs = fsMod, + settings, +}: SyncOptions): Promise { ensureProcessNodeEnv('production'); - const logger = createNodeLogger(inlineConfig); - const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); - telemetry.record(eventCliSession('sync', userConfig)); + const cwd = fileURLToPath(astroConfig.root); - const _settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root)); + settings ??= await createSettings(astroConfig, cwd); - const settings = await runHookConfigSetup({ - settings: _settings, - logger: logger, + settings = await runHookConfigSetup({ + settings, + logger, command: 'build', }); @@ -75,26 +68,28 @@ export default async function sync( logger, { optional: true, - cwd: inlineConfig.root, + cwd, }, [] ); try { await dbPackage?.typegen?.(astroConfig); - const exitCode = await syncContentCollections(settings, { ...options, logger }); - if (exitCode !== 0) return exitCode; - syncAstroEnv(settings, options?.fs); + await syncContentCollections(settings, { fs, logger }); + syncAstroEnv(settings, fs); + await setUpEnvTs({ settings, logger, fs }); logger.info(null, `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`); - return 0; + + return settings; } catch (err) { const error = createSafeError(err); logger.error( - 'content', + 'types', formatErrorMessage(collectErrorMetadata(error), logger.level() === 'debug') + '\n' ); - return 1; + // Will return exit code 1 in CLI + throw error; } } @@ -112,10 +107,10 @@ export default async function sync( * @param {LogOptions} options.logging Logging options * @return {Promise} */ -export async function syncContentCollections( +async function syncContentCollections( settings: AstroSettings, - { logger, fs }: SyncInternalOptions -): Promise { + { logger, fs }: Pick +): Promise { // Needed to load content config const tempViteServer = await createServer( await createVite( @@ -159,7 +154,6 @@ export async function syncContentCollections( case 'no-content-dir': default: logger.debug('types', 'No content directory found. Skipping type generation.'); - return 0; } } } catch (e) { @@ -179,8 +173,4 @@ export async function syncContentCollections( } finally { await tempViteServer.close(); } - - await setUpEnvTs({ settings, logger, fs: fs ?? fsMod }); - - return 0; } From 40e6d0de7030bd434a20641d6b091e44a976a0f3 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 4 Jul 2024 16:31:29 +0200 Subject: [PATCH 02/19] feat: call sync after astro:config:setup --- packages/astro/src/cli/check/index.ts | 4 +++- packages/astro/src/cli/sync/index.ts | 4 +++- packages/astro/src/core/build/index.ts | 10 +++++++--- packages/astro/src/core/dev/container.ts | 6 ++++++ packages/astro/src/core/index.ts | 10 +++++++++- packages/astro/src/core/preview/index.ts | 1 + packages/astro/src/core/sync/index.ts | 22 ++++------------------ 7 files changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts index db1d376121c5..8091474706f0 100644 --- a/packages/astro/src/cli/check/index.ts +++ b/packages/astro/src/cli/check/index.ts @@ -4,6 +4,7 @@ import { ensureProcessNodeEnv } from '../../core/util.js'; import { createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js'; import { getPackage } from '../install-package.js'; import { resolveConfig } from '../../core/config/config.js'; +import { createSettings } from '../../core/config/settings.js'; export async function check(flags: Arguments) { ensureProcessNodeEnv('production'); @@ -31,8 +32,9 @@ export async function check(flags: Arguments) { const { default: sync } = await import('../../core/sync/index.js'); const inlineConfig = flagsToAstroInlineConfig(flags); const { astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); + const settings = await createSettings(astroConfig, inlineConfig.root); try { - await sync({ astroConfig, logger }); + await sync({ settings, logger }); } catch (_) { return process.exit(1); } diff --git a/packages/astro/src/cli/sync/index.ts b/packages/astro/src/cli/sync/index.ts index 28324cf439a0..707d3f3d95bd 100644 --- a/packages/astro/src/cli/sync/index.ts +++ b/packages/astro/src/cli/sync/index.ts @@ -6,6 +6,7 @@ import { resolveConfig } from '../../core/config/config.js'; import { createNodeLogger } from '../../core/config/logging.js'; import { telemetry } from '../../events/index.js'; import { eventCliSession } from '../../events/session.js'; +import { createSettings } from '../../core/config/settings.js'; type ProcessExit = 0 | 1; @@ -30,9 +31,10 @@ export async function sync({ flags }: SyncOptions): Promise { const logger = createNodeLogger(inlineConfig); const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); telemetry.record(eventCliSession('sync', userConfig)); + const settings = await createSettings(astroConfig, inlineConfig.root); try { - await _sync({ astroConfig, logger }); + await _sync({ logger, settings }); return 0; } catch (_) { return 1; diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index 08fe4bf227fc..285651eb22c6 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -17,6 +17,7 @@ import { runHookBuildDone, runHookBuildStart, runHookConfigDone, + runHookConfigSetup, } from '../../integrations/hooks.js'; import { resolveConfig } from '../config/config.js'; import { createNodeLogger } from '../config/logging.js'; @@ -119,12 +120,15 @@ class AstroBuilder { const { logger } = this; this.timer.init = performance.now(); + this.settings = await runHookConfigSetup({ + settings: this.settings, + command: 'build', + logger: logger, + }); const { default: sync } = await import('../sync/index.js'); - - this.settings = await sync({ + await sync({ settings: this.settings, logger, - astroConfig: this.settings.config, fs, }); diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts index 0102a87cd0be..e8e573c10798 100644 --- a/packages/astro/src/core/dev/container.ts +++ b/packages/astro/src/core/dev/container.ts @@ -14,6 +14,7 @@ import { import { createVite } from '../create-vite.js'; import type { Logger } from '../logger/core.js'; import { apply as applyPolyfill } from '../polyfill.js'; +import sync from '../sync/index.js'; export interface Container { fs: typeof nodeFs; @@ -49,6 +50,11 @@ export async function createContainer({ logger: logger, isRestart, }); + await sync({ + settings, + logger, + fs, + }); settings = injectImageEndpoint(settings, 'dev'); diff --git a/packages/astro/src/core/index.ts b/packages/astro/src/core/index.ts index 8771b7334f5c..10ebe9a668ee 100644 --- a/packages/astro/src/core/index.ts +++ b/packages/astro/src/core/index.ts @@ -7,6 +7,8 @@ import { resolveConfig } from './config/config.js'; import { createNodeLogger } from './config/logging.js'; import { telemetry } from '../events/index.js'; import { eventCliSession } from '../events/session.js'; +import { createSettings } from './config/settings.js'; +import { runHookConfigSetup } from '../integrations/hooks.js'; export { default as dev } from './dev/index.js'; export { default as preview } from './preview/index.js'; @@ -30,6 +32,12 @@ export const build = (inlineConfig: AstroInlineConfig) => _build(inlineConfig); export const sync = async (inlineConfig: AstroInlineConfig) => { const logger = createNodeLogger(inlineConfig); const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); + let settings = await createSettings(astroConfig, inlineConfig.root); telemetry.record(eventCliSession('sync', userConfig)); - return await _sync({ astroConfig, logger }); + settings = await runHookConfigSetup({ + command: 'build', + settings, + logger, + }); + return await _sync({ settings, logger }); }; diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts index e7e3282ff3d2..7dc8a1dfaaf5 100644 --- a/packages/astro/src/core/preview/index.ts +++ b/packages/astro/src/core/preview/index.ts @@ -29,6 +29,7 @@ export default async function preview(inlineConfig: AstroInlineConfig): Promise< const _settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root)); + // TODO: should astro:config:* hooks be removed in preview? To be tested const settings = await runHookConfigSetup({ settings: _settings, command: 'preview', diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 84f96fad49b6..d733495f1fba 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -8,10 +8,8 @@ import { getPackage } from '../../cli/install-package.js'; import { createContentTypesGenerator } from '../../content/index.js'; import { globalContentConfigObserver } from '../../content/utils.js'; import { syncAstroEnv } from '../../env/sync.js'; -import { runHookConfigSetup } from '../../integrations/hooks.js'; import { setUpEnvTs } from '../../vite-plugin-inject-env-ts/index.js'; import { getTimeStat } from '../build/util.js'; -import { createSettings } from '../config/settings.js'; import { createVite } from '../create-vite.js'; import { collectErrorMetadata } from '../errors/dev/utils.js'; import { @@ -31,8 +29,7 @@ export type SyncOptions = { */ fs?: typeof fsMod; logger: Logger; - astroConfig: AstroConfig; - settings?: AstroSettings; + settings: AstroSettings; }; type DBPackage = { @@ -46,21 +43,12 @@ type DBPackage = { * @experimental The JavaScript API is experimental */ export default async function sync({ - astroConfig, logger, fs = fsMod, settings, -}: SyncOptions): Promise { +}: SyncOptions): Promise { ensureProcessNodeEnv('production'); - const cwd = fileURLToPath(astroConfig.root); - - settings ??= await createSettings(astroConfig, cwd); - - settings = await runHookConfigSetup({ - settings, - logger, - command: 'build', - }); + const cwd = fileURLToPath(settings.config.root); const timerStart = performance.now(); const dbPackage = await getPackage( @@ -74,14 +62,12 @@ export default async function sync({ ); try { - await dbPackage?.typegen?.(astroConfig); + await dbPackage?.typegen?.(settings.config); await syncContentCollections(settings, { fs, logger }); syncAstroEnv(settings, fs); await setUpEnvTs({ settings, logger, fs }); logger.info(null, `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`); - - return settings; } catch (err) { const error = createSafeError(err); logger.error( From 0e7a5d0ae1a57c7cf09efa3612b8094b9021c9e0 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 4 Jul 2024 16:59:11 +0200 Subject: [PATCH 03/19] fix: do not pass fs in test container --- packages/astro/src/core/dev/container.ts | 1 - packages/astro/src/core/sync/index.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts index e8e573c10798..42a5e24068f5 100644 --- a/packages/astro/src/core/dev/container.ts +++ b/packages/astro/src/core/dev/container.ts @@ -53,7 +53,6 @@ export async function createContainer({ await sync({ settings, logger, - fs, }); settings = injectImageEndpoint(settings, 'dev'); diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index d733495f1fba..473d272d14a5 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -95,7 +95,7 @@ export default async function sync({ */ async function syncContentCollections( settings: AstroSettings, - { logger, fs }: Pick + { logger, fs }: Required> ): Promise { // Needed to load content config const tempViteServer = await createServer( @@ -124,7 +124,7 @@ async function syncContentCollections( const contentTypesGenerator = await createContentTypesGenerator({ contentConfigObserver: globalContentConfigObserver, logger: logger, - fs: fs ?? fsMod, + fs, settings, viteServer: tempViteServer, }); From 7b2758a596f0dcafe103080030f8c7e899bddac8 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 4 Jul 2024 17:17:23 +0200 Subject: [PATCH 04/19] fix: test --- .../collections-mixed-content-errors.test.js | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js index 0086b51e83ac..3da5095744e4 100644 --- a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js +++ b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js @@ -2,12 +2,27 @@ import * as assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import { fileURLToPath } from 'node:url'; import _sync from '../../../dist/core/sync/index.js'; +import { resolveConfig } from '../../../dist/core/config/config.js'; +import { createSettings } from '../../../dist/core/config/settings.js'; +import { createNodeLogger } from '../../../dist/core/config/logging.js'; import { createFsWithFallback } from '../test-utils.js'; const root = new URL('../../fixtures/content-mixed-errors/', import.meta.url); -async function sync({ fs, config = {} }) { - return _sync({ ...config, root: fileURLToPath(root), logLevel: 'silent' }, { fs }); +async function sync({ fs }) { + const inlineConfig = { + root: fileURLToPath(root), + logLevel: 'silent', + }; + const logger = createNodeLogger(inlineConfig); + const { astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); + const settings = await createSettings(astroConfig, inlineConfig.root); + try { + await _sync({ settings, logger, fs }); + return 0; + } catch (_) { + return 1; + } } describe('Content Collections - mixed content errors', () => { @@ -114,7 +129,7 @@ title: Post const res = await sync({ fs }); assert.equal(res, 0); } catch (e) { - expect.fail(0, 1, `Did not expect sync to throw: ${e.message}`); + assert.fail(`Did not expect sync to throw: ${e.message}`); } }); }); From 886659e1c887d3bb313cde4ccb26efc4c1a4a13f Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 4 Jul 2024 18:05:35 +0200 Subject: [PATCH 05/19] fix: test --- packages/astro/src/actions/index.ts | 22 ++++++++++++++-------- packages/astro/src/core/sync/index.ts | 6 +----- packages/astro/src/integrations/hooks.ts | 8 +++++--- packages/astro/test/astro-sync.test.js | 19 +++++++++++++++---- packages/astro/test/test-utils.js | 4 ++-- 5 files changed, 37 insertions(+), 22 deletions(-) diff --git a/packages/astro/src/actions/index.ts b/packages/astro/src/actions/index.ts index e20f8647dd97..f4ab24e2d428 100644 --- a/packages/astro/src/actions/index.ts +++ b/packages/astro/src/actions/index.ts @@ -1,4 +1,4 @@ -import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import fsMod from 'node:fs'; import type { Plugin as VitePlugin } from 'vite'; import type { AstroIntegration } from '../@types/astro.js'; import { ActionsWithoutServerOutputError } from '../core/errors/errors-data.js'; @@ -6,7 +6,7 @@ import { AstroError } from '../core/errors/errors.js'; import { isServerLikeOutput, viteID } from '../core/util.js'; import { ACTIONS_TYPES_FILE, RESOLVED_VIRTUAL_MODULE_ID, VIRTUAL_MODULE_ID } from './consts.js'; -export default function astroActions(): AstroIntegration { +export default function astroActions({ fs = fsMod }: { fs?: typeof fsMod }): AstroIntegration { return { name: VIRTUAL_MODULE_ID, hooks: { @@ -25,7 +25,7 @@ export default function astroActions(): AstroIntegration { define: { 'import.meta.env.ACTIONS_PATH': stringifiedActionsImport, }, - plugins: [vitePluginActions], + plugins: [vitePluginActions(fs)], }, }); @@ -43,13 +43,14 @@ export default function astroActions(): AstroIntegration { await typegen({ stringifiedActionsImport, root: params.config.root, + fs, }); }, }, }; } -const vitePluginActions: VitePlugin = { +const vitePluginActions = (fs: typeof fsMod): VitePlugin => ({ name: VIRTUAL_MODULE_ID, enforce: 'pre', resolveId(id) { @@ -60,7 +61,10 @@ const vitePluginActions: VitePlugin = { async load(id, opts) { if (id !== RESOLVED_VIRTUAL_MODULE_ID) return; - let code = await readFile(new URL('../../templates/actions.mjs', import.meta.url), 'utf-8'); + let code = await fs.promises.readFile( + new URL('../../templates/actions.mjs', import.meta.url), + 'utf-8' + ); if (opts?.ssr) { code += `\nexport * from 'astro/actions/runtime/virtual/server.js';`; } else { @@ -68,14 +72,16 @@ const vitePluginActions: VitePlugin = { } return code; }, -}; +}); async function typegen({ stringifiedActionsImport, root, + fs, }: { stringifiedActionsImport: string; root: URL; + fs: typeof fsMod; }) { const content = `declare module "astro:actions" { type Actions = typeof import(${stringifiedActionsImport})["server"]; @@ -85,6 +91,6 @@ async function typegen({ const dotAstroDir = new URL('.astro/', root); - await mkdir(dotAstroDir, { recursive: true }); - await writeFile(new URL(ACTIONS_TYPES_FILE, dotAstroDir), content); + await fs.promises.mkdir(dotAstroDir, { recursive: true }); + await fs.promises.writeFile(new URL(ACTIONS_TYPES_FILE, dotAstroDir), content); } diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 473d272d14a5..f49db8d647fd 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -42,11 +42,7 @@ type DBPackage = { * * @experimental The JavaScript API is experimental */ -export default async function sync({ - logger, - fs = fsMod, - settings, -}: SyncOptions): Promise { +export default async function sync({ logger, fs = fsMod, settings }: SyncOptions): Promise { ensureProcessNodeEnv('production'); const cwd = fileURLToPath(settings.config.root); diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index 0e58f7e8588f..0da9c883379d 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -1,4 +1,4 @@ -import fs from 'node:fs'; +import fsMod from 'node:fs'; import type { AddressInfo } from 'node:net'; import { fileURLToPath } from 'node:url'; import { bold } from 'kleur/colors'; @@ -105,11 +105,13 @@ export async function runHookConfigSetup({ command, logger, isRestart = false, + fs = fsMod }: { settings: AstroSettings; command: 'dev' | 'build' | 'preview'; logger: Logger; isRestart?: boolean; + fs?: typeof fsMod }): Promise { // An adapter is an integration, so if one is provided push it. if (settings.config.adapter) { @@ -117,7 +119,7 @@ export async function runHookConfigSetup({ } if (settings.config.experimental?.actions) { const { default: actionsIntegration } = await import('../actions/index.js'); - settings.config.integrations.push(actionsIntegration()); + settings.config.integrations.push(actionsIntegration({ fs })); } let updatedConfig: AstroConfig = { ...settings.config }; @@ -532,7 +534,7 @@ export async function runHookBuildDone({ cacheManifest, }: RunHookBuildDone) { const dir = isServerLikeOutput(config) ? config.build.client : config.outDir; - await fs.promises.mkdir(dir, { recursive: true }); + await fsMod.promises.mkdir(dir, { recursive: true }); for (const integration of config.integrations) { if (integration?.hooks?.['astro:build:done']) { diff --git a/packages/astro/test/astro-sync.test.js b/packages/astro/test/astro-sync.test.js index 11152f77b2d8..2ad2efdd2d03 100644 --- a/packages/astro/test/astro-sync.test.js +++ b/packages/astro/test/astro-sync.test.js @@ -3,6 +3,11 @@ import * as fs from 'node:fs'; import { before, describe, it } from 'node:test'; import ts from 'typescript'; import { loadFixture } from './test-utils.js'; +import { createNodeLogger } from '../dist/core/config/logging.js'; +import { resolveConfig } from '../dist/core/config/config.js'; +import { createSettings } from '../dist/core/config/settings.js'; +import { fileURLToPath } from 'node:url'; +import { runHookConfigSetup } from '../dist/integrations/hooks.js'; const createFixture = () => { /** @type {Awaited>} */ @@ -47,10 +52,16 @@ const createFixture = () => { }, }; - const code = await astroFixture.sync({}, { fs: fsMock }); - if (code !== 0) { - throw new Error(`Process error code ${code}`); - } + const inlineConfig = { root: fileURLToPath(new URL(root, import.meta.url)) }; + const logger = createNodeLogger(inlineConfig); + const { astroConfig } = await resolveConfig(inlineConfig, 'sync'); + let settings = await createSettings(astroConfig, inlineConfig.root); + settings = await runHookConfigSetup({ + settings, + command: 'build', + logger, + }); + await astroFixture.sync({ settings, logger, fs: fsMock }); }, /** @param {string} path */ thenFileShouldExist(path) { diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index d68d64e3870c..aed973a79685 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -161,8 +161,8 @@ export async function loadFixture(inlineConfig) { process.env.NODE_ENV = 'production'; return build(mergeConfig(inlineConfig, extraInlineConfig), { teardownCompiler: false }); }, - sync: async (extraInlineConfig = {}, opts) => { - return sync(mergeConfig(inlineConfig, extraInlineConfig), opts); + sync: async (options) => { + return sync(options); }, check: async (opts) => { return await check(opts); From 171b934e36e6ab0e9979cf482b85360141f84b1c Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 10 Jul 2024 14:24:46 +0200 Subject: [PATCH 06/19] fix: run sync after config done in dev --- packages/astro/src/core/dev/container.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts index 42a5e24068f5..0c3d814763be 100644 --- a/packages/astro/src/core/dev/container.ts +++ b/packages/astro/src/core/dev/container.ts @@ -50,10 +50,6 @@ export async function createContainer({ logger: logger, isRestart, }); - await sync({ - settings, - logger, - }); settings = injectImageEndpoint(settings, 'dev'); @@ -82,6 +78,11 @@ export async function createContainer({ { settings, logger, mode: 'dev', command: 'dev', fs, sync: false } ); await runHookConfigDone({ settings, logger }); + await sync({ + settings, + logger, + }); + const viteServer = await vite.createServer(viteConfig); const container: Container = { From 53a7d6317aaf0940ebca672804fd5aa7023902b6 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 10 Jul 2024 14:41:09 +0200 Subject: [PATCH 07/19] feat: run sync after astro:config:done in build --- packages/astro/src/core/build/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index 285651eb22c6..c313956ff2fe 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -119,18 +119,11 @@ class AstroBuilder { this.logger.debug('build', 'Initial setup...'); const { logger } = this; this.timer.init = performance.now(); - this.settings = await runHookConfigSetup({ settings: this.settings, command: 'build', logger: logger, }); - const { default: sync } = await import('../sync/index.js'); - await sync({ - settings: this.settings, - logger, - fs, - }); if (isServerLikeOutput(this.settings.config)) { this.settings = injectImageEndpoint(this.settings, 'build'); @@ -150,6 +143,13 @@ class AstroBuilder { ); await runHookConfigDone({ settings: this.settings, logger: logger }); + const { default: sync } = await import('../sync/index.js'); + await sync({ + settings: this.settings, + logger, + fs, + }); + return { viteConfig }; } From b7b2e21edc03154edc97921f22adbb98d9cfbde9 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 10 Jul 2024 15:41:57 +0200 Subject: [PATCH 08/19] fix: skip content in dev --- packages/astro/src/core/dev/container.ts | 3 +++ packages/astro/src/core/sync/index.ts | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts index 0c3d814763be..050f954f0899 100644 --- a/packages/astro/src/core/dev/container.ts +++ b/packages/astro/src/core/dev/container.ts @@ -81,6 +81,9 @@ export async function createContainer({ await sync({ settings, logger, + skip: { + content: true, + }, }); const viteServer = await vite.createServer(viteConfig); diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index f49db8d647fd..dcc632275780 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -30,6 +30,10 @@ export type SyncOptions = { fs?: typeof fsMod; logger: Logger; settings: AstroSettings; + skip?: { + // Must be skipped in dev + content?: boolean; + }; }; type DBPackage = { @@ -42,7 +46,12 @@ type DBPackage = { * * @experimental The JavaScript API is experimental */ -export default async function sync({ logger, fs = fsMod, settings }: SyncOptions): Promise { +export default async function sync({ + logger, + fs = fsMod, + settings, + skip, +}: SyncOptions): Promise { ensureProcessNodeEnv('production'); const cwd = fileURLToPath(settings.config.root); @@ -59,7 +68,9 @@ export default async function sync({ logger, fs = fsMod, settings }: SyncOptions try { await dbPackage?.typegen?.(settings.config); - await syncContentCollections(settings, { fs, logger }); + if (!skip?.content) { + await syncContentCollections(settings, { fs, logger }); + } syncAstroEnv(settings, fs); await setUpEnvTs({ settings, logger, fs }); From 6528fef18afade3bb1fcf92d953033057b5b483d Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 10 Jul 2024 16:04:06 +0200 Subject: [PATCH 09/19] feat: clean setupEnvTs --- packages/astro/src/core/create-vite.ts | 2 - packages/astro/src/core/sync/index.ts | 2 +- .../index.ts => core/sync/setup-env-ts.ts} | 38 ++++--------------- 3 files changed, 8 insertions(+), 34 deletions(-) rename packages/astro/src/{vite-plugin-inject-env-ts/index.ts => core/sync/setup-env-ts.ts} (74%) diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index e07150c39db8..06c6c96b43ec 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -25,7 +25,6 @@ import envVitePlugin from '../vite-plugin-env/index.js'; import vitePluginFileURL from '../vite-plugin-fileurl/index.js'; import astroHeadPlugin from '../vite-plugin-head/index.js'; import htmlVitePlugin from '../vite-plugin-html/index.js'; -import { astroInjectEnvTsPlugin } from '../vite-plugin-inject-env-ts/index.js'; import astroIntegrationsContainerPlugin from '../vite-plugin-integrations-container/index.js'; import astroLoadFallbackPlugin from '../vite-plugin-load-fallback/index.js'; import markdownVitePlugin from '../vite-plugin-markdown/index.js'; @@ -147,7 +146,6 @@ export async function createVite( astroScriptsPageSSRPlugin({ settings }), astroHeadPlugin(), astroScannerPlugin({ settings, logger }), - astroInjectEnvTsPlugin({ settings, logger, fs }), astroContentVirtualModPlugin({ fs, settings }), astroContentImportPlugin({ fs, settings, logger }), astroContentAssetPropagationPlugin({ mode, settings }), diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index dcc632275780..d127a8be42e4 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -8,7 +8,7 @@ import { getPackage } from '../../cli/install-package.js'; import { createContentTypesGenerator } from '../../content/index.js'; import { globalContentConfigObserver } from '../../content/utils.js'; import { syncAstroEnv } from '../../env/sync.js'; -import { setUpEnvTs } from '../../vite-plugin-inject-env-ts/index.js'; +import { setUpEnvTs } from './setup-env-ts.js'; import { getTimeStat } from '../build/util.js'; import { createVite } from '../create-vite.js'; import { collectErrorMetadata } from '../errors/dev/utils.js'; diff --git a/packages/astro/src/vite-plugin-inject-env-ts/index.ts b/packages/astro/src/core/sync/setup-env-ts.ts similarity index 74% rename from packages/astro/src/vite-plugin-inject-env-ts/index.ts rename to packages/astro/src/core/sync/setup-env-ts.ts index 3ebecce2dd51..f21f07af2502 100644 --- a/packages/astro/src/vite-plugin-inject-env-ts/index.ts +++ b/packages/astro/src/core/sync/setup-env-ts.ts @@ -2,36 +2,12 @@ import type fsMod from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { bold } from 'kleur/colors'; -import { type Plugin, normalizePath } from 'vite'; -import type { AstroSettings } from '../@types/astro.js'; -import { ACTIONS_TYPES_FILE } from '../actions/consts.js'; -import { CONTENT_TYPES_FILE } from '../content/consts.js'; -import { type Logger } from '../core/logger/core.js'; -import { ENV_TYPES_FILE } from '../env/constants.js'; - -export function getEnvTsPath({ srcDir }: { srcDir: URL }) { - return new URL('env.d.ts', srcDir); -} - -export function astroInjectEnvTsPlugin({ - settings, - logger, - fs, -}: { - settings: AstroSettings; - logger: Logger; - fs: typeof fsMod; -}): Plugin { - return { - name: 'astro-inject-env-ts', - // Use `post` to ensure project setup is complete - // Ex. `.astro` types have been written - enforce: 'post', - async config() { - await setUpEnvTs({ settings, logger, fs }); - }, - }; -} +import { normalizePath } from 'vite'; +import type { AstroSettings } from '../../@types/astro.js'; +import { ACTIONS_TYPES_FILE } from '../../actions/consts.js'; +import { CONTENT_TYPES_FILE } from '../../content/consts.js'; +import { type Logger } from '../logger/core.js'; +import { ENV_TYPES_FILE } from '../../env/constants.js'; function getDotAstroTypeReference({ settings, @@ -58,7 +34,7 @@ export async function setUpEnvTs({ logger: Logger; fs: typeof fsMod; }) { - const envTsPath = getEnvTsPath(settings.config); + const envTsPath = new URL('env.d.ts', settings.config.srcDir); const envTsPathRelativetoRoot = normalizePath( path.relative(fileURLToPath(settings.config.root), fileURLToPath(envTsPath)) ); From 98c1e7f324c053249fa99db6e7b6c8a7d3016e99 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 10 Jul 2024 16:41:39 +0200 Subject: [PATCH 10/19] feat: extract repetitive logic to syncInlineConfig --- packages/astro/src/cli/check/index.ts | 9 ++----- packages/astro/src/cli/sync/index.ts | 19 +++----------- packages/astro/src/core/index.ts | 23 +++------------- packages/astro/src/core/sync/index.ts | 26 ++++++++++++++++++- packages/astro/test/astro-sync.test.js | 17 +++--------- packages/astro/test/test-utils.js | 4 +-- .../collections-mixed-content-errors.test.js | 20 ++++++-------- 7 files changed, 46 insertions(+), 72 deletions(-) diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts index 8091474706f0..8764d38da697 100644 --- a/packages/astro/src/cli/check/index.ts +++ b/packages/astro/src/cli/check/index.ts @@ -3,8 +3,6 @@ import type { Arguments } from 'yargs-parser'; import { ensureProcessNodeEnv } from '../../core/util.js'; import { createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js'; import { getPackage } from '../install-package.js'; -import { resolveConfig } from '../../core/config/config.js'; -import { createSettings } from '../../core/config/settings.js'; export async function check(flags: Arguments) { ensureProcessNodeEnv('production'); @@ -29,12 +27,9 @@ export async function check(flags: Arguments) { // Run sync before check to make sure types are generated. // NOTE: In the future, `@astrojs/check` can expose a `before lint` hook so that this works during `astro check --watch` too. // For now, we run this once as usually `astro check --watch` is ran alongside `astro dev` which also calls `astro sync`. - const { default: sync } = await import('../../core/sync/index.js'); - const inlineConfig = flagsToAstroInlineConfig(flags); - const { astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); - const settings = await createSettings(astroConfig, inlineConfig.root); + const { syncInlineConfig } = await import('../../core/sync/index.js'); try { - await sync({ settings, logger }); + await syncInlineConfig({ inlineConfig: flagsToAstroInlineConfig(flags) }); } catch (_) { return process.exit(1); } diff --git a/packages/astro/src/cli/sync/index.ts b/packages/astro/src/cli/sync/index.ts index 707d3f3d95bd..50f6a7dd3fde 100644 --- a/packages/astro/src/cli/sync/index.ts +++ b/packages/astro/src/cli/sync/index.ts @@ -1,20 +1,13 @@ import type yargs from 'yargs-parser'; import { printHelp } from '../../core/messages.js'; -import _sync from '../../core/sync/index.js'; +import { syncInlineConfig } from '../../core/sync/index.js'; import { flagsToAstroInlineConfig } from '../flags.js'; -import { resolveConfig } from '../../core/config/config.js'; -import { createNodeLogger } from '../../core/config/logging.js'; -import { telemetry } from '../../events/index.js'; -import { eventCliSession } from '../../events/session.js'; -import { createSettings } from '../../core/config/settings.js'; - -type ProcessExit = 0 | 1; interface SyncOptions { flags: yargs.Arguments; } -export async function sync({ flags }: SyncOptions): Promise { +export async function sync({ flags }: SyncOptions) { if (flags?.help || flags?.h) { printHelp({ commandName: 'astro sync', @@ -27,14 +20,8 @@ export async function sync({ flags }: SyncOptions): Promise { return 0; } - const inlineConfig = flagsToAstroInlineConfig(flags); - const logger = createNodeLogger(inlineConfig); - const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); - telemetry.record(eventCliSession('sync', userConfig)); - const settings = await createSettings(astroConfig, inlineConfig.root); - try { - await _sync({ logger, settings }); + await syncInlineConfig({ inlineConfig: flagsToAstroInlineConfig(flags), telemetry: true }); return 0; } catch (_) { return 1; diff --git a/packages/astro/src/core/index.ts b/packages/astro/src/core/index.ts index 10ebe9a668ee..5ee3afb84aff 100644 --- a/packages/astro/src/core/index.ts +++ b/packages/astro/src/core/index.ts @@ -2,13 +2,7 @@ import type { AstroInlineConfig } from '../@types/astro.js'; import { default as _build } from './build/index.js'; -import { default as _sync } from './sync/index.js'; -import { resolveConfig } from './config/config.js'; -import { createNodeLogger } from './config/logging.js'; -import { telemetry } from '../events/index.js'; -import { eventCliSession } from '../events/session.js'; -import { createSettings } from './config/settings.js'; -import { runHookConfigSetup } from '../integrations/hooks.js'; +import { syncInlineConfig } from './sync/index.js'; export { default as dev } from './dev/index.js'; export { default as preview } from './preview/index.js'; @@ -28,16 +22,5 @@ export const build = (inlineConfig: AstroInlineConfig) => _build(inlineConfig); * * @experimental The JavaScript API is experimental */ -// Wrap `_sync` to prevent exposing the second internal options parameter -export const sync = async (inlineConfig: AstroInlineConfig) => { - const logger = createNodeLogger(inlineConfig); - const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); - let settings = await createSettings(astroConfig, inlineConfig.root); - telemetry.record(eventCliSession('sync', userConfig)); - settings = await runHookConfigSetup({ - command: 'build', - settings, - logger, - }); - return await _sync({ settings, logger }); -}; +// Wrap `syncInlineConfig` to prevent exposing internal options +export const sync = async (inlineConfig: AstroInlineConfig) => syncInlineConfig({ inlineConfig }); diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index d127a8be42e4..767cdf0b7ea6 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -3,7 +3,7 @@ import fsMod from 'node:fs'; import { performance } from 'node:perf_hooks'; import { fileURLToPath } from 'node:url'; import { type HMRPayload, createServer } from 'vite'; -import type { AstroConfig, AstroSettings } from '../../@types/astro.js'; +import type { AstroConfig, AstroInlineConfig, AstroSettings } from '../../@types/astro.js'; import { getPackage } from '../../cli/install-package.js'; import { createContentTypesGenerator } from '../../content/index.js'; import { globalContentConfigObserver } from '../../content/utils.js'; @@ -22,6 +22,11 @@ import { import type { Logger } from '../logger/core.js'; import { formatErrorMessage } from '../messages.js'; import { ensureProcessNodeEnv } from '../util.js'; +import { createNodeLogger } from '../config/logging.js'; +import { resolveConfig } from '../config/config.js'; +import { createSettings } from '../config/settings.js'; +import { telemetry } from '../../events/index.js'; +import { eventCliSession } from '../../events/session.js'; export type SyncOptions = { /** @@ -40,6 +45,25 @@ type DBPackage = { typegen?: (args: Pick) => Promise; }; +export async function syncInlineConfig({ + inlineConfig, + fs, + telemetry: _telemetry = false, +}: { inlineConfig: AstroInlineConfig; fs?: typeof fsMod; telemetry?: boolean }) { + const logger = createNodeLogger(inlineConfig); + const { astroConfig, userConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); + if (_telemetry) { + telemetry.record(eventCliSession('sync', userConfig)); + } + let settings = await createSettings(astroConfig, inlineConfig.root); + settings = await runHookConfigSetup({ + command: 'build', + settings, + logger, + }); + return await sync({ settings, logger, fs }); +} + /** * Generates TypeScript types for all Astro modules. This sets up a `src/env.d.ts` file for type inferencing, * and defines the `astro:content` module for the Content Collections API. diff --git a/packages/astro/test/astro-sync.test.js b/packages/astro/test/astro-sync.test.js index 2ad2efdd2d03..d2baad293d24 100644 --- a/packages/astro/test/astro-sync.test.js +++ b/packages/astro/test/astro-sync.test.js @@ -3,11 +3,6 @@ import * as fs from 'node:fs'; import { before, describe, it } from 'node:test'; import ts from 'typescript'; import { loadFixture } from './test-utils.js'; -import { createNodeLogger } from '../dist/core/config/logging.js'; -import { resolveConfig } from '../dist/core/config/config.js'; -import { createSettings } from '../dist/core/config/settings.js'; -import { fileURLToPath } from 'node:url'; -import { runHookConfigSetup } from '../dist/integrations/hooks.js'; const createFixture = () => { /** @type {Awaited>} */ @@ -52,16 +47,10 @@ const createFixture = () => { }, }; - const inlineConfig = { root: fileURLToPath(new URL(root, import.meta.url)) }; - const logger = createNodeLogger(inlineConfig); - const { astroConfig } = await resolveConfig(inlineConfig, 'sync'); - let settings = await createSettings(astroConfig, inlineConfig.root); - settings = await runHookConfigSetup({ - settings, - command: 'build', - logger, + await astroFixture.sync({ + inlineConfig: { root: fileURLToPath(new URL(root, import.meta.url)) }, + fs: fsMock, }); - await astroFixture.sync({ settings, logger, fs: fsMock }); }, /** @param {string} path */ thenFileShouldExist(path) { diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index aed973a79685..a0bde8cb2e10 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -14,7 +14,7 @@ import { makeSplitEntryPointFileName } from '../dist/core/build/static-build.js' import { mergeConfig, resolveConfig } from '../dist/core/config/index.js'; import { dev, preview } from '../dist/core/index.js'; import { nodeLogDestination } from '../dist/core/logger/node.js'; -import sync from '../dist/core/sync/index.js'; +import { syncInlineConfig } from '../dist/core/sync/index.js'; // Disable telemetry when running tests process.env.ASTRO_TELEMETRY_DISABLED = true; @@ -162,7 +162,7 @@ export async function loadFixture(inlineConfig) { return build(mergeConfig(inlineConfig, extraInlineConfig), { teardownCompiler: false }); }, sync: async (options) => { - return sync(options); + return await syncInlineConfig(options) }, check: async (opts) => { return await check(opts); diff --git a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js index 3da5095744e4..2fc620b68808 100644 --- a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js +++ b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js @@ -1,24 +1,20 @@ import * as assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import { fileURLToPath } from 'node:url'; -import _sync from '../../../dist/core/sync/index.js'; -import { resolveConfig } from '../../../dist/core/config/config.js'; -import { createSettings } from '../../../dist/core/config/settings.js'; -import { createNodeLogger } from '../../../dist/core/config/logging.js'; +import { syncInlineConfig } from '../../../dist/core/sync/index.js'; import { createFsWithFallback } from '../test-utils.js'; const root = new URL('../../fixtures/content-mixed-errors/', import.meta.url); async function sync({ fs }) { - const inlineConfig = { - root: fileURLToPath(root), - logLevel: 'silent', - }; - const logger = createNodeLogger(inlineConfig); - const { astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); - const settings = await createSettings(astroConfig, inlineConfig.root); try { - await _sync({ settings, logger, fs }); + await syncInlineConfig({ + inlineConfig: { + root: fileURLToPath(root), + logLevel: 'silent', + }, + fs, + }); return 0; } catch (_) { return 1; From 97b1bbdaec7bf15706736f17a32b83a807b66287 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 10 Jul 2024 16:44:54 +0200 Subject: [PATCH 11/19] fix: import --- packages/astro/src/core/sync/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 767cdf0b7ea6..204268dbdfe3 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -27,6 +27,7 @@ import { resolveConfig } from '../config/config.js'; import { createSettings } from '../config/settings.js'; import { telemetry } from '../../events/index.js'; import { eventCliSession } from '../../events/session.js'; +import { runHookConfigSetup } from '../../integrations/hooks.js'; export type SyncOptions = { /** From 0016be003ccbd05051371bdd936fb32eeaa0d7ac Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 10 Jul 2024 16:56:56 +0200 Subject: [PATCH 12/19] chore: fix test and add changeset --- .changeset/modern-buses-check.md | 5 +++++ packages/astro/test/astro-sync.test.js | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/modern-buses-check.md diff --git a/.changeset/modern-buses-check.md b/.changeset/modern-buses-check.md new file mode 100644 index 000000000000..3cf7482c1bf1 --- /dev/null +++ b/.changeset/modern-buses-check.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Refactors how `sync` works and when it's called. Fixes an issue with `astro:env` types in dev not being generated diff --git a/packages/astro/test/astro-sync.test.js b/packages/astro/test/astro-sync.test.js index d2baad293d24..0e22a36c8d9a 100644 --- a/packages/astro/test/astro-sync.test.js +++ b/packages/astro/test/astro-sync.test.js @@ -3,6 +3,7 @@ import * as fs from 'node:fs'; import { before, describe, it } from 'node:test'; import ts from 'typescript'; import { loadFixture } from './test-utils.js'; +import { fileURLToPath } from 'node:url'; const createFixture = () => { /** @type {Awaited>} */ From 083368b0996460d41f2c938bc204c10c6996fac1 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 11 Jul 2024 15:03:16 +0200 Subject: [PATCH 13/19] feat: fix env.d.ts generation and improve logging --- packages/astro/src/core/sync/index.ts | 2 +- packages/astro/src/core/sync/setup-env-ts.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 204268dbdfe3..7cbe17c2311c 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -99,7 +99,7 @@ export default async function sync({ syncAstroEnv(settings, fs); await setUpEnvTs({ settings, logger, fs }); - logger.info(null, `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`); + logger.info('types', `Generated ${dim(getTimeStat(timerStart, performance.now()))}`); } catch (err) { const error = createSafeError(err); logger.error( diff --git a/packages/astro/src/core/sync/setup-env-ts.ts b/packages/astro/src/core/sync/setup-env-ts.ts index f21f07af2502..1363b0da8fb8 100644 --- a/packages/astro/src/core/sync/setup-env-ts.ts +++ b/packages/astro/src/core/sync/setup-env-ts.ts @@ -56,7 +56,8 @@ export async function setUpEnvTs({ } if (fs.existsSync(envTsPath)) { - let typesEnvContents = await fs.promises.readFile(envTsPath, 'utf-8'); + const initialEnvContents = await fs.promises.readFile(envTsPath, 'utf-8'); + let typesEnvContents = initialEnvContents for (const injectedType of injectedTypes) { if (!injectedType.meetsCondition || (await injectedType.meetsCondition?.())) { @@ -71,8 +72,10 @@ export async function setUpEnvTs({ } } - logger.info('types', `Added ${bold(envTsPathRelativetoRoot)} type declarations.`); - await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8'); + if (initialEnvContents !== typesEnvContents) { + logger.info('types', `Updated ${bold(envTsPathRelativetoRoot)} type declarations.`); + await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8'); + } } else { // Otherwise, inject the `env.d.ts` file let referenceDefs: string[] = []; From 24640087a1551ce8b04b6547ce713fa6d43c839a Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 11 Jul 2024 15:17:25 +0200 Subject: [PATCH 14/19] feat: try comment config hooks in preview --- packages/astro/src/core/preview/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts index 7dc8a1dfaaf5..e7d44675c9e3 100644 --- a/packages/astro/src/core/preview/index.ts +++ b/packages/astro/src/core/preview/index.ts @@ -27,15 +27,15 @@ export default async function preview(inlineConfig: AstroInlineConfig): Promise< const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'preview'); telemetry.record(eventCliSession('preview', userConfig)); - const _settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root)); + const settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root)); // TODO: should astro:config:* hooks be removed in preview? To be tested - const settings = await runHookConfigSetup({ - settings: _settings, - command: 'preview', - logger: logger, - }); - await runHookConfigDone({ settings: settings, logger: logger }); + // const settings = await runHookConfigSetup({ + // settings: _settings, + // command: 'preview', + // logger: logger, + // }); + // await runHookConfigDone({ settings: settings, logger: logger }); if (settings.config.output === 'static') { if (!fs.existsSync(settings.config.outDir)) { From ae5cda6218ea2f3d4089dc609efd1d26b4f983c8 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 11 Jul 2024 15:28:20 +0200 Subject: [PATCH 15/19] chore: revert --- packages/astro/src/core/preview/index.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts index e7d44675c9e3..e7e3282ff3d2 100644 --- a/packages/astro/src/core/preview/index.ts +++ b/packages/astro/src/core/preview/index.ts @@ -27,15 +27,14 @@ export default async function preview(inlineConfig: AstroInlineConfig): Promise< const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'preview'); telemetry.record(eventCliSession('preview', userConfig)); - const settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root)); + const _settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root)); - // TODO: should astro:config:* hooks be removed in preview? To be tested - // const settings = await runHookConfigSetup({ - // settings: _settings, - // command: 'preview', - // logger: logger, - // }); - // await runHookConfigDone({ settings: settings, logger: logger }); + const settings = await runHookConfigSetup({ + settings: _settings, + command: 'preview', + logger: logger, + }); + await runHookConfigDone({ settings: settings, logger: logger }); if (settings.config.output === 'static') { if (!fs.existsSync(settings.config.outDir)) { From 986c4d4490830e7f06ed8a78e22909fcc240a336 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 11 Jul 2024 15:29:23 +0200 Subject: [PATCH 16/19] Update packages/astro/src/core/index.ts --- packages/astro/src/core/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/core/index.ts b/packages/astro/src/core/index.ts index 5ee3afb84aff..789ccc36424c 100644 --- a/packages/astro/src/core/index.ts +++ b/packages/astro/src/core/index.ts @@ -23,4 +23,4 @@ export const build = (inlineConfig: AstroInlineConfig) => _build(inlineConfig); * @experimental The JavaScript API is experimental */ // Wrap `syncInlineConfig` to prevent exposing internal options -export const sync = async (inlineConfig: AstroInlineConfig) => syncInlineConfig({ inlineConfig }); +export const sync = (inlineConfig: AstroInlineConfig) => syncInlineConfig({ inlineConfig }); From 80808600d0d11e7e3dd020de366a75e631569af0 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 17 Jul 2024 16:12:35 +0200 Subject: [PATCH 17/19] fix: move node env check --- packages/astro/src/core/sync/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 7cbe17c2311c..1fc886eb5803 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -51,6 +51,7 @@ export async function syncInlineConfig({ fs, telemetry: _telemetry = false, }: { inlineConfig: AstroInlineConfig; fs?: typeof fsMod; telemetry?: boolean }) { + ensureProcessNodeEnv('production'); const logger = createNodeLogger(inlineConfig); const { astroConfig, userConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); if (_telemetry) { @@ -77,7 +78,6 @@ export default async function sync({ settings, skip, }: SyncOptions): Promise { - ensureProcessNodeEnv('production'); const cwd = fileURLToPath(settings.config.root); const timerStart = performance.now(); From 0b2a23aba1fd0afa4102f1d813bc55b2ba81e59f Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 17 Jul 2024 16:17:07 +0200 Subject: [PATCH 18/19] chore: renames --- packages/astro/src/cli/check/index.ts | 4 ++-- packages/astro/src/cli/sync/index.ts | 4 ++-- packages/astro/src/core/build/index.ts | 4 ++-- packages/astro/src/core/dev/container.ts | 4 ++-- packages/astro/src/core/index.ts | 6 +++--- packages/astro/src/core/sync/index.ts | 6 +++--- packages/astro/test/test-utils.js | 6 ++---- .../test/units/dev/collections-mixed-content-errors.test.js | 4 ++-- 8 files changed, 18 insertions(+), 20 deletions(-) diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts index 8764d38da697..ff7835fdca08 100644 --- a/packages/astro/src/cli/check/index.ts +++ b/packages/astro/src/cli/check/index.ts @@ -27,9 +27,9 @@ export async function check(flags: Arguments) { // Run sync before check to make sure types are generated. // NOTE: In the future, `@astrojs/check` can expose a `before lint` hook so that this works during `astro check --watch` too. // For now, we run this once as usually `astro check --watch` is ran alongside `astro dev` which also calls `astro sync`. - const { syncInlineConfig } = await import('../../core/sync/index.js'); + const { default: sync } = await import('../../core/sync/index.js'); try { - await syncInlineConfig({ inlineConfig: flagsToAstroInlineConfig(flags) }); + await sync({ inlineConfig: flagsToAstroInlineConfig(flags) }); } catch (_) { return process.exit(1); } diff --git a/packages/astro/src/cli/sync/index.ts b/packages/astro/src/cli/sync/index.ts index 50f6a7dd3fde..6849fee70844 100644 --- a/packages/astro/src/cli/sync/index.ts +++ b/packages/astro/src/cli/sync/index.ts @@ -1,6 +1,6 @@ import type yargs from 'yargs-parser'; import { printHelp } from '../../core/messages.js'; -import { syncInlineConfig } from '../../core/sync/index.js'; +import _sync from '../../core/sync/index.js'; import { flagsToAstroInlineConfig } from '../flags.js'; interface SyncOptions { @@ -21,7 +21,7 @@ export async function sync({ flags }: SyncOptions) { } try { - await syncInlineConfig({ inlineConfig: flagsToAstroInlineConfig(flags), telemetry: true }); + await _sync({ inlineConfig: flagsToAstroInlineConfig(flags), telemetry: true }); return 0; } catch (_) { return 1; diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index c313956ff2fe..7933b77f9732 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -143,8 +143,8 @@ class AstroBuilder { ); await runHookConfigDone({ settings: this.settings, logger: logger }); - const { default: sync } = await import('../sync/index.js'); - await sync({ + const { syncInternal } = await import('../sync/index.js'); + await syncInternal({ settings: this.settings, logger, fs, diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts index 050f954f0899..c54d3886d767 100644 --- a/packages/astro/src/core/dev/container.ts +++ b/packages/astro/src/core/dev/container.ts @@ -14,7 +14,7 @@ import { import { createVite } from '../create-vite.js'; import type { Logger } from '../logger/core.js'; import { apply as applyPolyfill } from '../polyfill.js'; -import sync from '../sync/index.js'; +import { syncInternal } from '../sync/index.js'; export interface Container { fs: typeof nodeFs; @@ -78,7 +78,7 @@ export async function createContainer({ { settings, logger, mode: 'dev', command: 'dev', fs, sync: false } ); await runHookConfigDone({ settings, logger }); - await sync({ + await syncInternal({ settings, logger, skip: { diff --git a/packages/astro/src/core/index.ts b/packages/astro/src/core/index.ts index 789ccc36424c..e0f9f6c82412 100644 --- a/packages/astro/src/core/index.ts +++ b/packages/astro/src/core/index.ts @@ -2,7 +2,7 @@ import type { AstroInlineConfig } from '../@types/astro.js'; import { default as _build } from './build/index.js'; -import { syncInlineConfig } from './sync/index.js'; +import { default as _sync } from './sync/index.js'; export { default as dev } from './dev/index.js'; export { default as preview } from './preview/index.js'; @@ -22,5 +22,5 @@ export const build = (inlineConfig: AstroInlineConfig) => _build(inlineConfig); * * @experimental The JavaScript API is experimental */ -// Wrap `syncInlineConfig` to prevent exposing internal options -export const sync = (inlineConfig: AstroInlineConfig) => syncInlineConfig({ inlineConfig }); +// Wrap `_sync` to prevent exposing internal options +export const sync = (inlineConfig: AstroInlineConfig) => _sync({ inlineConfig }); diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 1fc886eb5803..c95252953619 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -46,7 +46,7 @@ type DBPackage = { typegen?: (args: Pick) => Promise; }; -export async function syncInlineConfig({ +export default async function sync({ inlineConfig, fs, telemetry: _telemetry = false, @@ -63,7 +63,7 @@ export async function syncInlineConfig({ settings, logger, }); - return await sync({ settings, logger, fs }); + return await syncInternal({ settings, logger, fs }); } /** @@ -72,7 +72,7 @@ export async function syncInlineConfig({ * * @experimental The JavaScript API is experimental */ -export default async function sync({ +export async function syncInternal({ logger, fs = fsMod, settings, diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index a0bde8cb2e10..025fe63359e6 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -14,7 +14,7 @@ import { makeSplitEntryPointFileName } from '../dist/core/build/static-build.js' import { mergeConfig, resolveConfig } from '../dist/core/config/index.js'; import { dev, preview } from '../dist/core/index.js'; import { nodeLogDestination } from '../dist/core/logger/node.js'; -import { syncInlineConfig } from '../dist/core/sync/index.js'; +import sync from '../dist/core/sync/index.js'; // Disable telemetry when running tests process.env.ASTRO_TELEMETRY_DISABLED = true; @@ -161,9 +161,7 @@ export async function loadFixture(inlineConfig) { process.env.NODE_ENV = 'production'; return build(mergeConfig(inlineConfig, extraInlineConfig), { teardownCompiler: false }); }, - sync: async (options) => { - return await syncInlineConfig(options) - }, + sync, check: async (opts) => { return await check(opts); }, diff --git a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js index 2fc620b68808..1687d6809a01 100644 --- a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js +++ b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js @@ -1,14 +1,14 @@ import * as assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import { fileURLToPath } from 'node:url'; -import { syncInlineConfig } from '../../../dist/core/sync/index.js'; +import sync from '../../../dist/core/sync/index.js'; import { createFsWithFallback } from '../test-utils.js'; const root = new URL('../../fixtures/content-mixed-errors/', import.meta.url); async function sync({ fs }) { try { - await syncInlineConfig({ + await sync({ inlineConfig: { root: fileURLToPath(root), logLevel: 'silent', From e6993d07c8a5b8bb165124ec8651d2ea5667f71d Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 17 Jul 2024 16:25:41 +0200 Subject: [PATCH 19/19] fix: import --- .../test/units/dev/collections-mixed-content-errors.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js index 1687d6809a01..d63e42d53323 100644 --- a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js +++ b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js @@ -1,14 +1,14 @@ import * as assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import { fileURLToPath } from 'node:url'; -import sync from '../../../dist/core/sync/index.js'; +import _sync from '../../../dist/core/sync/index.js'; import { createFsWithFallback } from '../test-utils.js'; const root = new URL('../../fixtures/content-mixed-errors/', import.meta.url); async function sync({ fs }) { try { - await sync({ + await _sync({ inlineConfig: { root: fileURLToPath(root), logLevel: 'silent',