Export experimental JS API (#7979)

Co-authored-by: Chris Swithinbank <swithinbank@gmail.com>
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
Bjorn Lu 2023-08-18 16:52:04 +08:00 committed by GitHub
parent 8a5b0c1f3a
commit dbc97b121f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 139 additions and 29 deletions

View file

@ -0,0 +1,35 @@
---
'astro': major
---
Export experimental `dev`, `build`, `preview`, and `sync` APIs from `astro`. These APIs allow you to run Astro's commands programmatically, and replaces the previous entry point that runs the Astro CLI.
While these APIs are experimental, the inline config parameter is relatively stable without foreseeable changes. However, the returned results of these APIs are more likely to change in the future.
```ts
import { dev, build, preview, sync, type AstroInlineConfig } from 'astro';
// Inline Astro config object.
// Provide a path to a configuration file to load or set options directly inline.
const inlineConfig: AstroInlineConfig = {
// Inline-specific options...
configFile: './astro.config.mjs',
logLevel: 'info',
// Standard Astro config options...
site: 'https://example.com',
};
// Start the Astro dev server
const devServer = await dev(inlineConfig);
await devServer.stop();
// Build your Astro project
await build(inlineConfig);
// Preview your built project
const previewServer = await preview(inlineConfig);
await previewServer.stop();
// Generate types for your Astro project
await sync(inlineConfig);
```

2
packages/astro/index.d.ts vendored Normal file
View file

@ -0,0 +1,2 @@
export type * from './dist/@types/astro.js';
export * from './dist/core/index.js';

View file

@ -12,7 +12,7 @@
},
"bugs": "https://github.com/withastro/astro/issues",
"homepage": "https://astro.build",
"types": "./dist/@types/astro.d.ts",
"types": "./index.d.ts",
"typesVersions": {
"*": {
"app": [
@ -31,8 +31,8 @@
},
"exports": {
".": {
"types": "./dist/@types/astro.d.ts",
"default": "./astro.js"
"types": "./index.d.ts",
"default": "./dist/core/index.js"
},
"./env": "./env.d.ts",
"./types": "./types.d.ts",
@ -90,6 +90,7 @@
"tsconfigs",
"dist",
"astro.js",
"index.d.ts",
"config.d.ts",
"config.mjs",
"zod.d.ts",

View file

@ -143,7 +143,7 @@ export interface CLIFlags {
*/
export interface AstroGlobal<
Props extends Record<string, any> = Record<string, any>,
Self = AstroComponentFactory
Self = AstroComponentFactory,
> extends AstroGlobalPartial,
AstroSharedContext<Props> {
/**
@ -1404,13 +1404,39 @@ export interface AstroConfig extends AstroConfigType {
// TypeScript still confirms zod validation matches this type.
integrations: AstroIntegration[];
}
/**
* An inline Astro config that takes highest priority when merging with the user config,
* and includes inline-specific options to configure how Astro runs.
*/
export interface AstroInlineConfig extends AstroUserConfig, AstroInlineOnlyConfig {}
export interface AstroInlineOnlyConfig {
/**
* A custom path to the Astro config file. If relative, it'll resolve based on the current working directory.
* Set to false to disable loading any config files.
*
* If this value is undefined or unset, Astro will search for an `astro.config.(js,mjs,ts)` file relative to
* the `root` and load the config file if found.
*
* The inline config passed in this object will take highest priority when merging with the loaded user config.
*/
configFile?: string | false;
/**
* The mode used when building your site to generate either "development" or "production" code.
*/
mode?: RuntimeMode;
/**
* The logging level to filter messages logged by Astro.
* - "debug": Log everything, including noisy debugging diagnostics.
* - "info": Log informational messages, warnings, and errors.
* - "warn": Log warnings and errors.
* - "error": Log errors only.
* - "silent": No logging.
*
* @default "info"
*/
logLevel?: LoggerLevel;
/**
* @internal for testing only
* @internal for testing only, use `logLevel` instead.
*/
logging?: LogOptions;
}

View file

@ -25,7 +25,5 @@ export async function build({ flags }: BuildOptions) {
const inlineConfig = flagsToAstroInlineConfig(flags);
await _build(inlineConfig, {
teardownCompiler: true,
});
await _build(inlineConfig);
}

View file

@ -27,7 +27,7 @@ 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 { sync } = await import('../../core/sync/index.js');
const { default: sync } = await import('../../core/sync/index.js');
const inlineConfig = flagsToAstroInlineConfig(flags);
const exitCode = await sync(inlineConfig);
if (exitCode !== 0) {

View file

@ -1,6 +1,6 @@
import type yargs from 'yargs-parser';
import { printHelp } from '../../core/messages.js';
import { sync as _sync } from '../../core/sync/index.js';
import _sync from '../../core/sync/index.js';
import { flagsToAstroInlineConfig } from '../flags.js';
interface SyncOptions {

View file

@ -1,6 +1,8 @@
# `core/`
Code that executes within the top-level Node context. Contains the main Astro logic for the `build` and `dev` commands, and also manages the Vite server and SSR.
Code that executes within the top-level Node context. Contains the main Astro logic for the `build`, `dev`, `preview`, and `sync` commands, and also manages the Vite server and SSR.
The `core/index.ts` file is the main entry point for the `astro` package.
[See CONTRIBUTING.md](../../../../CONTRIBUTING.md) for a code overview.

View file

@ -37,14 +37,22 @@ export interface BuildOptions {
/**
* Teardown the compiler WASM instance after build. This can improve performance when
* building once, but may cause a performance hit if building multiple times in a row.
*
* @internal only used for testing
* @default true
*/
teardownCompiler?: boolean;
}
/** `astro build` */
/**
* Builds your site for deployment. By default, this will generate static files and place them in a dist/ directory.
* If SSR is enabled, this will generate the necessary server files to serve your site.
*
* @experimental The JavaScript API is experimental
*/
export default async function build(
inlineConfig: AstroInlineConfig,
options: BuildOptions
options?: BuildOptions
): Promise<void> {
applyPolyfill();
const logging = createNodeLogging(inlineConfig);
@ -82,7 +90,7 @@ class AstroBuilder {
}
this.settings = settings;
this.logging = options.logging;
this.teardownCompiler = options.teardownCompiler ?? false;
this.teardownCompiler = options.teardownCompiler ?? true;
this.routeCache = new RouteCache(this.logging);
this.origin = settings.config.site
? new URL(settings.config.site).origin

View file

@ -18,7 +18,12 @@ export interface DevServer {
stop(): Promise<void>;
}
/** `astro dev` */
/**
* Runs Astros development server. This is a local HTTP server that doesnt bundle assets.
* It uses Hot Module Replacement (HMR) to update your browser as you save changes in your editor.
*
* @experimental The JavaScript API is experimental
*/
export default async function dev(inlineConfig: AstroInlineConfig): Promise<DevServer> {
const devStart = performance.now();
await telemetry.record([]);

View file

@ -0,0 +1,26 @@
// This is the main entrypoint when importing the `astro` package.
import type { AstroInlineConfig } from '../@types/astro.js';
import { default as _build } from './build/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';
/**
* Builds your site for deployment. By default, this will generate static files and place them in a dist/ directory.
* If SSR is enabled, this will generate the necessary server files to serve your site.
*
* @experimental The JavaScript API is experimental
*/
// Wrap `_build` to prevent exposing the second internal options parameter
export const build = (inlineConfig: AstroInlineConfig) => _build(inlineConfig);
/**
* 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
*/
// Wrap `_sync` to prevent exposing the second internal options parameter
export const sync = (inlineConfig: AstroInlineConfig) => _sync(inlineConfig);

View file

@ -10,10 +10,13 @@ import { createSettings } from '../config/settings.js';
import createStaticPreviewServer from './static-preview-server.js';
import { getResolvedHostForHttpServer } from './util.js';
/** The primary dev action */
export default async function preview(
inlineConfig: AstroInlineConfig
): Promise<PreviewServer | undefined> {
/**
* Starts a local server to serve your static dist/ directory. This command is useful for previewing
* your build locally, before deploying it. It is not designed to be run in production.
*
* @experimental The JavaScript API is experimental
*/
export default async function preview(inlineConfig: AstroInlineConfig): Promise<PreviewServer> {
const logging = createNodeLogging(inlineConfig);
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'preview');
telemetry.record(eventCliSession('preview', userConfig));

View file

@ -22,8 +22,7 @@ export type ProcessExit = 0 | 1;
export type SyncOptions = {
/**
* Only used for testing
* @internal
* @internal only used for testing
*/
fs?: typeof fsMod;
};
@ -32,7 +31,13 @@ export type SyncInternalOptions = SyncOptions & {
logging: LogOptions;
};
export async function sync(
/**
* 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> {
@ -48,7 +53,7 @@ export async function sync(
command: 'build',
});
return await syncInternal(settings, { logging, fs: options?.fs });
return await syncInternal(settings, { ...options, logging });
}
/**

View file

@ -6,15 +6,14 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
import stripAnsi from 'strip-ansi';
import { check } from '../dist/cli/check/index.js';
import { dev, preview } from '../dist/core/index.js';
import build from '../dist/core/build/index.js';
import sync from '../dist/core/sync/index.js';
import { RESOLVED_SPLIT_MODULE_ID } from '../dist/core/build/plugins/plugin-ssr.js';
import { getVirtualModulePageNameFromPath } from '../dist/core/build/plugins/util.js';
import { makeSplitEntryPointFileName } from '../dist/core/build/static-build.js';
import { mergeConfig, resolveConfig } from '../dist/core/config/index.js';
import dev from '../dist/core/dev/index.js';
import { nodeLogDestination } from '../dist/core/logger/node.js';
import preview from '../dist/core/preview/index.js';
import { sync } from '../dist/core/sync/index.js';
// Disable telemetry when running tests
process.env.ASTRO_TELEMETRY_DISABLED = true;
@ -148,7 +147,7 @@ export async function loadFixture(inlineConfig) {
return {
build: async (extraInlineConfig = {}) => {
process.env.NODE_ENV = 'production';
return build(mergeConfig(inlineConfig, extraInlineConfig));
return build(mergeConfig(inlineConfig, extraInlineConfig), { teardownCompiler: false });
},
sync: async (extraInlineConfig = {}, opts) => {
return sync(mergeConfig(inlineConfig, extraInlineConfig), opts);

View file

@ -1,6 +1,6 @@
import { expect } from 'chai';
import { fileURLToPath } from 'node:url';
import { sync as _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);

View file

@ -1,6 +1,6 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src", "index.d.ts"],
"include": ["src"],
"compilerOptions": {
"allowJs": true,
"declarationDir": "./dist",