Add the output
option (#4015)
* 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>
This commit is contained in:
parent
8859655f15
commit
6fd161d769
67 changed files with 365 additions and 251 deletions
33
.changeset/famous-coins-destroy.md
Normal file
33
.changeset/famous-coins-destroy.md
Normal file
|
@ -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',
|
||||||
|
});
|
||||||
|
```
|
|
@ -4,6 +4,7 @@ import node from '@astrojs/node';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
adapter: node(),
|
adapter: node(),
|
||||||
integrations: [svelte()],
|
integrations: [svelte()],
|
||||||
});
|
});
|
||||||
|
|
|
@ -84,7 +84,6 @@ export interface BuildConfig {
|
||||||
client: URL;
|
client: URL;
|
||||||
server: URL;
|
server: URL;
|
||||||
serverEntry: string;
|
serverEntry: string;
|
||||||
staticMode: boolean | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -424,6 +423,50 @@ export interface AstroUserConfig {
|
||||||
*/
|
*/
|
||||||
trailingSlash?: 'always' | 'never' | 'ignore';
|
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
|
* @docs
|
||||||
* @kind heading
|
* @kind heading
|
||||||
|
@ -606,26 +649,6 @@ export interface AstroUserConfig {
|
||||||
rehypePlugins?: RehypePlugins;
|
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
|
* @docs
|
||||||
* @kind heading
|
* @kind heading
|
||||||
|
@ -747,7 +770,7 @@ export interface AstroConfig extends z.output<typeof AstroConfigSchema> {
|
||||||
// This is a more detailed type than zod validation gives us.
|
// This is a more detailed type than zod validation gives us.
|
||||||
// TypeScript still confirms zod validation matches this type.
|
// TypeScript still confirms zod validation matches this type.
|
||||||
integrations: AstroIntegration[];
|
integrations: AstroIntegration[];
|
||||||
adapter?: AstroIntegration;
|
|
||||||
// Private:
|
// Private:
|
||||||
// We have a need to pass context based on configured state,
|
// We have a need to pass context based on configured state,
|
||||||
// that is different from the user-exposed configuration.
|
// that is different from the user-exposed configuration.
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import type { AstroAdapter, AstroIntegration } from '../@types/astro';
|
|
||||||
|
|
||||||
export function getAdapter(): AstroAdapter {
|
|
||||||
return {
|
|
||||||
name: '@astrojs/ssg',
|
|
||||||
// This one has no server entrypoint and is mostly just an integration
|
|
||||||
//serverEntrypoint: '@astrojs/ssg/server.js',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function createIntegration(): AstroIntegration {
|
|
||||||
return {
|
|
||||||
name: '@astrojs/ssg',
|
|
||||||
hooks: {
|
|
||||||
'astro:config:done': ({ setAdapter }) => {
|
|
||||||
setAdapter(getAdapter());
|
|
||||||
},
|
|
||||||
'astro:build:start': ({ buildConfig }) => {
|
|
||||||
buildConfig.staticMode = true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -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));
|
telemetry.record(event.eventCliSession(cmd, userConfig, flags));
|
||||||
|
|
||||||
// Common CLI Commands:
|
// Common CLI Commands:
|
||||||
|
@ -154,7 +154,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
|
||||||
watcher.on('add', async function restartServerOnNewConfigFile(addedFile: string) {
|
watcher.on('add', async function restartServerOnNewConfigFile(addedFile: string) {
|
||||||
// if there was not a config before, attempt to resolve
|
// if there was not a config before, attempt to resolve
|
||||||
if (!userConfigPath && addedFile.includes('astro.config')) {
|
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) {
|
if (addedConfig.userConfigPath) {
|
||||||
info(logging, 'astro', 'Astro config detected. Restarting server...');
|
info(logging, 'astro', 'Astro config detected. Restarting server...');
|
||||||
astroConfig = addedConfig.astroConfig;
|
astroConfig = addedConfig.astroConfig;
|
||||||
|
|
|
@ -66,7 +66,7 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
|
||||||
['--yes', 'Accept all prompts.'],
|
['--yes', 'Accept all prompts.'],
|
||||||
['--help', 'Show this help message.'],
|
['--help', 'Show this help message.'],
|
||||||
],
|
],
|
||||||
'Example: Add a UI Framework': [
|
'Recommended: UI Frameworks': [
|
||||||
['react', 'astro add react'],
|
['react', 'astro add react'],
|
||||||
['preact', 'astro add preact'],
|
['preact', 'astro add preact'],
|
||||||
['vue', 'astro add vue'],
|
['vue', 'astro add vue'],
|
||||||
|
@ -74,7 +74,13 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
|
||||||
['solid-js', 'astro add solid-js'],
|
['solid-js', 'astro add solid-js'],
|
||||||
['lit', 'astro add lit'],
|
['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'],
|
['tailwind', 'astro add tailwind'],
|
||||||
['partytown', 'astro add partytown'],
|
['partytown', 'astro add partytown'],
|
||||||
['sitemap', 'astro add sitemap'],
|
['sitemap', 'astro add sitemap'],
|
||||||
|
@ -85,9 +91,7 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
|
||||||
['deno', 'astro add deno'],
|
['deno', 'astro add deno'],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
description: `Check out the full integration catalog: ${cyan(
|
description: `For more integrations, check out: ${cyan('https://astro.build/integrations')}`,
|
||||||
'https://astro.build/integrations'
|
|
||||||
)}`,
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { debug, info } from '../logger/core.js';
|
||||||
import { render } from '../render/core.js';
|
import { render } from '../render/core.js';
|
||||||
import { createLinkStylesheetElementSet, createModuleScriptsSet } from '../render/ssr-element.js';
|
import { createLinkStylesheetElementSet, createModuleScriptsSet } from '../render/ssr-element.js';
|
||||||
import { createRequest } from '../request.js';
|
import { createRequest } from '../request.js';
|
||||||
import { getOutputFilename, isBuildingToSSR } from '../util.js';
|
import { getOutputFilename } from '../util.js';
|
||||||
import { getOutFile, getOutFolder } from './common.js';
|
import { getOutFile, getOutFolder } from './common.js';
|
||||||
import { eachPageData, getPageDataByComponent } from './internal.js';
|
import { eachPageData, getPageDataByComponent } from './internal.js';
|
||||||
import type { PageBuildData, SingleFileBuiltModule, StaticBuildOptions } from './types';
|
import type { PageBuildData, SingleFileBuiltModule, StaticBuildOptions } from './types';
|
||||||
|
@ -97,7 +97,7 @@ export async function generatePages(
|
||||||
const timer = performance.now();
|
const timer = performance.now();
|
||||||
info(opts.logging, null, `\n${bgGreen(black(' generating static routes '))}`);
|
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 serverEntry = opts.buildConfig.serverEntry;
|
||||||
const outFolder = ssr ? opts.buildConfig.server : opts.astroConfig.outDir;
|
const outFolder = ssr ? opts.buildConfig.server : opts.astroConfig.outDir;
|
||||||
const ssrEntryURL = new URL('./' + serverEntry + `?time=${Date.now()}`, outFolder);
|
const ssrEntryURL = new URL('./' + serverEntry + `?time=${Date.now()}`, outFolder);
|
||||||
|
@ -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 url = new URL(opts.astroConfig.base + removeLeadingForwardSlash(pathname), origin);
|
||||||
const options: RenderOptions = {
|
const options: RenderOptions = {
|
||||||
adapterName: undefined,
|
adapterName: undefined,
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
import type { AstroTelemetry } from '@astrojs/telemetry';
|
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 type { LogOptions } from '../logger/core';
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
@ -18,7 +24,7 @@ import { debug, info, levels, timerMessage } from '../logger/core.js';
|
||||||
import { apply as applyPolyfill } from '../polyfill.js';
|
import { apply as applyPolyfill } from '../polyfill.js';
|
||||||
import { RouteCache } from '../render/route-cache.js';
|
import { RouteCache } from '../render/route-cache.js';
|
||||||
import { createRouteManifest } from '../routing/index.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 { collectPagesData } from './page-data.js';
|
||||||
import { staticBuild } from './static-build.js';
|
import { staticBuild } from './static-build.js';
|
||||||
import { getTimeStat } from './util.js';
|
import { getTimeStat } from './util.js';
|
||||||
|
@ -98,11 +104,14 @@ class AstroBuilder {
|
||||||
client: new URL('./client/', this.config.outDir),
|
client: new URL('./client/', this.config.outDir),
|
||||||
server: new URL('./server/', this.config.outDir),
|
server: new URL('./server/', this.config.outDir),
|
||||||
serverEntry: 'entry.mjs',
|
serverEntry: 'entry.mjs',
|
||||||
staticMode: undefined,
|
|
||||||
};
|
};
|
||||||
await runHookBuildStart({ config: this.config, buildConfig });
|
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();
|
this.timer.loadStart = performance.now();
|
||||||
const { assets, allPages } = await collectPagesData({
|
const { assets, allPages } = await collectPagesData({
|
||||||
astroConfig: this.config,
|
astroConfig: this.config,
|
||||||
|
@ -111,7 +120,7 @@ class AstroBuilder {
|
||||||
origin,
|
origin,
|
||||||
routeCache: this.routeCache,
|
routeCache: this.routeCache,
|
||||||
viteServer,
|
viteServer,
|
||||||
ssr: isBuildingToSSR(this.config),
|
ssr: this.config.output === 'server',
|
||||||
});
|
});
|
||||||
|
|
||||||
debug('build', timerMessage('All pages loaded', this.timer.loadStart));
|
debug('build', timerMessage('All pages loaded', this.timer.loadStart));
|
||||||
|
@ -168,12 +177,11 @@ class AstroBuilder {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.logging.level && levels[this.logging.level] <= levels['info']) {
|
if (this.logging.level && levels[this.logging.level] <= levels['info']) {
|
||||||
const buildMode = isBuildingToSSR(this.config) ? 'ssr' : 'static';
|
|
||||||
await this.printStats({
|
await this.printStats({
|
||||||
logging: this.logging,
|
logging: this.logging,
|
||||||
timeStart: this.timer.init,
|
timeStart: this.timer.init,
|
||||||
pageCount: pageNames.length,
|
pageCount: pageNames.length,
|
||||||
buildMode,
|
buildMode: this.config.output,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,7 +206,7 @@ class AstroBuilder {
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
timeStart: number;
|
timeStart: number;
|
||||||
pageCount: number;
|
pageCount: number;
|
||||||
buildMode: 'static' | 'ssr';
|
buildMode: 'static' | 'server';
|
||||||
}) {
|
}) {
|
||||||
const total = getTimeStat(timeStart, performance.now());
|
const total = getTimeStat(timeStart, performance.now());
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { debug } from '../logger/core.js';
|
||||||
import { removeTrailingForwardSlash } from '../path.js';
|
import { removeTrailingForwardSlash } from '../path.js';
|
||||||
import { callGetStaticPaths, RouteCache, RouteCacheEntry } from '../render/route-cache.js';
|
import { callGetStaticPaths, RouteCache, RouteCacheEntry } from '../render/route-cache.js';
|
||||||
import { matchRoute } from '../routing/match.js';
|
import { matchRoute } from '../routing/match.js';
|
||||||
import { isBuildingToSSR } from '../util.js';
|
|
||||||
|
|
||||||
export interface CollectPagesDataOptions {
|
export interface CollectPagesDataOptions {
|
||||||
astroConfig: AstroConfig;
|
astroConfig: AstroConfig;
|
||||||
|
@ -36,9 +35,6 @@ export async function collectPagesData(
|
||||||
const assets: Record<string, string> = {};
|
const assets: Record<string, string> = {};
|
||||||
const allPages: AllPagesData = {};
|
const allPages: AllPagesData = {};
|
||||||
const builtPaths = new Set<string>();
|
const builtPaths = new Set<string>();
|
||||||
|
|
||||||
const buildMode = isBuildingToSSR(astroConfig) ? 'ssr' : 'static';
|
|
||||||
|
|
||||||
const dataCollectionLogTimeout = setInterval(() => {
|
const dataCollectionLogTimeout = setInterval(() => {
|
||||||
info(opts.logging, 'build', 'The data collection step may take longer for larger projects...');
|
info(opts.logging, 'build', 'The data collection step may take longer for larger projects...');
|
||||||
clearInterval(dataCollectionLogTimeout);
|
clearInterval(dataCollectionLogTimeout);
|
||||||
|
@ -72,7 +68,7 @@ export async function collectPagesData(
|
||||||
};
|
};
|
||||||
|
|
||||||
clearInterval(routeCollectionLogTimeout);
|
clearInterval(routeCollectionLogTimeout);
|
||||||
if (buildMode === 'static') {
|
if (astroConfig.output === 'static') {
|
||||||
const html = `${route.pathname}`.replace(/\/?$/, '/index.html');
|
const html = `${route.pathname}`.replace(/\/?$/, '/index.html');
|
||||||
debug(
|
debug(
|
||||||
'build',
|
'build',
|
||||||
|
|
|
@ -6,12 +6,11 @@ import { fileURLToPath } from 'url';
|
||||||
import * as vite from 'vite';
|
import * as vite from 'vite';
|
||||||
import { BuildInternals, createBuildInternals } from '../../core/build/internal.js';
|
import { BuildInternals, createBuildInternals } from '../../core/build/internal.js';
|
||||||
import { prependForwardSlash } from '../../core/path.js';
|
import { prependForwardSlash } from '../../core/path.js';
|
||||||
import { emptyDir, removeDir } from '../../core/util.js';
|
import { emptyDir, removeDir, isModeServerWithNoAdapter } from '../../core/util.js';
|
||||||
import { runHookBuildSetup } from '../../integrations/index.js';
|
import { runHookBuildSetup } from '../../integrations/index.js';
|
||||||
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
|
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
|
||||||
import type { ViteConfigWithSSR } from '../create-vite';
|
import type { ViteConfigWithSSR } from '../create-vite';
|
||||||
import { info } from '../logger/core.js';
|
import { info } from '../logger/core.js';
|
||||||
import { isBuildingToSSR } from '../util.js';
|
|
||||||
import { generatePages } from './generate.js';
|
import { generatePages } from './generate.js';
|
||||||
import { trackPageData } from './internal.js';
|
import { trackPageData } from './internal.js';
|
||||||
import type { PageBuildData, StaticBuildOptions } from './types';
|
import type { PageBuildData, StaticBuildOptions } from './types';
|
||||||
|
@ -25,6 +24,21 @@ import { injectManifest, vitePluginSSR } from './vite-plugin-ssr.js';
|
||||||
export async function staticBuild(opts: StaticBuildOptions) {
|
export async function staticBuild(opts: StaticBuildOptions) {
|
||||||
const { allPages, astroConfig } = opts;
|
const { allPages, astroConfig } = opts;
|
||||||
|
|
||||||
|
// Verify this app is buildable.
|
||||||
|
if(isModeServerWithNoAdapter(opts.astroConfig)) {
|
||||||
|
throw new Error(`Cannot use \`output: 'server'\` without an adapter.
|
||||||
|
Install and configure the appropriate server adapter for your final deployment.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
// astro.config.js
|
||||||
|
import netlify from '@astrojs/netlify';
|
||||||
|
export default {
|
||||||
|
output: 'server',
|
||||||
|
adapter: netlify(),
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
// The pages to be built for rendering purposes.
|
// The pages to be built for rendering purposes.
|
||||||
const pageInput = new Set<string>();
|
const pageInput = new Set<string>();
|
||||||
|
|
||||||
|
@ -60,9 +74,7 @@ export async function staticBuild(opts: StaticBuildOptions) {
|
||||||
info(
|
info(
|
||||||
opts.logging,
|
opts.logging,
|
||||||
'build',
|
'build',
|
||||||
isBuildingToSSR(astroConfig)
|
`Building ${astroConfig.output} entrypoints...`
|
||||||
? 'Building SSR entrypoints...'
|
|
||||||
: 'Building entrypoints for prerendering...'
|
|
||||||
);
|
);
|
||||||
const ssrResult = (await ssrBuild(opts, internals, pageInput)) as RollupOutput;
|
const ssrResult = (await ssrBuild(opts, internals, pageInput)) as RollupOutput;
|
||||||
info(opts.logging, 'build', dim(`Completed in ${getTimeStat(timer.ssr, performance.now())}.`));
|
info(opts.logging, 'build', dim(`Completed in ${getTimeStat(timer.ssr, performance.now())}.`));
|
||||||
|
@ -83,7 +95,7 @@ export async function staticBuild(opts: StaticBuildOptions) {
|
||||||
await clientBuild(opts, internals, clientInput);
|
await clientBuild(opts, internals, clientInput);
|
||||||
|
|
||||||
timer.generate = performance.now();
|
timer.generate = performance.now();
|
||||||
if (opts.buildConfig.staticMode) {
|
if (astroConfig.output === 'static') {
|
||||||
try {
|
try {
|
||||||
await generatePages(ssrResult, opts, internals, facadeIdToPageDataMap);
|
await generatePages(ssrResult, opts, internals, facadeIdToPageDataMap);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -100,7 +112,7 @@ export async function staticBuild(opts: StaticBuildOptions) {
|
||||||
|
|
||||||
async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set<string>) {
|
async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set<string>) {
|
||||||
const { astroConfig, viteConfig } = opts;
|
const { astroConfig, viteConfig } = opts;
|
||||||
const ssr = isBuildingToSSR(astroConfig);
|
const ssr = astroConfig.output === 'server';
|
||||||
const out = ssr ? opts.buildConfig.server : astroConfig.outDir;
|
const out = ssr ? opts.buildConfig.server : astroConfig.outDir;
|
||||||
|
|
||||||
const viteBuildConfig: ViteConfigWithSSR = {
|
const viteBuildConfig: ViteConfigWithSSR = {
|
||||||
|
@ -144,7 +156,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
|
||||||
}),
|
}),
|
||||||
...(viteConfig.plugins || []),
|
...(viteConfig.plugins || []),
|
||||||
// SSR needs to be last
|
// SSR needs to be last
|
||||||
isBuildingToSSR(opts.astroConfig) && vitePluginSSR(internals, opts.astroConfig._ctx.adapter!),
|
opts.astroConfig.output === 'server' && vitePluginSSR(internals, opts.astroConfig._ctx.adapter!),
|
||||||
vitePluginAnalyzer(opts.astroConfig, internals),
|
vitePluginAnalyzer(opts.astroConfig, internals),
|
||||||
],
|
],
|
||||||
publicDir: ssr ? false : viteConfig.publicDir,
|
publicDir: ssr ? false : viteConfig.publicDir,
|
||||||
|
@ -174,7 +186,7 @@ async function clientBuild(
|
||||||
) {
|
) {
|
||||||
const { astroConfig, viteConfig } = opts;
|
const { astroConfig, viteConfig } = opts;
|
||||||
const timer = performance.now();
|
const timer = performance.now();
|
||||||
const ssr = isBuildingToSSR(astroConfig);
|
const ssr = astroConfig.output === 'server';
|
||||||
const out = ssr ? opts.buildConfig.client : astroConfig.outDir;
|
const out = ssr ? opts.buildConfig.client : astroConfig.outDir;
|
||||||
|
|
||||||
// Nothing to do if there is no client-side JS.
|
// Nothing to do if there is no client-side JS.
|
||||||
|
@ -275,7 +287,7 @@ async function copyFiles(fromFolder: URL, toFolder: URL) {
|
||||||
|
|
||||||
async function ssrMoveAssets(opts: StaticBuildOptions) {
|
async function ssrMoveAssets(opts: StaticBuildOptions) {
|
||||||
info(opts.logging, 'build', 'Rearranging server assets...');
|
info(opts.logging, 'build', 'Rearranging server assets...');
|
||||||
const serverRoot = opts.buildConfig.staticMode
|
const serverRoot = opts.astroConfig.output === 'static'
|
||||||
? opts.buildConfig.client
|
? opts.buildConfig.client
|
||||||
: opts.buildConfig.server;
|
: opts.buildConfig.server;
|
||||||
const clientRoot = opts.buildConfig.client;
|
const clientRoot = opts.buildConfig.client;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { Plugin as VitePlugin } from 'vite';
|
import type { Plugin as VitePlugin } from 'vite';
|
||||||
import { pagesVirtualModuleId, resolvedPagesVirtualModuleId } from '../app/index.js';
|
import { pagesVirtualModuleId, resolvedPagesVirtualModuleId } from '../app/index.js';
|
||||||
import { isBuildingToSSR } from '../util.js';
|
|
||||||
import { addRollupInput } from './add-rollup-input.js';
|
import { addRollupInput } from './add-rollup-input.js';
|
||||||
import type { BuildInternals } from './internal.js';
|
import type { BuildInternals } from './internal.js';
|
||||||
import { eachPageData } from './internal.js';
|
import { eachPageData } from './internal.js';
|
||||||
|
@ -11,7 +10,7 @@ export function vitePluginPages(opts: StaticBuildOptions, internals: BuildIntern
|
||||||
name: '@astro/plugin-build-pages',
|
name: '@astro/plugin-build-pages',
|
||||||
|
|
||||||
options(options) {
|
options(options) {
|
||||||
if (!isBuildingToSSR(opts.astroConfig)) {
|
if (opts.astroConfig.output === 'static') {
|
||||||
return addRollupInput(options, [pagesVirtualModuleId]);
|
return addRollupInput(options, [pagesVirtualModuleId]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { mergeConfig as mergeViteConfig } from 'vite';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { appendForwardSlash, prependForwardSlash, trimSlashes } from './path.js';
|
import { appendForwardSlash, prependForwardSlash, trimSlashes } from './path.js';
|
||||||
import { arraify, isObject } from './util.js';
|
import { arraify, isObject } from './util.js';
|
||||||
|
import { LogOptions, warn } from './logger/core.js';
|
||||||
|
|
||||||
load.use([loadTypeScript]);
|
load.use([loadTypeScript]);
|
||||||
|
|
||||||
|
@ -92,7 +93,6 @@ export const LEGACY_ASTRO_CONFIG_KEYS = new Set([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const AstroConfigSchema = z.object({
|
export const AstroConfigSchema = z.object({
|
||||||
adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(),
|
|
||||||
root: z
|
root: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
|
@ -127,6 +127,19 @@ export const AstroConfigSchema = z.object({
|
||||||
.union([z.literal('always'), z.literal('never'), z.literal('ignore')])
|
.union([z.literal('always'), z.literal('never'), z.literal('ignore')])
|
||||||
.optional()
|
.optional()
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.trailingSlash),
|
.default(ASTRO_CONFIG_DEFAULTS.trailingSlash),
|
||||||
|
output: z
|
||||||
|
.union([z.literal('static'), z.literal('server')])
|
||||||
|
.optional()
|
||||||
|
.default('static'),
|
||||||
|
adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(),
|
||||||
|
integrations: z.preprocess(
|
||||||
|
// preprocess
|
||||||
|
(val) => (Array.isArray(val) ? val.flat(Infinity).filter(Boolean) : val),
|
||||||
|
// validate
|
||||||
|
z
|
||||||
|
.array(z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }))
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.integrations)
|
||||||
|
),
|
||||||
build: z
|
build: z
|
||||||
.object({
|
.object({
|
||||||
format: z
|
format: z
|
||||||
|
@ -153,14 +166,6 @@ export const AstroConfigSchema = z.object({
|
||||||
.optional()
|
.optional()
|
||||||
.default({})
|
.default({})
|
||||||
),
|
),
|
||||||
integrations: z.preprocess(
|
|
||||||
// preprocess
|
|
||||||
(val) => (Array.isArray(val) ? val.flat(Infinity).filter(Boolean) : val),
|
|
||||||
// validate
|
|
||||||
z
|
|
||||||
.array(z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }))
|
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.integrations)
|
|
||||||
),
|
|
||||||
style: z
|
style: z
|
||||||
.object({
|
.object({
|
||||||
postcss: z
|
postcss: z
|
||||||
|
@ -227,7 +232,8 @@ export const AstroConfigSchema = z.object({
|
||||||
export async function validateConfig(
|
export async function validateConfig(
|
||||||
userConfig: any,
|
userConfig: any,
|
||||||
root: string,
|
root: string,
|
||||||
cmd: string
|
cmd: string,
|
||||||
|
logging: LogOptions
|
||||||
): Promise<AstroConfig> {
|
): Promise<AstroConfig> {
|
||||||
const fileProtocolRoot = pathToFileURL(root + path.sep);
|
const fileProtocolRoot = pathToFileURL(root + path.sep);
|
||||||
// Manual deprecation checks
|
// Manual deprecation checks
|
||||||
|
@ -388,6 +394,7 @@ interface LoadConfigOptions {
|
||||||
flags?: Flags;
|
flags?: Flags;
|
||||||
cmd: string;
|
cmd: string;
|
||||||
validate?: boolean;
|
validate?: boolean;
|
||||||
|
logging: LogOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -459,7 +466,13 @@ export async function openConfig(configOptions: LoadConfigOptions): Promise<Open
|
||||||
userConfig = config.value;
|
userConfig = config.value;
|
||||||
userConfigPath = config.filePath;
|
userConfigPath = config.filePath;
|
||||||
}
|
}
|
||||||
const astroConfig = await resolveConfig(userConfig, root, flags, configOptions.cmd);
|
const astroConfig = await resolveConfig(
|
||||||
|
userConfig,
|
||||||
|
root,
|
||||||
|
flags,
|
||||||
|
configOptions.cmd,
|
||||||
|
configOptions.logging
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
astroConfig,
|
astroConfig,
|
||||||
|
@ -505,7 +518,7 @@ export async function loadConfig(configOptions: LoadConfigOptions): Promise<Astr
|
||||||
if (config) {
|
if (config) {
|
||||||
userConfig = config.value;
|
userConfig = config.value;
|
||||||
}
|
}
|
||||||
return resolveConfig(userConfig, root, flags, configOptions.cmd);
|
return resolveConfig(userConfig, root, flags, configOptions.cmd, configOptions.logging);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Attempt to resolve an Astro configuration object. Normalize, validate, and return. */
|
/** Attempt to resolve an Astro configuration object. Normalize, validate, and return. */
|
||||||
|
@ -513,10 +526,11 @@ export async function resolveConfig(
|
||||||
userConfig: AstroUserConfig,
|
userConfig: AstroUserConfig,
|
||||||
root: string,
|
root: string,
|
||||||
flags: CLIFlags = {},
|
flags: CLIFlags = {},
|
||||||
cmd: string
|
cmd: string,
|
||||||
|
logging: LogOptions
|
||||||
): Promise<AstroConfig> {
|
): Promise<AstroConfig> {
|
||||||
const mergedConfig = mergeCLIFlags(userConfig, flags, cmd);
|
const mergedConfig = mergeCLIFlags(userConfig, flags, cmd);
|
||||||
const validatedConfig = await validateConfig(mergedConfig, root, cmd);
|
const validatedConfig = await validateConfig(mergedConfig, root, cmd, logging);
|
||||||
|
|
||||||
return validatedConfig;
|
return validatedConfig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import type { EndpointHandler } from '../../../@types/astro';
|
import type { EndpointHandler } from '../../../@types/astro';
|
||||||
import type { SSROptions } from '../../render/dev';
|
import type { SSROptions } from '../../render/dev';
|
||||||
import { preload } from '../../render/dev/index.js';
|
import { preload } from '../../render/dev/index.js';
|
||||||
import { isBuildingToSSR } from '../../util.js';
|
|
||||||
import { call as callEndpoint } from '../index.js';
|
import { call as callEndpoint } from '../index.js';
|
||||||
|
|
||||||
export async function call(ssrOpts: SSROptions) {
|
export async function call(ssrOpts: SSROptions) {
|
||||||
const [, mod] = await preload(ssrOpts);
|
const [, mod] = await preload(ssrOpts);
|
||||||
return await callEndpoint(mod as unknown as EndpointHandler, {
|
return await callEndpoint(mod as unknown as EndpointHandler, {
|
||||||
...ssrOpts,
|
...ssrOpts,
|
||||||
ssr: isBuildingToSSR(ssrOpts.astroConfig),
|
ssr: ssrOpts.astroConfig.output === 'server',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,6 @@ export const logger = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function enableVerboseLogging() {
|
export function enableVerboseLogging() {
|
||||||
//debugPackage.enable('*,-babel');
|
|
||||||
debug('cli', '--verbose flag enabled! Enabling: DEBUG="*,-babel"');
|
debug('cli', '--verbose flag enabled! Enabling: DEBUG="*,-babel"');
|
||||||
debug(
|
debug(
|
||||||
'cli',
|
'cli',
|
||||||
|
|
|
@ -11,7 +11,7 @@ import type {
|
||||||
} from '../../../@types/astro';
|
} from '../../../@types/astro';
|
||||||
import { prependForwardSlash } from '../../../core/path.js';
|
import { prependForwardSlash } from '../../../core/path.js';
|
||||||
import { LogOptions } from '../../logger/core.js';
|
import { LogOptions } from '../../logger/core.js';
|
||||||
import { isBuildingToSSR, isPage } from '../../util.js';
|
import { isPage } from '../../util.js';
|
||||||
import { render as coreRender } from '../core.js';
|
import { render as coreRender } from '../core.js';
|
||||||
import { RouteCache } from '../route-cache.js';
|
import { RouteCache } from '../route-cache.js';
|
||||||
import { collectMdMetadata } from '../util.js';
|
import { collectMdMetadata } from '../util.js';
|
||||||
|
@ -194,7 +194,7 @@ export async function render(
|
||||||
route,
|
route,
|
||||||
routeCache,
|
routeCache,
|
||||||
site: astroConfig.site ? new URL(astroConfig.base, astroConfig.site).toString() : undefined,
|
site: astroConfig.site ? new URL(astroConfig.base, astroConfig.site).toString() : undefined,
|
||||||
ssr: isBuildingToSSR(astroConfig),
|
ssr: astroConfig.output === 'server',
|
||||||
streaming: true,
|
streaming: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ export function createResult(args: CreateResultArgs): SSRResult {
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
if (args.streaming) {
|
if (args.streaming) {
|
||||||
headers.set('Transfer-Encoding', 'chunked');
|
headers.set('Transfer-Encoding', 'chunked');
|
||||||
|
headers.set('Content-Type', 'text/html');
|
||||||
} else {
|
} else {
|
||||||
headers.set('Content-Type', 'text/html');
|
headers.set('Content-Type', 'text/html');
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ export function createRequest({
|
||||||
warn(
|
warn(
|
||||||
logging,
|
logging,
|
||||||
'ssg',
|
'ssg',
|
||||||
`Headers are not exposed in static-site generation (SSG) mode. To enable reading headers you need to set an SSR adapter in your config.`
|
`Headers are not exposed in static (SSG) output mode. To enable headers: set \`output: "server"\` in your config file.`
|
||||||
);
|
);
|
||||||
return _headers;
|
return _headers;
|
||||||
},
|
},
|
||||||
|
|
|
@ -182,15 +182,8 @@ export function isPage(file: URL, config: AstroConfig): boolean {
|
||||||
return endsWithPageExt(file, config);
|
return endsWithPageExt(file, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isBuildingToSSR(config: AstroConfig): boolean {
|
export function isModeServerWithNoAdapter(config: AstroConfig): boolean {
|
||||||
const adapter = config._ctx.adapter;
|
return config.output === 'server' && !config._ctx.adapter;
|
||||||
if (!adapter) return false;
|
|
||||||
|
|
||||||
if (typeof adapter.serverEntrypoint === 'string') {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function emoji(char: string, fallback: string) {
|
export function emoji(char: string, fallback: string) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import { createRequire } from 'node:module';
|
|
||||||
import type { AstroUserConfig } from '../@types/astro';
|
import type { AstroUserConfig } from '../@types/astro';
|
||||||
const require = createRequire(import.meta.url);
|
|
||||||
|
|
||||||
const EVENT_SESSION = 'ASTRO_CLI_SESSION_STARTED';
|
const EVENT_SESSION = 'ASTRO_CLI_SESSION_STARTED';
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,10 @@ import {
|
||||||
HookParameters,
|
HookParameters,
|
||||||
RouteData,
|
RouteData,
|
||||||
} from '../@types/astro.js';
|
} from '../@types/astro.js';
|
||||||
import ssgAdapter from '../adapter-ssg/index.js';
|
|
||||||
import type { SerializedSSRManifest } from '../core/app/types';
|
import type { SerializedSSRManifest } from '../core/app/types';
|
||||||
import type { PageBuildData } from '../core/build/types';
|
import type { PageBuildData } from '../core/build/types';
|
||||||
import { mergeConfig } from '../core/config.js';
|
import { mergeConfig } from '../core/config.js';
|
||||||
import type { ViteConfigWithSSR } from '../core/create-vite.js';
|
import type { ViteConfigWithSSR } from '../core/create-vite.js';
|
||||||
import { isBuildingToSSR } from '../core/util.js';
|
|
||||||
|
|
||||||
export async function runHookConfigSetup({
|
export async function runHookConfigSetup({
|
||||||
config: _config,
|
config: _config,
|
||||||
|
@ -21,8 +19,9 @@ export async function runHookConfigSetup({
|
||||||
config: AstroConfig;
|
config: AstroConfig;
|
||||||
command: 'dev' | 'build';
|
command: 'dev' | 'build';
|
||||||
}): Promise<AstroConfig> {
|
}): Promise<AstroConfig> {
|
||||||
|
// An adapter is an integration, so if one is provided push it.
|
||||||
if (_config.adapter) {
|
if (_config.adapter) {
|
||||||
_config.integrations.push(_config.adapter);
|
_config.integrations.push(_config.adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
let updatedConfig: AstroConfig = { ..._config };
|
let updatedConfig: AstroConfig = { ..._config };
|
||||||
|
@ -80,7 +79,7 @@ export async function runHookConfigDone({ config }: { config: AstroConfig }) {
|
||||||
setAdapter(adapter) {
|
setAdapter(adapter) {
|
||||||
if (config._ctx.adapter && config._ctx.adapter.name !== adapter.name) {
|
if (config._ctx.adapter && config._ctx.adapter.name !== adapter.name) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Adapter already set to ${config._ctx.adapter.name}. You can only have one adapter.`
|
`Integration "${integration.name}" conflicts with "${config._ctx.adapter.name}". You can only configure one deployment integration.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
config._ctx.adapter = adapter;
|
config._ctx.adapter = adapter;
|
||||||
|
@ -88,22 +87,9 @@ export async function runHookConfigDone({ config }: { config: AstroConfig }) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Call the default adapter
|
|
||||||
if (!config._ctx.adapter) {
|
|
||||||
const integration = ssgAdapter();
|
|
||||||
config.integrations.push(integration);
|
|
||||||
if (integration?.hooks?.['astro:config:done']) {
|
|
||||||
await integration.hooks['astro:config:done']({
|
|
||||||
config,
|
|
||||||
setAdapter(adapter) {
|
|
||||||
config._ctx.adapter = adapter;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runHookServerSetup({
|
export async function runHookServerSetup({
|
||||||
config,
|
config,
|
||||||
server,
|
server,
|
||||||
}: {
|
}: {
|
||||||
|
@ -203,7 +189,7 @@ export async function runHookBuildDone({
|
||||||
pages: string[];
|
pages: string[];
|
||||||
routes: RouteData[];
|
routes: RouteData[];
|
||||||
}) {
|
}) {
|
||||||
const dir = isBuildingToSSR(config) ? buildConfig.client : config.outDir;
|
const dir = config.output === 'server' ? buildConfig.client : config.outDir;
|
||||||
|
|
||||||
for (const integration of config.integrations) {
|
for (const integration of config.integrations) {
|
||||||
if (integration?.hooks?.['astro:build:done']) {
|
if (integration?.hooks?.['astro:build:done']) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { preload, ssr } from '../core/render/dev/index.js';
|
||||||
import { RouteCache } from '../core/render/route-cache.js';
|
import { RouteCache } from '../core/render/route-cache.js';
|
||||||
import { createRequest } from '../core/request.js';
|
import { createRequest } from '../core/request.js';
|
||||||
import { createRouteManifest, matchRoute } from '../core/routing/index.js';
|
import { createRouteManifest, matchRoute } from '../core/routing/index.js';
|
||||||
import { createSafeError, isBuildingToSSR, resolvePages } from '../core/util.js';
|
import { createSafeError, resolvePages } from '../core/util.js';
|
||||||
import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js';
|
import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js';
|
||||||
|
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
|
@ -205,7 +205,7 @@ async function handleRequest(
|
||||||
) {
|
) {
|
||||||
const reqStart = performance.now();
|
const reqStart = performance.now();
|
||||||
const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
|
const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
|
||||||
const buildingToSSR = isBuildingToSSR(config);
|
const buildingToSSR = config.output === 'server';
|
||||||
// Ignore `.html` extensions and `index.html` in request URLS to ensure that
|
// Ignore `.html` extensions and `index.html` in request URLS to ensure that
|
||||||
// routing behavior matches production builds. This supports both file and directory
|
// routing behavior matches production builds. This supports both file and directory
|
||||||
// build formats, and is necessary based on how the manifest tracks build targets.
|
// build formats, and is necessary based on how the manifest tracks build targets.
|
||||||
|
@ -276,7 +276,7 @@ async function handleRequest(
|
||||||
routeCache,
|
routeCache,
|
||||||
pathname: pathname,
|
pathname: pathname,
|
||||||
logging,
|
logging,
|
||||||
ssr: isBuildingToSSR(config),
|
ssr: config.output === 'server',
|
||||||
});
|
});
|
||||||
if (paramsAndPropsRes === GetParamsAndPropsError.NoMatchingStaticPath) {
|
if (paramsAndPropsRes === GetParamsAndPropsError.NoMatchingStaticPath) {
|
||||||
warn(
|
warn(
|
||||||
|
|
|
@ -12,9 +12,7 @@ describe('Astro.clientAddress', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/client-address/',
|
root: './fixtures/client-address/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -67,9 +65,7 @@ describe('Astro.clientAddress', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/client-address/',
|
root: './fixtures/client-address/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter({ provideAddress: false }),
|
adapter: testAdapter({ provideAddress: false }),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
@ -90,6 +86,7 @@ describe('Astro.clientAddress', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/client-address/',
|
root: './fixtures/client-address/',
|
||||||
|
output: 'static',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
101
packages/astro/test/config-mode.test.js
Normal file
101
packages/astro/test/config-mode.test.js
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { load as cheerioLoad } from 'cheerio';
|
||||||
|
import { loadFixture } from './test-utils.js';
|
||||||
|
import testAdapter from './test-adapter.js';
|
||||||
|
|
||||||
|
describe('AstroConfig - config.mode', () => {
|
||||||
|
describe(`output: 'server'`, () => {
|
||||||
|
describe('deploy config provided', () => {
|
||||||
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
let fixture;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
fixture = await loadFixture({
|
||||||
|
// This is just a random fixture to test, doesn't matter.
|
||||||
|
root: './fixtures/astro-basic/',
|
||||||
|
adapter: testAdapter(),
|
||||||
|
output: 'server',
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Builds an SSR-able app', async () => {
|
||||||
|
const app = await fixture.loadTestAdapterApp();
|
||||||
|
const request = new Request('http://example.com/');
|
||||||
|
const response = await app.render(request);
|
||||||
|
expect(response.status).to.equal(200);
|
||||||
|
expect(response.headers.get('content-type')).to.equal('text/html');
|
||||||
|
const html = await response.text();
|
||||||
|
expect(html.length).to.be.greaterThan(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deploy config omitted', () => {
|
||||||
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
let fixture;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
fixture = await loadFixture({
|
||||||
|
// This is just a random fixture to test, doesn't matter.
|
||||||
|
root: './fixtures/astro-basic/',
|
||||||
|
output: 'server'
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Throws during the build', async () => {
|
||||||
|
let built = false;
|
||||||
|
try {
|
||||||
|
await fixture.build();
|
||||||
|
built = true;
|
||||||
|
} catch(err) {
|
||||||
|
expect(err).to.be.an.instanceOf(Error);
|
||||||
|
expect(err.message).to.match(/without an adapter/);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(built).to.equal(false, 'Should not have built');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`output: 'static'`, () => {
|
||||||
|
describe('Deploy config omitted', () => {
|
||||||
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
let fixture;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
fixture = await loadFixture({
|
||||||
|
// This is just a random fixture to test, doesn't matter.
|
||||||
|
root: './fixtures/astro-basic/',
|
||||||
|
output: 'static'
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Builds to static HTML', async () => {
|
||||||
|
let html;
|
||||||
|
try {
|
||||||
|
html = await fixture.readFile('/index.html');
|
||||||
|
} catch(err) {
|
||||||
|
expect(false).to.equal(true, 'Couldnt find the file, which mean it did not build.');
|
||||||
|
}
|
||||||
|
expect(html.length).to.be.greaterThan(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skip('deploy config provided - TODO, we need adapters to support static mode first', () => {
|
||||||
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
let fixture;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
fixture = await loadFixture({
|
||||||
|
// This is just a random fixture to test, doesn't matter.
|
||||||
|
root: './fixtures/astro-basic/',
|
||||||
|
adapter: testAdapter(),
|
||||||
|
output: 'server'
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -3,4 +3,5 @@ import nodejs from '@astrojs/node';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
adapter: nodejs(),
|
adapter: nodejs(),
|
||||||
|
output: 'server',
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,9 +10,7 @@ describe('404 and 500 pages', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-api-route-custom-404/',
|
root: './fixtures/ssr-api-route-custom-404/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build({});
|
await fixture.build({});
|
||||||
|
|
|
@ -11,9 +11,7 @@ describe('Integration buildConfig hook', () => {
|
||||||
let _config;
|
let _config;
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-request/',
|
root: './fixtures/ssr-request/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: {
|
adapter: {
|
||||||
name: 'my-ssr-adapter',
|
name: 'my-ssr-adapter',
|
||||||
hooks: {
|
hooks: {
|
||||||
|
|
|
@ -9,9 +9,7 @@ describe('API routes in SSR', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-api-route/',
|
root: './fixtures/ssr-api-route/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -9,9 +9,7 @@ describe('SSR Assets', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-assets/',
|
root: './fixtures/ssr-assets/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -10,9 +10,7 @@ describe('Dynamic pages in SSR', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-dynamic/',
|
root: './fixtures/ssr-dynamic/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -10,9 +10,7 @@ describe('SSR Environment Variables', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-env/',
|
root: './fixtures/ssr-env/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -10,9 +10,7 @@ describe('Hoisted scripts in SSR', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-hoisted-script/',
|
root: './fixtures/ssr-hoisted-script/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -10,9 +10,7 @@ describe('SSR with Large Array and client rendering', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/large-array/',
|
root: './fixtures/large-array/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -10,9 +10,7 @@ describe('Lit integration in SSR', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/lit-element/',
|
root: './fixtures/lit-element/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -10,9 +10,7 @@ describe('Markdown pages in SSR', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-markdown/',
|
root: './fixtures/ssr-markdown/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -11,9 +11,7 @@ describe('Using the Partytown integration in SSR', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-partytown/',
|
root: './fixtures/ssr-partytown/',
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
experimental: {
|
output: 'server'
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,9 +9,7 @@ describe('Astro.redirect', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-redirect/',
|
root: './fixtures/ssr-redirect/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -11,9 +11,7 @@ describe('Using Astro.request in SSR', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-request/',
|
root: './fixtures/ssr-request/',
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
experimental: {
|
output: 'server'
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,9 +11,7 @@ describe('Using Astro.response in SSR', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-response/',
|
root: './fixtures/ssr-response/',
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
experimental: {
|
output: 'server'
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,9 +9,7 @@ describe('SSR Hydrated component scripts', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/ssr-scripts/',
|
root: './fixtures/ssr-scripts/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -176,7 +176,7 @@ describe('Static build', () => {
|
||||||
for (const log of logs) {
|
for (const log of logs) {
|
||||||
if (
|
if (
|
||||||
log.type === 'ssg' &&
|
log.type === 'ssg' &&
|
||||||
/[hH]eaders are not exposed in static-site generation/.test(log.args[0])
|
/[hH]eaders are not exposed in static \(SSG\) output mode/.test(log.args[0])
|
||||||
) {
|
) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,7 @@ describe('Streaming', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/streaming/',
|
root: './fixtures/streaming/',
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
experimental: {
|
output: 'server'
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -82,9 +80,7 @@ describe('Streaming disabled', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/streaming/',
|
root: './fixtures/streaming/',
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
server: {
|
server: {
|
||||||
streaming: false,
|
streaming: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -72,8 +72,14 @@ export async function loadFixture(inlineConfig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {import('../src/core/logger/core').LogOptions} */
|
||||||
|
const logging = {
|
||||||
|
dest: nodeLogDestination,
|
||||||
|
level: 'error',
|
||||||
|
};
|
||||||
|
|
||||||
// Load the config.
|
// Load the config.
|
||||||
let config = await loadConfig({ cwd: fileURLToPath(cwd) });
|
let config = await loadConfig({ cwd: fileURLToPath(cwd), logging });
|
||||||
config = merge(config, { ...inlineConfig, root: cwd });
|
config = merge(config, { ...inlineConfig, root: cwd });
|
||||||
|
|
||||||
// HACK: the inline config doesn't run through config validation where these normalizations usually occur
|
// HACK: the inline config doesn't run through config validation where these normalizations usually occur
|
||||||
|
@ -89,12 +95,6 @@ export async function loadFixture(inlineConfig) {
|
||||||
config._ctx.renderers.unshift(jsxRenderer);
|
config._ctx.renderers.unshift(jsxRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {import('../src/core/logger/core').LogOptions} */
|
|
||||||
const logging = {
|
|
||||||
dest: nodeLogDestination,
|
|
||||||
level: 'error',
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @type {import('@astrojs/telemetry').AstroTelemetry} */
|
/** @type {import('@astrojs/telemetry').AstroTelemetry} */
|
||||||
const telemetry = {
|
const telemetry = {
|
||||||
record() {
|
record() {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { defineConfig } from 'astro/config';
|
||||||
import cloudflare from '@astrojs/cloudflare';
|
import cloudflare from '@astrojs/cloudflare';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
adapter: cloudflare()
|
adapter: cloudflare()
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
|
@ -21,6 +21,11 @@ export default function createIntegration(): AstroIntegration {
|
||||||
'astro:config:done': ({ setAdapter, config }) => {
|
'astro:config:done': ({ setAdapter, config }) => {
|
||||||
setAdapter(getAdapter());
|
setAdapter(getAdapter());
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
|
if(config.output === 'static') {
|
||||||
|
console.warn(`[@astrojs/cloudflare] \`output: "server"\` is required to use this adapter.`);
|
||||||
|
console.warn(`[@astrojs/cloudflare] Otherwise, this adapter is not required to deploy a static site to Cloudflare.`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'astro:build:start': ({ buildConfig }) => {
|
'astro:build:start': ({ buildConfig }) => {
|
||||||
_buildConfig = buildConfig;
|
_buildConfig = buildConfig;
|
||||||
|
|
|
@ -37,6 +37,7 @@ import deno from '@astrojs/deno';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// ...
|
// ...
|
||||||
|
output: 'server',
|
||||||
adapter: deno()
|
adapter: deno()
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
@ -69,6 +70,7 @@ import { defineConfig } from 'astro/config';
|
||||||
import deno from '@astrojs/deno';
|
import deno from '@astrojs/deno';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
adapter: deno({
|
adapter: deno({
|
||||||
//options go here
|
//options go here
|
||||||
})
|
})
|
||||||
|
@ -85,6 +87,7 @@ export default defineConfig({
|
||||||
import deno from '@astrojs/deno';
|
import deno from '@astrojs/deno';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
adapter: deno({
|
adapter: deno({
|
||||||
start: false
|
start: false
|
||||||
})
|
})
|
||||||
|
@ -115,6 +118,7 @@ export default defineConfig({
|
||||||
import deno from '@astrojs/deno';
|
import deno from '@astrojs/deno';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
adapter: deno({
|
adapter: deno({
|
||||||
port: 8081,
|
port: 8081,
|
||||||
hostname: 'myhost'
|
hostname: 'myhost'
|
||||||
|
|
|
@ -29,8 +29,13 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
return {
|
return {
|
||||||
name: '@astrojs/deno',
|
name: '@astrojs/deno',
|
||||||
hooks: {
|
hooks: {
|
||||||
'astro:config:done': ({ setAdapter }) => {
|
'astro:config:done': ({ setAdapter, config }) => {
|
||||||
setAdapter(getAdapter(args));
|
setAdapter(getAdapter(args));
|
||||||
|
|
||||||
|
if(config.output === 'static') {
|
||||||
|
console.warn(`[@astrojs/deno] \`output: "server"\` is required to use this adapter.`);
|
||||||
|
console.warn(`[@astrojs/deno] Otherwise, this adapter is not required to deploy a static site to Deno.`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'astro:build:start': ({ buildConfig }) => {
|
'astro:build:start': ({ buildConfig }) => {
|
||||||
_buildConfig = buildConfig;
|
_buildConfig = buildConfig;
|
||||||
|
|
|
@ -5,7 +5,5 @@ import react from '@astrojs/react';
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
adapter: deno(),
|
adapter: deno(),
|
||||||
integrations: [react()],
|
integrations: [react()],
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,7 +3,5 @@ import deno from '@astrojs/deno';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
adapter: deno(),
|
adapter: deno(),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -16,7 +16,7 @@ export default function integration(options: IntegrationOptions = {}): AstroInte
|
||||||
const staticImages = new Map<string, Map<string, TransformOptions>>();
|
const staticImages = new Map<string, Map<string, TransformOptions>>();
|
||||||
|
|
||||||
let _config: AstroConfig;
|
let _config: AstroConfig;
|
||||||
let mode: 'ssr' | 'ssg';
|
let output: 'server' | 'static';
|
||||||
|
|
||||||
function getViteConfiguration() {
|
function getViteConfiguration() {
|
||||||
return {
|
return {
|
||||||
|
@ -37,11 +37,11 @@ export default function integration(options: IntegrationOptions = {}): AstroInte
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
// Always treat `astro dev` as SSR mode, even without an adapter
|
// Always treat `astro dev` as SSR mode, even without an adapter
|
||||||
mode = command === 'dev' || config.adapter ? 'ssr' : 'ssg';
|
output = command === 'dev' ? 'server' : config.output;
|
||||||
|
|
||||||
updateConfig({ vite: getViteConfiguration() });
|
updateConfig({ vite: getViteConfiguration() });
|
||||||
|
|
||||||
if (mode === 'ssr') {
|
if (output === 'server') {
|
||||||
injectRoute({
|
injectRoute({
|
||||||
pattern: ROUTE_PATTERN,
|
pattern: ROUTE_PATTERN,
|
||||||
entryPoint:
|
entryPoint:
|
||||||
|
@ -67,7 +67,7 @@ export default function integration(options: IntegrationOptions = {}): AstroInte
|
||||||
|
|
||||||
// Helpers for building static images should only be available for SSG
|
// Helpers for building static images should only be available for SSG
|
||||||
globalThis.astroImage =
|
globalThis.astroImage =
|
||||||
mode === 'ssg'
|
output === 'static'
|
||||||
? {
|
? {
|
||||||
addStaticImage,
|
addStaticImage,
|
||||||
filenameFormat,
|
filenameFormat,
|
||||||
|
@ -75,7 +75,7 @@ export default function integration(options: IntegrationOptions = {}): AstroInte
|
||||||
: {};
|
: {};
|
||||||
},
|
},
|
||||||
'astro:build:done': async ({ dir }) => {
|
'astro:build:done': async ({ dir }) => {
|
||||||
if (mode === 'ssr') {
|
if (output === 'server') {
|
||||||
// for SSR builds, copy all image files from src to dist
|
// for SSR builds, copy all image files from src to dist
|
||||||
// to make sure they are available for use in production
|
// to make sure they are available for use in production
|
||||||
await ssrBuild({ srcDir: _config.srcDir, outDir: dir });
|
await ssrBuild({ srcDir: _config.srcDir, outDir: dir });
|
||||||
|
|
|
@ -19,9 +19,7 @@ describe('SSR images - build', function () {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/basic-image/',
|
root: './fixtures/basic-image/',
|
||||||
adapter: testAdapter({ streaming: false }),
|
adapter: testAdapter({ streaming: false }),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
@ -139,9 +137,7 @@ describe('SSR images - dev', function () {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/basic-image/',
|
root: './fixtures/basic-image/',
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
|
|
|
@ -19,9 +19,7 @@ describe('SSR pictures - build', function () {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/basic-picture/',
|
root: './fixtures/basic-picture/',
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
@ -187,9 +185,7 @@ describe('SSR images - dev', function () {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/basic-picture/',
|
root: './fixtures/basic-picture/',
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
devServer = await fixture.startDevServer();
|
devServer = await fixture.startDevServer();
|
||||||
|
|
|
@ -37,6 +37,7 @@ import { defineConfig } from 'astro/config';
|
||||||
import netlify from '@astrojs/netlify/functions';
|
import netlify from '@astrojs/netlify/functions';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
adapter: netlify(),
|
adapter: netlify(),
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
@ -51,6 +52,7 @@ import { defineConfig } from 'astro/config';
|
||||||
+ import netlify from '@astrojs/netlify/edge-functions';
|
+ import netlify from '@astrojs/netlify/edge-functions';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
adapter: netlify(),
|
adapter: netlify(),
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
@ -83,6 +85,7 @@ import { defineConfig } from 'astro/config';
|
||||||
import netlify from '@astrojs/netlify/functions';
|
import netlify from '@astrojs/netlify/functions';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
adapter: netlify({
|
adapter: netlify({
|
||||||
dist: new URL('./dist/', import.meta.url)
|
dist: new URL('./dist/', import.meta.url)
|
||||||
})
|
})
|
||||||
|
|
|
@ -135,6 +135,11 @@ export function netlifyEdgeFunctions({ dist }: NetlifyEdgeFunctionsOptions = {})
|
||||||
'astro:config:done': ({ config, setAdapter }) => {
|
'astro:config:done': ({ config, setAdapter }) => {
|
||||||
setAdapter(getAdapter());
|
setAdapter(getAdapter());
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
|
if(config.output === 'static') {
|
||||||
|
console.warn(`[@astrojs/netlify] \`output: "server"\` is required to use this adapter.`);
|
||||||
|
console.warn(`[@astrojs/netlify] Otherwise, this adapter is not required to deploy a static site to Netlify.`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'astro:build:start': async ({ buildConfig }) => {
|
'astro:build:start': async ({ buildConfig }) => {
|
||||||
_buildConfig = buildConfig;
|
_buildConfig = buildConfig;
|
||||||
|
|
|
@ -35,6 +35,11 @@ function netlifyFunctions({
|
||||||
'astro:config:done': ({ config, setAdapter }) => {
|
'astro:config:done': ({ config, setAdapter }) => {
|
||||||
setAdapter(getAdapter({ binaryMediaTypes }));
|
setAdapter(getAdapter({ binaryMediaTypes }));
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
|
if(config.output === 'static') {
|
||||||
|
console.warn(`[@astrojs/netlify] \`output: "server"\` is required to use this adapter.`);
|
||||||
|
console.warn(`[@astrojs/netlify] Otherwise, this adapter is not required to deploy a static site to Netlify.`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'astro:build:start': async ({ buildConfig }) => {
|
'astro:build:start': async ({ buildConfig }) => {
|
||||||
entryFile = buildConfig.serverEntry.replace(/\.m?js/, '');
|
entryFile = buildConfig.serverEntry.replace(/\.m?js/, '');
|
||||||
|
|
|
@ -5,7 +5,5 @@ export default defineConfig({
|
||||||
adapter: netlifyEdgeFunctions({
|
adapter: netlifyEdgeFunctions({
|
||||||
dist: new URL('./dist/', import.meta.url),
|
dist: new URL('./dist/', import.meta.url),
|
||||||
}),
|
}),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,7 +7,5 @@ export default defineConfig({
|
||||||
dist: new URL('./dist/', import.meta.url),
|
dist: new URL('./dist/', import.meta.url),
|
||||||
}),
|
}),
|
||||||
integrations: [react()],
|
integrations: [react()],
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,7 +5,5 @@ export default defineConfig({
|
||||||
adapter: netlifyEdgeFunctions({
|
adapter: netlifyEdgeFunctions({
|
||||||
dist: new URL('./dist/', import.meta.url),
|
dist: new URL('./dist/', import.meta.url),
|
||||||
}),
|
}),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,9 +9,7 @@ describe('Base64 Responses', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: new URL('./fixtures/base64-response/', import.meta.url).toString(),
|
root: new URL('./fixtures/base64-response/', import.meta.url).toString(),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: netlifyAdapter({
|
adapter: netlifyAdapter({
|
||||||
dist: new URL('./fixtures/base64-response/dist/', import.meta.url),
|
dist: new URL('./fixtures/base64-response/dist/', import.meta.url),
|
||||||
binaryMediaTypes: ['font/otf'],
|
binaryMediaTypes: ['font/otf'],
|
||||||
|
|
|
@ -11,9 +11,7 @@ describe('Cookies', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: new URL('./fixtures/cookies/', import.meta.url).toString(),
|
root: new URL('./fixtures/cookies/', import.meta.url).toString(),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: netlifyAdapter({
|
adapter: netlifyAdapter({
|
||||||
dist: new URL('./fixtures/cookies/dist/', import.meta.url),
|
dist: new URL('./fixtures/cookies/dist/', import.meta.url),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -9,9 +9,7 @@ describe('Dynamic pages', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: new URL('./fixtures/dynamic-route/', import.meta.url).toString(),
|
root: new URL('./fixtures/dynamic-route/', import.meta.url).toString(),
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: netlifyAdapter({
|
adapter: netlifyAdapter({
|
||||||
dist: new URL('./fixtures/dynamic-route/dist/', import.meta.url),
|
dist: new URL('./fixtures/dynamic-route/dist/', import.meta.url),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -37,6 +37,7 @@ import node from '@astrojs/node';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// ...
|
// ...
|
||||||
|
output: 'server',
|
||||||
adapter: node()
|
adapter: node()
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
|
@ -12,8 +12,12 @@ export default function createIntegration(): AstroIntegration {
|
||||||
return {
|
return {
|
||||||
name: '@astrojs/node',
|
name: '@astrojs/node',
|
||||||
hooks: {
|
hooks: {
|
||||||
'astro:config:done': ({ setAdapter }) => {
|
'astro:config:done': ({ setAdapter, config }) => {
|
||||||
setAdapter(getAdapter());
|
setAdapter(getAdapter());
|
||||||
|
|
||||||
|
if(config.output === 'static') {
|
||||||
|
console.warn(`[@astrojs/Node] \`output: "server"\` is required to use this adapter.`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,9 +9,7 @@ describe('API routes', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/api-route/',
|
root: './fixtures/api-route/',
|
||||||
experimental: {
|
output: 'server',
|
||||||
ssr: true,
|
|
||||||
},
|
|
||||||
adapter: nodejs(),
|
adapter: nodejs(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
|
|
@ -98,9 +98,9 @@ const createPlugin = (options?: SitemapOptions): AstroIntegration => {
|
||||||
|
|
||||||
if (pageUrls.length === 0) {
|
if (pageUrls.length === 0) {
|
||||||
// offer suggestion for SSR users
|
// offer suggestion for SSR users
|
||||||
if (typeof config.adapter !== 'undefined') {
|
if (config.output !== 'static') {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`No pages found! We can only detect sitemap routes for "static" projects. Since you are using an SSR adapter, we recommend manually listing your sitemap routes using the "customPages" integration option.\n\nExample: \`sitemap({ customPages: ['https://example.com/route'] })\``
|
`No pages found! We can only detect sitemap routes for "static" builds. Since you are using an SSR adapter, we recommend manually listing your sitemap routes using the "customPages" integration option.\n\nExample: \`sitemap({ customPages: ['https://example.com/route'] })\``
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
logger.warn(`No pages found!\n\`${OUTFILE}\` not created.`);
|
logger.warn(`No pages found!\n\`${OUTFILE}\` not created.`);
|
||||||
|
|
|
@ -25,7 +25,7 @@ First, install the `@astrojs/vercel` package using your package manager. If you'
|
||||||
npm install @astrojs/vercel
|
npm install @astrojs/vercel
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, install this adapter in your `astro.config.*` file using the `adapter` property (note the import from `@astrojs/vercel/serverless` - see [targets](#targets)).
|
Then, install this adapter in your `astro.config.*` file using the `deploy` property (note the import from `@astrojs/vercel/serverless` - see [targets](#targets)).
|
||||||
|
|
||||||
__`astro.config.mjs`__
|
__`astro.config.mjs`__
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ import { defineConfig } from 'astro/config';
|
||||||
import vercel from '@astrojs/vercel/serverless';
|
import vercel from '@astrojs/vercel/serverless';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
adapter: vercel()
|
adapter: vercel()
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
|
@ -23,9 +23,7 @@ export default function vercelStatic(): AstroIntegration {
|
||||||
setAdapter(getAdapter());
|
setAdapter(getAdapter());
|
||||||
_config = config;
|
_config = config;
|
||||||
},
|
},
|
||||||
'astro:build:start': async ({ buildConfig }) => {
|
'astro:build:start': async () => {
|
||||||
buildConfig.staticMode = true;
|
|
||||||
|
|
||||||
// Ensure to have `.vercel/output` empty.
|
// Ensure to have `.vercel/output` empty.
|
||||||
// This is because, when building to static, outDir = .vercel/output/static/,
|
// This is because, when building to static, outDir = .vercel/output/static/,
|
||||||
// so .vercel/output itself won't get cleaned.
|
// so .vercel/output itself won't get cleaned.
|
||||||
|
|
2
packages/webapi/mod.d.ts
vendored
2
packages/webapi/mod.d.ts
vendored
|
@ -1,5 +1,5 @@
|
||||||
export { pathToPosix } from './lib/utils';
|
export { pathToPosix } from './lib/utils';
|
||||||
export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter } from './mod.js';
|
export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, } from './mod.js';
|
||||||
export declare const polyfill: {
|
export declare const polyfill: {
|
||||||
(target: any, options?: PolyfillOptions): any;
|
(target: any, options?: PolyfillOptions): any;
|
||||||
internals(target: any, name: string): any;
|
internals(target: any, name: string): any;
|
||||||
|
|
Loading…
Reference in a new issue