summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--packages/astro/package.json5
-rw-r--r--packages/astro/src/@types/astro.ts2
-rw-r--r--packages/astro/src/core/build/index.ts3
-rw-r--r--packages/astro/src/core/config.ts2
-rw-r--r--packages/astro/src/core/routing/manifest/create.ts6
-rw-r--r--packages/astro/src/integrations/index.ts3
-rw-r--r--packages/integrations/vercel/README.md44
-rw-r--r--packages/integrations/vercel/package.json33
-rw-r--r--packages/integrations/vercel/src/index.ts79
-rw-r--r--packages/integrations/vercel/src/shims.ts5
-rw-r--r--packages/integrations/vercel/tsconfig.json10
-rw-r--r--pnpm-lock.yaml34
13 files changed, 221 insertions, 6 deletions
diff --git a/.gitignore b/.gitignore
index 2185b7f84..6a837da1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
node_modules/
dist/
+.output/
*.tsbuildinfo
.DS_Store
.vercel
diff --git a/packages/astro/package.json b/packages/astro/package.json
index 70d26a3d2..d475244bb 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -103,6 +103,7 @@
"htmlparser2": "^7.2.0",
"kleur": "^4.1.4",
"magic-string": "^0.25.9",
+ "micromatch": "^4.0.5",
"micromorph": "^0.1.2",
"mime": "^3.0.0",
"ora": "^6.1.0",
@@ -145,6 +146,7 @@
"@types/diff": "^5.0.2",
"@types/estree": "^0.0.51",
"@types/html-escaper": "^3.0.0",
+ "@types/micromatch": "^4.0.2",
"@types/mime": "^2.0.3",
"@types/mocha": "^9.1.0",
"@types/parse5": "^6.0.3",
@@ -157,7 +159,8 @@
"chai": "^4.3.6",
"cheerio": "^1.0.0-rc.10",
"mocha": "^9.2.2",
- "sass": "^1.49.9"
+ "sass": "^1.49.9",
+ "type-fest": "^2.12.1"
},
"engines": {
"node": "^14.15.0 || >=16.0.0",
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index fca4aff80..47c783e0d 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -502,6 +502,7 @@ export interface AstroConfig extends z.output<typeof AstroConfigSchema> {
adapter: AstroAdapter | undefined;
renderers: AstroRenderer[];
scripts: { stage: InjectedScriptStage; content: string }[];
+ ignoredPages: string[];
};
}
@@ -671,6 +672,7 @@ export interface AstroIntegration {
updateConfig: (newConfig: Record<string, any>) => void;
addRenderer: (renderer: AstroRenderer) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
+ ignorePages: (glob: string) => void;
// TODO: Add support for `injectElement()` for full HTML element injection, not just scripts.
// This may require some refactoring of `scripts`, `styles`, and `links` into something
// more generalized. Consider the SSR use-case as well.
diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts
index 4962ce1c7..1800c2636 100644
--- a/packages/astro/src/core/build/index.ts
+++ b/packages/astro/src/core/build/index.ts
@@ -26,7 +26,7 @@ export interface BuildOptions {
/** `astro build` */
export default async function build(config: AstroConfig, options: BuildOptions = { logging: defaultLogOptions }): Promise<void> {
- applyPolyfill();
+ config = await runHookConfigSetup({ config, command: 'build' });
const builder = new AstroBuilder(config, options);
await builder.run();
}
@@ -62,7 +62,6 @@ class AstroBuilder {
const { logging } = this;
this.timer.init = performance.now();
this.timer.viteStart = performance.now();
- this.config = await runHookConfigSetup({ config: this.config, command: 'build' });
const viteConfig = await createVite(
{
mode: this.mode,
diff --git a/packages/astro/src/core/config.ts b/packages/astro/src/core/config.ts
index 394c1c42d..8e4547d0a 100644
--- a/packages/astro/src/core/config.ts
+++ b/packages/astro/src/core/config.ts
@@ -206,7 +206,7 @@ export async function validateConfig(userConfig: any, root: string): Promise<Ast
// First-Pass Validation
const result = {
...(await AstroConfigRelativeSchema.parseAsync(userConfig)),
- _ctx: { scripts: [], renderers: [], adapter: undefined },
+ _ctx: { scripts: [], renderers: [], adapter: undefined, ignoredPages: [] },
};
// Final-Pass Validation (perform checks that require the full config object)
if (!result.experimentalIntegrations && !result.integrations.every((int) => int.name.startsWith('@astrojs/'))) {
diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts
index 1e0a6f3bc..8e0bdb736 100644
--- a/packages/astro/src/core/routing/manifest/create.ts
+++ b/packages/astro/src/core/routing/manifest/create.ts
@@ -4,6 +4,7 @@ import type { LogOptions } from '../../logger';
import fs from 'fs';
import path from 'path';
import { compile } from 'path-to-regexp';
+import micromatch from 'micromatch';
import slash from 'slash';
import { fileURLToPath } from 'url';
import { warn } from '../../logger.js';
@@ -178,11 +179,16 @@ export function createRouteManifest({ config, cwd }: { config: AstroConfig; cwd?
fs.readdirSync(dir).forEach((basename) => {
const resolved = path.join(dir, basename);
const file = slash(path.relative(cwd || fileURLToPath(config.projectRoot), resolved));
+ const pagePath = slash(path.relative(fileURLToPath(config.pages), resolved));
const isDir = fs.statSync(resolved).isDirectory();
const ext = path.extname(basename);
const name = ext ? basename.slice(0, -ext.length) : basename;
+ if ((config._ctx?.ignoredPages || []).length > 0 && micromatch.isMatch(pagePath, config._ctx.ignoredPages)) {
+ return;
+ }
+
if (name[0] === '_') {
return;
}
diff --git a/packages/astro/src/integrations/index.ts b/packages/astro/src/integrations/index.ts
index b04caeaf1..580552775 100644
--- a/packages/astro/src/integrations/index.ts
+++ b/packages/astro/src/integrations/index.ts
@@ -24,6 +24,9 @@ export async function runHookConfigSetup({ config: _config, command }: { config:
updateConfig: (newConfig) => {
updatedConfig = mergeConfig(updatedConfig, newConfig) as AstroConfig;
},
+ ignorePages: (glob: string) => {
+ updatedConfig._ctx.ignoredPages.push(glob);
+ },
});
}
}
diff --git a/packages/integrations/vercel/README.md b/packages/integrations/vercel/README.md
new file mode 100644
index 000000000..24fdb5187
--- /dev/null
+++ b/packages/integrations/vercel/README.md
@@ -0,0 +1,44 @@
+# @astrojs/netlify
+
+Deploy your server-side rendered (SSR) Astro app to [Netlify](https://www.netlify.com/).
+
+Use this adapter in your Astro configuration file:
+
+```js
+import { defineConfig } from 'astro/config';
+import netlify from '@astrojs/netlify/functions';
+
+export default defineConfig({
+ adapter: netlify()
+});
+```
+
+After you build your site the `netlify/` folder will contain [Netlify Functions](https://docs.netlify.com/functions/overview/) in the `netlify/functions/` folder.
+
+Now you can deploy!
+
+```shell
+netlify deploy
+```
+
+## Configuration
+
+The output folder is configuration with the `dist` property when creating the adapter.
+
+```js
+import { defineConfig } from 'astro/config';
+import netlify from '@astrojs/netlify/functions';
+
+export default defineConfig({
+ adapter: netlify({
+ dist: new URL('./dist/', import.meta.url)
+ })
+});
+```
+
+And then point to the dist in your `netlify.toml`:
+
+```toml
+[functions]
+ directory = "dist/functions"
+```
diff --git a/packages/integrations/vercel/package.json b/packages/integrations/vercel/package.json
new file mode 100644
index 000000000..d7713183c
--- /dev/null
+++ b/packages/integrations/vercel/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "@astrojs/vercel",
+ "description": "Deploy your site to Vercel",
+ "version": "0.0.1",
+ "type": "module",
+ "types": "./dist/index.d.ts",
+ "author": "withastro",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/withastro/astro.git",
+ "directory": "packages/integrations/vercel"
+ },
+ "bugs": "https://github.com/withastro/astro/issues",
+ "homepage": "https://astro.build",
+ "exports": {
+ ".": "./dist/index.js",
+ "./package.json": "./package.json"
+ },
+ "scripts": {
+ "build": "astro-scripts build \"src/**/*.ts\" && tsc",
+ "dev": "astro-scripts dev \"src/**/*.ts\""
+ },
+ "dependencies": {
+ "@astrojs/webapi": "^0.11.0",
+ "esbuild": "0.14.25",
+ "globby": "^12.2.0"
+ },
+ "devDependencies": {
+ "astro": "workspace:*",
+ "astro-scripts": "workspace:*"
+ }
+}
diff --git a/packages/integrations/vercel/src/index.ts b/packages/integrations/vercel/src/index.ts
new file mode 100644
index 000000000..5d6794206
--- /dev/null
+++ b/packages/integrations/vercel/src/index.ts
@@ -0,0 +1,79 @@
+import type { AstroIntegration, AstroConfig } from 'astro';
+import type { IncomingMessage, ServerResponse } from 'http';
+import type { PathLike } from 'fs';
+
+import fs from 'fs/promises';
+import { fileURLToPath } from 'url';
+import { globby } from 'globby';
+import esbuild from 'esbuild';
+
+export type VercelRequest = IncomingMessage;
+export type VercelResponse = ServerResponse;
+export type VercelHandler = (request: VercelRequest, response: VercelResponse) => void | Promise<void>;
+
+const writeJson = (path: PathLike, data: any) => fs.writeFile(path, JSON.stringify(data), { encoding: 'utf-8' });
+
+const ENDPOINT_GLOB = 'api/**/*.{js,ts,tsx}';
+
+function vercelFunctions(): AstroIntegration {
+ let _config: AstroConfig;
+ let output: URL;
+
+ return {
+ name: '@astrojs/vercel',
+ hooks: {
+ 'astro:config:setup': ({ config, ignorePages }) => {
+ output = new URL('./.output/', config.projectRoot);
+ config.dist = new URL('./static/', output);
+ config.buildOptions.pageUrlFormat = 'directory';
+ ignorePages(ENDPOINT_GLOB);
+ },
+ 'astro:config:done': async ({ config }) => {
+ _config = config;
+ },
+ 'astro:build:start': async () => {
+ await fs.rm(output, { recursive: true, force: true });
+ },
+ 'astro:build:done': async ({ pages }) => {
+ // Split pages from the rest of files
+ await Promise.all(
+ pages.map(async ({ pathname }) => {
+ const origin = new URL(`./static/${pathname}index.html`, output);
+ const finalDir = new URL(`./server/pages/${pathname}`, output);
+
+ await fs.mkdir(finalDir, { recursive: true });
+ await fs.copyFile(origin, new URL(`./index.html`, finalDir));
+ await fs.rm(origin);
+ })
+ );
+
+ // Routes Manifest
+ // https://vercel.com/docs/file-system-api#configuration/routes
+ await writeJson(new URL(`./routes-manifest.json`, output), {
+ version: 3,
+ basePath: '/',
+ pages404: false,
+ });
+
+ const endpoints = await globby([ENDPOINT_GLOB, '!_*'], { onlyFiles: true, cwd: _config.pages });
+
+ if (endpoints.length === 0) return;
+
+ await esbuild.build({
+ entryPoints: endpoints.map((endpoint) => new URL(endpoint, _config.pages)).map(fileURLToPath),
+ outdir: fileURLToPath(new URL('./server/pages/api/', output)),
+ outbase: fileURLToPath(new URL('./api/', _config.pages)),
+ inject: [fileURLToPath(new URL('./shims.js', import.meta.url))],
+ bundle: true,
+ target: 'node14',
+ platform: 'node',
+ format: 'cjs',
+ });
+
+ await writeJson(new URL(`./package.json`, output), { type: 'commonjs' });
+ },
+ },
+ };
+}
+
+export default vercelFunctions;
diff --git a/packages/integrations/vercel/src/shims.ts b/packages/integrations/vercel/src/shims.ts
new file mode 100644
index 000000000..01f7b39bf
--- /dev/null
+++ b/packages/integrations/vercel/src/shims.ts
@@ -0,0 +1,5 @@
+import { polyfill } from '@astrojs/webapi';
+
+polyfill(globalThis, {
+ exclude: 'window document',
+});
diff --git a/packages/integrations/vercel/tsconfig.json b/packages/integrations/vercel/tsconfig.json
new file mode 100644
index 000000000..44baf375c
--- /dev/null
+++ b/packages/integrations/vercel/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "include": ["src"],
+ "compilerOptions": {
+ "allowJs": true,
+ "module": "ES2020",
+ "outDir": "./dist",
+ "target": "ES2020"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 503d62826..997848edc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -464,6 +464,7 @@ importers:
'@types/diff': ^5.0.2
'@types/estree': ^0.0.51
'@types/html-escaper': ^3.0.0
+ '@types/micromatch': ^4.0.2
'@types/mime': ^2.0.3
'@types/mocha': ^9.1.0
'@types/parse5': ^6.0.3
@@ -494,6 +495,7 @@ importers:
htmlparser2: ^7.2.0
kleur: ^4.1.4
magic-string: ^0.25.9
+ micromatch: ^4.0.5
micromorph: ^0.1.2
mime: ^3.0.0
mocha: ^9.2.2
@@ -522,6 +524,7 @@ importers:
strip-ansi: ^7.0.1
supports-esm: ^1.0.0
tsconfig-resolver: ^3.0.1
+ type-fest: ^2.12.1
vite: ^2.8.6
yargs-parser: ^21.0.1
zod: ^3.14.3
@@ -556,6 +559,7 @@ importers:
htmlparser2: 7.2.0
kleur: 4.1.4
magic-string: 0.25.9
+ micromatch: 4.0.5
micromorph: 0.1.2
mime: 3.0.0
ora: 6.1.0
@@ -597,6 +601,7 @@ importers:
'@types/diff': 5.0.2
'@types/estree': 0.0.51
'@types/html-escaper': 3.0.0
+ '@types/micromatch': 4.0.2
'@types/mime': 2.0.3
'@types/mocha': 9.1.0
'@types/parse5': 6.0.3
@@ -610,6 +615,7 @@ importers:
cheerio: 1.0.0-rc.10
mocha: 9.2.2
sass: 1.49.9
+ type-fest: 2.12.1
packages/astro-prism:
specifiers:
@@ -1339,6 +1345,21 @@ importers:
astro: link:../../astro
astro-scripts: link:../../../scripts
+ packages/integrations/vercel:
+ specifiers:
+ '@astrojs/webapi': ^0.11.0
+ astro: workspace:*
+ astro-scripts: workspace:*
+ esbuild: 0.14.25
+ globby: ^12.2.0
+ dependencies:
+ '@astrojs/webapi': link:../../webapi
+ esbuild: 0.14.25
+ globby: 12.2.0
+ devDependencies:
+ astro: link:../../astro
+ astro-scripts: link:../../../scripts
+
packages/integrations/vue:
specifiers:
'@vitejs/plugin-vue': ^2.2.4
@@ -3827,6 +3848,10 @@ packages:
'@babel/types': 7.17.0
dev: true
+ /@types/braces/3.0.1:
+ resolution: {integrity: sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==}
+ dev: true
+
/@types/chai/4.3.0:
resolution: {integrity: sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==}
dev: true
@@ -3915,6 +3940,12 @@ packages:
resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==}
dev: false
+ /@types/micromatch/4.0.2:
+ resolution: {integrity: sha512-oqXqVb0ci19GtH0vOA/U2TmHTcRY9kuZl4mqUxe0QmJAlIW13kzhuK5pi1i9+ngav8FjpSb9FVS/GE00GLX1VA==}
+ dependencies:
+ '@types/braces': 3.0.1
+ dev: true
+
/@types/mime/1.3.2:
resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==}
dev: true
@@ -10176,7 +10207,6 @@ packages:
/type-fest/2.12.1:
resolution: {integrity: sha512-AiknQSEqKVGDDjtZqeKrUoTlcj7FKhupmnVUgz6KoOKtvMwRGE6hUNJ/nVear+h7fnUPO1q/htSkYKb1pyntkQ==}
engines: {node: '>=12.20'}
- dev: false
/typescript/4.6.3:
resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==}
@@ -10689,7 +10719,7 @@ packages:
/wide-align/1.1.5:
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
dependencies:
- string-width: 1.0.2
+ string-width: 4.2.3
dev: true
/widest-line/4.0.1: