Skip to content

Commit

Permalink
Add the output option (#4015)
Browse files Browse the repository at this point in the history
* Start of work on astroConfig.mode === 'server'

* Add tests and more

* adapter -> deploy in some places

* Add fallback for `adapter` config

* Update more tests

* Update image tests

* Fix clientAddress test

* Updates based on PR review

* Add a changeset

* Update integrations tests + readme

* Oops

* Remove old option

* Rename `mode` to `output`

* Update Node adapter test

* Update test

* fred pass

* fred pass

* fred pass

* fix test

Co-authored-by: Fred K. Schott <fkschott@gmail.com>
  • Loading branch information
matthewp and FredKSchott authored Jul 25, 2022
1 parent 8859655 commit 6fd161d
Show file tree
Hide file tree
Showing 67 changed files with 365 additions and 251 deletions.
33 changes: 33 additions & 0 deletions .changeset/famous-coins-destroy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
'astro': minor
'@astrojs/cloudflare': minor
'@astrojs/deno': minor
'@astrojs/image': minor
'@astrojs/netlify': minor
'@astrojs/node': minor
'@astrojs/sitemap': minor
'@astrojs/vercel': minor
---

New `output` configuration option

This change introduces a new "output target" configuration option (`output`). Setting the output target lets you decide the format of your final build, either:

* `"static"` (default): A static site. Your final build will be a collection of static assets (HTML, CSS, JS) that you can deploy to any static site host.
* `"server"`: A dynamic server application. Your final build will be an application that will run in a hosted server environment, generating HTML dynamically for different requests.

If `output` is omitted from your config, the default value `"static"` will be used.

When using the `"server"` output target, you must also include a runtime adapter via the `adapter` configuration. An adapter will *adapt* your final build to run on the deployed platform of your choice (Netlify, Vercel, Node.js, Deno, etc).

To migrate: No action is required for most users. If you currently define an `adapter`, you will need to also add `output: 'server'` to your config file to make it explicit that you are building a server. Here is an example of what that change would look like for someone deploying to Netlify:

```diff
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify/functions';

export default defineConfig({
adapter: netlify(),
+ output: 'server',
});
```
1 change: 1 addition & 0 deletions examples/ssr/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import node from '@astrojs/node';

// https://astro.build/config
export default defineConfig({
output: 'server',
adapter: node(),
integrations: [svelte()],
});
67 changes: 45 additions & 22 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ export interface BuildConfig {
client: URL;
server: URL;
serverEntry: string;
staticMode: boolean | undefined;
}

/**
Expand Down Expand Up @@ -424,6 +423,50 @@ export interface AstroUserConfig {
*/
trailingSlash?: 'always' | 'never' | 'ignore';

/**
* @docs
* @name adapter
* @typeraw {AstroIntegration}
* @see output
* @description
*
* Deploy to your favorite server, serverless, or edge host with build adapters. Import one of our first-party adapters for [Netlify](https://docs.astro.build/en/guides/deploy/netlify/#adapter-for-ssredge), [Vercel](https://docs.astro.build/en/guides/deploy/vercel/#adapter-for-ssr), and more to engage Astro SSR.
*
* [See our Server-side Rendering guide](https://docs.astro.build/en/guides/server-side-rendering/) for more on SSR, and [our deployment guides](https://docs.astro.build/en/guides/deploy/) for a complete list of hosts.
*
* ```js
* import netlify from '@astrojs/netlify/functions';
* {
* // Example: Build for Netlify serverless deployment
* adapter: netlify(),
* }
* ```
*/
adapter?: AstroIntegration;

/**
* @docs
* @name output
* @type {('static' | 'server')}
* @default `'static'`
* @see adapter
* @description
*
* Specifies the output target for builds.
*
* - 'static' - Building a static site to be deploy to any static host.
* - 'server' - Building an app to be deployed to a host supporting SSR (server-side rendering).
*
* ```js
* import { defineConfig } from 'astro/config';
*
* export default defineConfig({
* output: 'static'
* })
* ```
*/
output?: 'static' | 'server';

/**
* @docs
* @kind heading
Expand Down Expand Up @@ -606,26 +649,6 @@ export interface AstroUserConfig {
rehypePlugins?: RehypePlugins;
};

/**
* @docs
* @kind heading
* @name Adapter
* @description
*
* Deploy to your favorite server, serverless, or edge host with build adapters. Import one of our first-party adapters for [Netlify](https://docs.astro.build/en/guides/deploy/netlify/#adapter-for-ssredge), [Vercel](https://docs.astro.build/en/guides/deploy/vercel/#adapter-for-ssr), and more to engage Astro SSR.
*
* [See our Server-side Rendering guide](https://docs.astro.build/en/guides/server-side-rendering/) for more on SSR, and [our deployment guides](https://docs.astro.build/en/guides/deploy/) for a complete list of hosts.
*
* ```js
* import netlify from '@astrojs/netlify/functions';
* {
* // Example: Build for Netlify serverless deployment
* adapter: netlify(),
* }
* ```
*/
adapter?: AstroIntegration;

/**
* @docs
* @kind heading
Expand Down Expand Up @@ -747,7 +770,7 @@ export interface AstroConfig extends z.output<typeof AstroConfigSchema> {
// This is a more detailed type than zod validation gives us.
// TypeScript still confirms zod validation matches this type.
integrations: AstroIntegration[];
adapter?: AstroIntegration;

// Private:
// We have a need to pass context based on configured state,
// that is different from the user-exposed configuration.
Expand Down
23 changes: 0 additions & 23 deletions packages/astro/src/adapter-ssg/index.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/astro/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
}
}

let { astroConfig, userConfig, userConfigPath } = await openConfig({ cwd: root, flags, cmd });
let { astroConfig, userConfig, userConfigPath } = await openConfig({ cwd: root, flags, cmd, logging });
telemetry.record(event.eventCliSession(cmd, userConfig, flags));

// Common CLI Commands:
Expand All @@ -154,7 +154,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
watcher.on('add', async function restartServerOnNewConfigFile(addedFile: string) {
// if there was not a config before, attempt to resolve
if (!userConfigPath && addedFile.includes('astro.config')) {
const addedConfig = await openConfig({ cwd: root, flags, cmd });
const addedConfig = await openConfig({ cwd: root, flags, cmd, logging });
if (addedConfig.userConfigPath) {
info(logging, 'astro', 'Astro config detected. Restarting server...');
astroConfig = addedConfig.astroConfig;
Expand Down
14 changes: 9 additions & 5 deletions packages/astro/src/core/add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,21 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
['--yes', 'Accept all prompts.'],
['--help', 'Show this help message.'],
],
'Example: Add a UI Framework': [
'Recommended: UI Frameworks': [
['react', 'astro add react'],
['preact', 'astro add preact'],
['vue', 'astro add vue'],
['svelte', 'astro add svelte'],
['solid-js', 'astro add solid-js'],
['lit', 'astro add lit'],
],
'Example: Add an Integration': [
'Recommended: Hosting': [
['netlify', 'astro add netlify'],
['vercel', 'astro add vercel'],
['cloudflare', 'astro add cloudflare'],
['deno', 'astro add deno'],
],
'Recommended: Integrations': [
['tailwind', 'astro add tailwind'],
['partytown', 'astro add partytown'],
['sitemap', 'astro add sitemap'],
Expand All @@ -85,9 +91,7 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
['deno', 'astro add deno'],
],
},
description: `Check out the full integration catalog: ${cyan(
'https://astro.build/integrations'
)}`,
description: `For more integrations, check out: ${cyan('https://astro.build/integrations')}`,
});
return;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/astro/src/core/build/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { debug, info } from '../logger/core.js';
import { render } from '../render/core.js';
import { createLinkStylesheetElementSet, createModuleScriptsSet } from '../render/ssr-element.js';
import { createRequest } from '../request.js';
import { getOutputFilename, isBuildingToSSR } from '../util.js';
import { getOutputFilename } from '../util.js';
import { getOutFile, getOutFolder } from './common.js';
import { eachPageData, getPageDataByComponent } from './internal.js';
import type { PageBuildData, SingleFileBuiltModule, StaticBuildOptions } from './types';
Expand Down Expand Up @@ -97,7 +97,7 @@ export async function generatePages(
const timer = performance.now();
info(opts.logging, null, `\n${bgGreen(black(' generating static routes '))}`);

const ssr = isBuildingToSSR(opts.astroConfig);
const ssr = opts.astroConfig.output === 'server';
const serverEntry = opts.buildConfig.serverEntry;
const outFolder = ssr ? opts.buildConfig.server : opts.astroConfig.outDir;
const ssrEntryURL = new URL('./' + serverEntry + `?time=${Date.now()}`, outFolder);
Expand Down Expand Up @@ -207,7 +207,7 @@ async function generatePath(
}
}

const ssr = isBuildingToSSR(opts.astroConfig);
const ssr = opts.astroConfig.output === 'server';
const url = new URL(opts.astroConfig.base + removeLeadingForwardSlash(pathname), origin);
const options: RenderOptions = {
adapterName: undefined,
Expand Down
24 changes: 16 additions & 8 deletions packages/astro/src/core/build/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import type { AstroTelemetry } from '@astrojs/telemetry';
import type { AstroConfig, BuildConfig, ManifestData, RuntimeMode } from '../../@types/astro';
import type {
AstroAdapter,
AstroConfig,
BuildConfig,
ManifestData,
RuntimeMode,
} from '../../@types/astro';
import type { LogOptions } from '../logger/core';

import fs from 'fs';
Expand All @@ -18,7 +24,7 @@ import { debug, info, levels, timerMessage } from '../logger/core.js';
import { apply as applyPolyfill } from '../polyfill.js';
import { RouteCache } from '../render/route-cache.js';
import { createRouteManifest } from '../routing/index.js';
import { createSafeError, isBuildingToSSR } from '../util.js';
import { createSafeError } from '../util.js';
import { collectPagesData } from './page-data.js';
import { staticBuild } from './static-build.js';
import { getTimeStat } from './util.js';
Expand Down Expand Up @@ -98,11 +104,14 @@ class AstroBuilder {
client: new URL('./client/', this.config.outDir),
server: new URL('./server/', this.config.outDir),
serverEntry: 'entry.mjs',
staticMode: undefined,
};
await runHookBuildStart({ config: this.config, buildConfig });

info(this.logging, 'build', 'Collecting build information...');
info(this.logging, 'build', `output target: ${colors.green(this.config.output)}`);
if (this.config._ctx.adapter) {
info(this.logging, 'build', `deploy adapter: ${colors.green(this.config._ctx.adapter.name)}`);
}
info(this.logging, 'build', 'Collecting build info...');
this.timer.loadStart = performance.now();
const { assets, allPages } = await collectPagesData({
astroConfig: this.config,
Expand All @@ -111,7 +120,7 @@ class AstroBuilder {
origin,
routeCache: this.routeCache,
viteServer,
ssr: isBuildingToSSR(this.config),
ssr: this.config.output === 'server',
});

debug('build', timerMessage('All pages loaded', this.timer.loadStart));
Expand Down Expand Up @@ -168,12 +177,11 @@ class AstroBuilder {
});

if (this.logging.level && levels[this.logging.level] <= levels['info']) {
const buildMode = isBuildingToSSR(this.config) ? 'ssr' : 'static';
await this.printStats({
logging: this.logging,
timeStart: this.timer.init,
pageCount: pageNames.length,
buildMode,
buildMode: this.config.output,
});
}
}
Expand All @@ -198,7 +206,7 @@ class AstroBuilder {
logging: LogOptions;
timeStart: number;
pageCount: number;
buildMode: 'static' | 'ssr';
buildMode: 'static' | 'server';
}) {
const total = getTimeStat(timeStart, performance.now());

Expand Down
6 changes: 1 addition & 5 deletions packages/astro/src/core/build/page-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { debug } from '../logger/core.js';
import { removeTrailingForwardSlash } from '../path.js';
import { callGetStaticPaths, RouteCache, RouteCacheEntry } from '../render/route-cache.js';
import { matchRoute } from '../routing/match.js';
import { isBuildingToSSR } from '../util.js';

export interface CollectPagesDataOptions {
astroConfig: AstroConfig;
Expand All @@ -36,9 +35,6 @@ export async function collectPagesData(
const assets: Record<string, string> = {};
const allPages: AllPagesData = {};
const builtPaths = new Set<string>();

const buildMode = isBuildingToSSR(astroConfig) ? 'ssr' : 'static';

const dataCollectionLogTimeout = setInterval(() => {
info(opts.logging, 'build', 'The data collection step may take longer for larger projects...');
clearInterval(dataCollectionLogTimeout);
Expand Down Expand Up @@ -72,7 +68,7 @@ export async function collectPagesData(
};

clearInterval(routeCollectionLogTimeout);
if (buildMode === 'static') {
if (astroConfig.output === 'static') {
const html = `${route.pathname}`.replace(/\/?$/, '/index.html');
debug(
'build',
Expand Down
Loading

0 comments on commit 6fd161d

Please sign in to comment.