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

Export experimental JS API #7979

Merged
merged 12 commits into from
Aug 18, 2023
Merged
35 changes: 35 additions & 0 deletions .changeset/many-pears-explode.md
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions packages/astro/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type * from './dist/@types/astro.js';
export * from './dist/core/index.js';
7 changes: 4 additions & 3 deletions packages/astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand All @@ -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",
Expand Down Expand Up @@ -90,6 +90,7 @@
"tsconfigs",
"dist",
"astro.js",
"index.d.ts",
"config.d.ts",
"config.mjs",
"zod.d.ts",
Expand Down
30 changes: 28 additions & 2 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
/**
Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 1 addition & 3 deletions packages/astro/src/cli/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,5 @@ export async function build({ flags }: BuildOptions) {

const inlineConfig = flagsToAstroInlineConfig(flags);

await _build(inlineConfig, {
teardownCompiler: true,
});
await _build(inlineConfig);
}
2 changes: 1 addition & 1 deletion packages/astro/src/cli/check/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/cli/sync/index.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
4 changes: 3 additions & 1 deletion packages/astro/src/core/README.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
14 changes: 11 additions & 3 deletions packages/astro/src/core/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
bluwy marked this conversation as resolved.
Show resolved Hide resolved
inlineConfig: AstroInlineConfig,
options: BuildOptions
options?: BuildOptions
): Promise<void> {
applyPolyfill();
const logging = createNodeLogging(inlineConfig);
Expand Down Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion packages/astro/src/core/dev/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ export interface DevServer {
stop(): Promise<void>;
}

/** `astro dev` */
/**
* Runs Astro’s development server. This is a local HTTP server that doesn’t 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([]);
Expand Down
26 changes: 26 additions & 0 deletions packages/astro/src/core/index.ts
Original file line number Diff line number Diff line change
@@ -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);
11 changes: 7 additions & 4 deletions packages/astro/src/core/preview/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
13 changes: 9 additions & 4 deletions packages/astro/src/core/sync/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand All @@ -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> {
Expand All @@ -48,7 +53,7 @@ export async function sync(
command: 'build',
});

return await syncInternal(settings, { logging, fs: options?.fs });
return await syncInternal(settings, { ...options, logging });
}

/**
Expand Down
7 changes: 3 additions & 4 deletions packages/astro/test/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src", "index.d.ts"],
"include": ["src"],
"compilerOptions": {
"allowJs": true,
"declarationDir": "./dist",
Expand Down
Loading