Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(astro): clean sync #11415

Merged
merged 22 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
17bfac3
feat: work on astro sync cleanup
florian-lefebvre Jul 4, 2024
40e6d0d
feat: call sync after astro:config:setup
florian-lefebvre Jul 4, 2024
0e7a5d0
fix: do not pass fs in test container
florian-lefebvre Jul 4, 2024
7b2758a
fix: test
florian-lefebvre Jul 4, 2024
886659e
fix: test
florian-lefebvre Jul 4, 2024
a8873ce
Merge branch 'main' into feat/clean-astro-sync
florian-lefebvre Jul 10, 2024
1c14fbf
Merge branch 'main' into feat/clean-astro-sync
florian-lefebvre Jul 10, 2024
171b934
fix: run sync after config done in dev
florian-lefebvre Jul 10, 2024
53a7d63
feat: run sync after astro:config:done in build
florian-lefebvre Jul 10, 2024
b7b2e21
fix: skip content in dev
florian-lefebvre Jul 10, 2024
6528fef
feat: clean setupEnvTs
florian-lefebvre Jul 10, 2024
98c1e7f
feat: extract repetitive logic to syncInlineConfig
florian-lefebvre Jul 10, 2024
97b1bbd
fix: import
florian-lefebvre Jul 10, 2024
0016be0
chore: fix test and add changeset
florian-lefebvre Jul 10, 2024
083368b
feat: fix env.d.ts generation and improve logging
florian-lefebvre Jul 11, 2024
2464008
feat: try comment config hooks in preview
florian-lefebvre Jul 11, 2024
ae5cda6
chore: revert
florian-lefebvre Jul 11, 2024
986c4d4
Update packages/astro/src/core/index.ts
florian-lefebvre Jul 11, 2024
8080860
fix: move node env check
florian-lefebvre Jul 17, 2024
0b2a23a
chore: renames
florian-lefebvre Jul 17, 2024
3dd37cf
Merge branch 'main' into feat/clean-astro-sync
florian-lefebvre Jul 17, 2024
e6993d0
fix: import
florian-lefebvre Jul 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading