Skip to content

Commit

Permalink
feat(astro): clean sync (#11415)
Browse files Browse the repository at this point in the history
  • Loading branch information
florian-lefebvre authored and ematipico committed Jul 18, 2024
1 parent ea94316 commit b2e1728
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 119 deletions.
5 changes: 5 additions & 0 deletions .changeset/modern-buses-check.md
Original file line number Diff line number Diff line change
@@ -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
22 changes: 14 additions & 8 deletions packages/astro/src/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
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';
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: {
Expand All @@ -25,7 +25,7 @@ export default function astroActions(): AstroIntegration {
define: {
'import.meta.env.ACTIONS_PATH': stringifiedActionsImport,
},
plugins: [vitePluginActions],
plugins: [vitePluginActions(fs)],
},
});

Expand All @@ -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) {
Expand All @@ -60,22 +61,27 @@ 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 {
code += `\nexport * from 'astro/actions/runtime/virtual/client.js';`;
}
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"];
Expand All @@ -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);
}
8 changes: 4 additions & 4 deletions packages/astro/src/cli/check/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ export async function check(flags: Arguments) {
// 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 exitCode = await sync(inlineConfig);
if (exitCode !== 0) {
process.exit(exitCode);
try {
await sync({ inlineConfig: flagsToAstroInlineConfig(flags) });
} catch (_) {
return process.exit(1);
}

const { check: checker, parseArgsAsCheckConfig } = checkPackage;
Expand Down
10 changes: 6 additions & 4 deletions packages/astro/src/cli/sync/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ export async function sync({ flags }: SyncOptions) {
return 0;
}

const inlineConfig = flagsToAstroInlineConfig(flags);

const exitCode = await _sync(inlineConfig);
return exitCode;
try {
await _sync({ inlineConfig: flagsToAstroInlineConfig(flags), telemetry: true });
return 0;
} catch (_) {
return 1;
}
}
11 changes: 6 additions & 5 deletions packages/astro/src/core/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,12 @@ 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);
}
const { syncInternal } = await import('../sync/index.js');
await syncInternal({
settings: this.settings,
logger,
fs,
});

return { viteConfig };
}
Expand Down
2 changes: 0 additions & 2 deletions packages/astro/src/core/create-vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -142,7 +141,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 }),
Expand Down
9 changes: 9 additions & 0 deletions packages/astro/src/core/dev/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { syncInternal } from '../sync/index.js';

export interface Container {
fs: typeof nodeFs;
Expand Down Expand Up @@ -90,6 +91,14 @@ export async function createContainer({
{ settings, logger, mode: 'dev', command: 'dev', fs, sync: false }
);
await runHookConfigDone({ settings, logger });
await syncInternal({
settings,
logger,
skip: {
content: true,
},
});

const viteServer = await vite.createServer(viteConfig);

const container: Container = {
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +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 = (inlineConfig: AstroInlineConfig) => _sync(inlineConfig);
// Wrap `_sync` to prevent exposing internal options
export const sync = (inlineConfig: AstroInlineConfig) => _sync({ inlineConfig });
102 changes: 55 additions & 47 deletions packages/astro/src/core/sync/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
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 { 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 { setUpEnvTs } from './setup-env-ts.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';
import {
Expand All @@ -28,73 +22,92 @@ import {
import type { Logger } from '../logger/core.js';
import { formatErrorMessage } from '../messages.js';
import { ensureProcessNodeEnv } from '../util.js';

export type ProcessExit = 0 | 1;
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';
import { runHookConfigSetup } from '../../integrations/hooks.js';

export type SyncOptions = {
/**
* @internal only used for testing
*/
fs?: typeof fsMod;
};

export type SyncInternalOptions = SyncOptions & {
logger: Logger;
settings: AstroSettings;
skip?: {
// Must be skipped in dev
content?: boolean;
};
};

type DBPackage = {
typegen?: (args: Pick<AstroConfig, 'root' | 'integrations'>) => Promise<void>;
};

export default async function sync({
inlineConfig,
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) {
telemetry.record(eventCliSession('sync', userConfig));
}
let settings = await createSettings(astroConfig, inlineConfig.root);
settings = await runHookConfigSetup({
command: 'build',
settings,
logger,
});
return await syncInternal({ 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.
*
* @experimental The JavaScript API is experimental
*/
export default async function sync(
inlineConfig: AstroInlineConfig,
options?: SyncOptions
): Promise<ProcessExit> {
ensureProcessNodeEnv('production');
const logger = createNodeLogger(inlineConfig);
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync');
telemetry.record(eventCliSession('sync', userConfig));

const _settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root));

const settings = await runHookConfigSetup({
settings: _settings,
logger: logger,
command: 'build',
});
export async function syncInternal({
logger,
fs = fsMod,
settings,
skip,
}: SyncOptions): Promise<void> {
const cwd = fileURLToPath(settings.config.root);

const timerStart = performance.now();
const dbPackage = await getPackage<DBPackage>(
'@astrojs/db',
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 dbPackage?.typegen?.(settings.config);
if (!skip?.content) {
await syncContentCollections(settings, { fs, logger });
}
syncAstroEnv(settings, fs);

logger.info(null, `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`);
return 0;
await setUpEnvTs({ settings, logger, fs });
logger.info('types', `Generated ${dim(getTimeStat(timerStart, performance.now()))}`);
} 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;
}
}

Expand All @@ -112,10 +125,10 @@ export default async function sync(
* @param {LogOptions} options.logging Logging options
* @return {Promise<ProcessExit>}
*/
export async function syncContentCollections(
async function syncContentCollections(
settings: AstroSettings,
{ logger, fs }: SyncInternalOptions
): Promise<ProcessExit> {
{ logger, fs }: Required<Pick<SyncOptions, 'logger' | 'fs'>>
): Promise<void> {
// Needed to load content config
const tempViteServer = await createServer(
await createVite(
Expand Down Expand Up @@ -143,7 +156,7 @@ export async function syncContentCollections(
const contentTypesGenerator = await createContentTypesGenerator({
contentConfigObserver: globalContentConfigObserver,
logger: logger,
fs: fs ?? fsMod,
fs,
settings,
viteServer: tempViteServer,
});
Expand All @@ -159,7 +172,6 @@ export async function syncContentCollections(
case 'no-content-dir':
default:
logger.debug('types', 'No content directory found. Skipping type generation.');
return 0;
}
}
} catch (e) {
Expand All @@ -179,8 +191,4 @@ export async function syncContentCollections(
} finally {
await tempViteServer.close();
}

await setUpEnvTs({ settings, logger, fs: fs ?? fsMod });

return 0;
}
Loading

0 comments on commit b2e1728

Please sign in to comment.