mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 04:22:13 +00:00
Compare commits
45 Commits
@vercel/py
...
vercel@28.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b30f000d2a | ||
|
|
f78051ada9 | ||
|
|
10bc74904c | ||
|
|
c8f7a9a874 | ||
|
|
2fd3315221 | ||
|
|
54ef027cbe | ||
|
|
6620c7f600 | ||
|
|
38f40f1c15 | ||
|
|
63211b8b89 | ||
|
|
83ee5ea2b8 | ||
|
|
f063645646 | ||
|
|
4f8c5e344d | ||
|
|
70a53515bd | ||
|
|
4d4f0fa672 | ||
|
|
46c0fd153a | ||
|
|
1c8b4717e3 | ||
|
|
d52d26eaac | ||
|
|
db65728fc4 | ||
|
|
a788d06f85 | ||
|
|
3d98d1cdea | ||
|
|
667af829c4 | ||
|
|
1bb7b37e0c | ||
|
|
ca81c133b9 | ||
|
|
f332b7856c | ||
|
|
9308a0fda5 | ||
|
|
c2f8a5990a | ||
|
|
fc2f0b919b | ||
|
|
a606ab8678 | ||
|
|
13062cd47d | ||
|
|
bb9faaed99 | ||
|
|
881e43a0e2 | ||
|
|
578a7742fe | ||
|
|
2d84a64430 | ||
|
|
200ac99647 | ||
|
|
1d3f2b5a62 | ||
|
|
8f49969585 | ||
|
|
cfbfaa7cd0 | ||
|
|
25747a7621 | ||
|
|
8d635beed7 | ||
|
|
6225f050fa | ||
|
|
30a899bab1 | ||
|
|
a010d8fe8a | ||
|
|
a9ff23fe22 | ||
|
|
b60d3f657a | ||
|
|
e7947a1b33 |
5
.github/workflows/cron-update-next.yml
vendored
5
.github/workflows/cron-update-next.yml
vendored
@@ -1,6 +1,8 @@
|
||||
name: Cron Update Next
|
||||
|
||||
on:
|
||||
# Allow manual runs
|
||||
workflow_dispatch:
|
||||
# Run every 4 hours https://crontab.guru/every-4-hours
|
||||
schedule:
|
||||
- cron: '0 */4 * * *'
|
||||
@@ -14,10 +16,13 @@ jobs:
|
||||
# 0 means fetch all commits so we can commit and push in the script below
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Enable corepack
|
||||
run: corepack enable pnpm
|
||||
- name: Create Pull Request
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
|
||||
# See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function
|
||||
with:
|
||||
script: |
|
||||
|
||||
7
.github/workflows/cron-update-turbo.yml
vendored
7
.github/workflows/cron-update-turbo.yml
vendored
@@ -1,6 +1,8 @@
|
||||
name: Cron Update Turbo
|
||||
|
||||
on:
|
||||
# Allow manual runs
|
||||
workflow_dispatch:
|
||||
# Run every week https://crontab.guru/every-week
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
@@ -14,12 +16,13 @@ jobs:
|
||||
# 0 means fetch all commits so we can commit and push in the script below
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: install pnpm@7.26.0
|
||||
run: npm i -g pnpm@7.26.0
|
||||
- name: Enable corepack
|
||||
run: corepack enable pnpm
|
||||
- name: Create Pull Request
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
|
||||
# See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function
|
||||
with:
|
||||
script: |
|
||||
|
||||
2
.github/workflows/publish.yml
vendored
2
.github/workflows/publish.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 14
|
||||
node-version: 16
|
||||
- name: install pnpm@7.24.2
|
||||
run: npm i -g pnpm@7.24.2
|
||||
- name: Install
|
||||
|
||||
4
.github/workflows/test-integration-cli.yml
vendored
4
.github/workflows/test-integration-cli.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
node: [14]
|
||||
node: [16]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
run: npm i -g pnpm@7.24.2
|
||||
- run: pnpm install
|
||||
- run: pnpm run build
|
||||
- run: pnpm test-integration-cli
|
||||
- run: pnpm test-cli
|
||||
env:
|
||||
VERCEL_TEST_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
|
||||
VERCEL_TEST_REGISTRATION_URL: ${{ secrets.VERCEL_TEST_REGISTRATION_URL }}
|
||||
|
||||
2
.github/workflows/test-unit.yml
vendored
2
.github/workflows/test-unit.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
node: [14]
|
||||
node: [16]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
NODE_VERSION: '14'
|
||||
NODE_VERSION: '16'
|
||||
TURBO_REMOTE_ONLY: 'true'
|
||||
TURBO_TEAM: 'vercel'
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
|
||||
@@ -11,4 +11,4 @@ Remove the `functions` config from your `now.json` or `vercel.json` to take adva
|
||||
|
||||
### Useful Links
|
||||
|
||||
- [Functions Config Documentation](https://vercel.com/docs/configuration?query=functions#project/functions)
|
||||
- [Functions Config Documentation](https://vercel.com/docs/concepts/projects/project-configuration#functions)
|
||||
|
||||
@@ -11,6 +11,6 @@ Migrate from using legacy `routes` to the new `rewrites`, `redirects`, and `head
|
||||
|
||||
### Useful Links
|
||||
|
||||
- [Rewrites Documentation](https://vercel.com/docs/configuration?query=rewrites#project/rewrites)
|
||||
- [Redirects Documentation](https://vercel.com/docs/configuration?query=rewrites#project/redirects)
|
||||
- [Headers Documentation](https://vercel.com/docs/configuration?query=rewrites#project/headers)
|
||||
- [Rewrites Documentation](https://vercel.com/docs/concepts/projects/project-configuration#rewrites)
|
||||
- [Redirects Documentation](https://vercel.com/docs/concepts/projects/project-configuration#redirects)
|
||||
- [Headers Documentation](https://vercel.com/docs/concepts/projects/project-configuration#headers)
|
||||
|
||||
@@ -14,7 +14,9 @@ In order to create the smallest possible lambdas Next.js has to be configured to
|
||||
npm install next --save
|
||||
```
|
||||
|
||||
2. Add the `now-build` script to your `package.json`
|
||||
2. Check [Node.js Version](https://vercel.link/node-version) in your Project Settings. Using an old or incompatible version of Node.js can cause the Build Step to fail with this error message.
|
||||
|
||||
3. Add the `now-build` script to your `package.json` [deprecated]
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -24,7 +26,7 @@ npm install next --save
|
||||
}
|
||||
```
|
||||
|
||||
3. Add `target: 'serverless'` to `next.config.js` [deprecated]
|
||||
4. Add `target: 'serverless'` to `next.config.js` [deprecated]
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
@@ -33,9 +35,9 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
4. Remove `distDir` from `next.config.js` as `@vercel/next` can't parse this file and expects your build output at `/.next`
|
||||
5. Remove `distDir` from `next.config.js` as `@vercel/next` can't parse this file and expects your build output at `/.next`
|
||||
|
||||
5. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
|
||||
6. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
|
||||
|
||||
```js
|
||||
{
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
#### Why This Error Occurred
|
||||
|
||||
This could be caused by a misconfigured "Build Command" or "Output Directory" for your Next.js project.
|
||||
This error is often caused by a misconfigured "Build Command" or "Output Directory" for your Next.js project.
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
In the Vercel dashboard, open your "Project Settings" and draw attention to "Build & Development Settings":
|
||||
|
||||
1. Ensure that the "Build Command" setting is not changed, or that it calls `next build`. If this command is not changed but you are seeing this error, double check that your `build` script in `package.json` calls `next build`.
|
||||
2. Ensure that the "Output Directory" setting is not changed. This value almost never needs to be configured, and is only necessary if you override `distDir` in `next.config.js`.
|
||||
3. For `next export` users: **do not override the "Output Directory"**. Next.js automatically detects what folder you outputted `next export` to.
|
||||
1. Ensure that the "Build Command" setting is not overridden, or that it calls `next build`. If this command is not overridden but you are seeing this error, double check that your `build` script in `package.json` calls `next build`. If `buildCommand` exists in `vercel.json`, make sure it calls `next build`.
|
||||
2. Ensure that the "Output Directory" setting is not overridden. This value almost never needs to be configured, and is only necessary if you override `distDir` in `next.config.js`. If `outputDirectory` exists in `vercel.json`, remove that property.
|
||||
3. For `next export` users: **do not override the "Output Directory"**, even if you customized the `next export` output directory. It will automatically detects the correct output.
|
||||
|
||||
In rare scenarios, this error message can also be caused by a Next.js build failure (if your "Build Command" accidentally returns an exit code that is not 0).
|
||||
Double check for any error messages above the Routes Manifest error, which may provide additional details.
|
||||
|
||||
2
examples/package.json
vendored
2
examples/package.json
vendored
@@ -4,7 +4,7 @@
|
||||
"description": "Each subdirectory is an example boilerplate for a framework. This package.json only exists for testing purposes.",
|
||||
"scripts": {
|
||||
"test-unit": "pnpm test __tests__/unit/",
|
||||
"test-integration-once": "pnpm test __tests__/integration/",
|
||||
"test-e2e": "pnpm test __tests__/integration/",
|
||||
"test": "jest --env node --verbose --runInBand --bail"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -13,10 +13,10 @@ function hydrate() {
|
||||
});
|
||||
}
|
||||
|
||||
if (window.requestIdleCallback) {
|
||||
window.requestIdleCallback(hydrate);
|
||||
if (typeof requestIdleCallback === "function") {
|
||||
requestIdleCallback(hydrate);
|
||||
} else {
|
||||
// Safari doesn't support requestIdleCallback
|
||||
// https://caniuse.com/requestidlecallback
|
||||
window.setTimeout(hydrate, 1);
|
||||
setTimeout(hydrate, 1);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
import type { EntryContext } from "@remix-run/node";
|
||||
import handleRequest from "@vercel/remix-entry-server";
|
||||
import { RemixServer } from "@remix-run/react";
|
||||
import { renderToString } from "react-dom/server";
|
||||
import type { EntryContext } from "@remix-run/server-runtime";
|
||||
|
||||
export default function handleRequest(
|
||||
export default function (
|
||||
request: Request,
|
||||
responseStatusCode: number,
|
||||
responseHeaders: Headers,
|
||||
remixContext: EntryContext
|
||||
) {
|
||||
const markup = renderToString(
|
||||
<RemixServer context={remixContext} url={request.url} />
|
||||
);
|
||||
|
||||
responseHeaders.set("Content-Type", "text/html");
|
||||
|
||||
return new Response("<!DOCTYPE html>" + markup, {
|
||||
headers: responseHeaders,
|
||||
status: responseStatusCode,
|
||||
});
|
||||
const remixServer = <RemixServer context={remixContext} url={request.url} />;
|
||||
return handleRequest(request, responseStatusCode, responseHeaders, remixServer)
|
||||
}
|
||||
|
||||
|
||||
11
examples/remix/app/routes/edge.tsx
Normal file
11
examples/remix/app/routes/edge.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
export const config = {
|
||||
runtime: 'edge'
|
||||
};
|
||||
|
||||
export default function Edge() {
|
||||
return (
|
||||
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
|
||||
<h1>Welcome to Remix@Edge</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -6,20 +6,20 @@
|
||||
"dev": "remix dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@remix-run/node": "^1.7.6",
|
||||
"@remix-run/react": "^1.7.6",
|
||||
"@remix-run/vercel": "^1.7.6",
|
||||
"@vercel/analytics": "^0.1.5",
|
||||
"@vercel/node": "^2.7.0",
|
||||
"@remix-run/node": "^1.13.0",
|
||||
"@remix-run/react": "^1.13.0",
|
||||
"@remix-run/serve": "^1.13.0",
|
||||
"@remix-run/server-runtime": "^1.13.0",
|
||||
"@vercel/analytics": "^0.1.10",
|
||||
"@vercel/remix-entry-server": "^0.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@remix-run/dev": "^1.7.6",
|
||||
"@remix-run/eslint-config": "^1.7.6",
|
||||
"@remix-run/serve": "^1.7.6",
|
||||
"@remix-run/dev": "^1.13.0",
|
||||
"@remix-run/eslint-config": "^1.13.0",
|
||||
"@types/react": "^18.0.25",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"eslint": "^8.28.0",
|
||||
"typescript": "^4.9.3"
|
||||
},
|
||||
|
||||
3566
examples/remix/pnpm-lock.yaml
generated
3566
examples/remix/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,10 @@
|
||||
/** @type {import('@remix-run/dev').AppConfig} */
|
||||
/**
|
||||
* @type {import('@remix-run/dev').AppConfig}
|
||||
*/
|
||||
module.exports = {
|
||||
serverBuildTarget: "vercel",
|
||||
// When running locally in development mode, we use the built in remix
|
||||
// server. This does not understand the vercel lambda module format,
|
||||
// so we default back to the standard build output.
|
||||
server: process.env.NODE_ENV === "development" ? undefined : "./server.js",
|
||||
ignoredRouteFiles: ["**/.*"],
|
||||
ignoredRouteFiles: ['**/.*'],
|
||||
// appDirectory: "app",
|
||||
// assetsBuildDirectory: "public/build",
|
||||
// serverBuildPath: "api/index.js",
|
||||
// serverBuildPath: "build/index.js",
|
||||
// publicPath: "/build/",
|
||||
};
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import { createRequestHandler } from "@remix-run/vercel";
|
||||
import * as build from "@remix-run/dev/server-build";
|
||||
|
||||
export default createRequestHandler({ build, mode: process.env.NODE_ENV });
|
||||
@@ -32,7 +32,7 @@
|
||||
"source-map-support": "0.5.12",
|
||||
"ts-eager": "2.0.2",
|
||||
"ts-jest": "28.0.5",
|
||||
"turbo": "1.7.0"
|
||||
"turbo": "1.7.4"
|
||||
},
|
||||
"scripts": {
|
||||
"lerna": "lerna",
|
||||
@@ -47,9 +47,9 @@
|
||||
"pre-commit": "lint-staged",
|
||||
"test": "jest --rootDir=\"test\" --testPathPattern=\"\\.test.js\"",
|
||||
"test-unit": "pnpm test && node utils/gen.js && turbo run test-unit",
|
||||
"test-integration-cli": "node utils/gen.js && turbo run test-integration-cli",
|
||||
"test-integration-once": "node utils/gen.js && turbo run test-integration-once",
|
||||
"test-integration-dev": "node utils/gen.js && turbo run test-integration-dev",
|
||||
"test-cli": "node utils/gen.js && turbo run test-cli",
|
||||
"test-e2e": "node utils/gen.js && turbo run test-e2e",
|
||||
"test-dev": "node utils/gen.js && turbo run test-dev",
|
||||
"lint": "eslint . --cache --ext .ts,.js",
|
||||
"prepare": "husky install",
|
||||
"pack": "cd utils && node -r ts-eager/register ./pack.ts"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "6.2.2",
|
||||
"version": "6.3.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
@@ -14,7 +14,7 @@
|
||||
"build": "node build",
|
||||
"test": "jest --env node --verbose --runInBand --bail",
|
||||
"test-unit": "pnpm test test/unit.*test.*",
|
||||
"test-integration-once": "pnpm test test/integration.test.ts"
|
||||
"test-e2e": "pnpm test test/integration.test.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iarna/toml": "2.2.3",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Cron, Files } from './types';
|
||||
import type { Files, FunctionFramework } from './types';
|
||||
|
||||
/**
|
||||
* An Edge Functions output
|
||||
@@ -41,8 +41,8 @@ export class EdgeFunction {
|
||||
/** The regions where the edge function will be executed on */
|
||||
regions?: string | string[];
|
||||
|
||||
/** Cronjob definition for the edge function */
|
||||
cron?: Cron;
|
||||
/** The framework */
|
||||
framework?: FunctionFramework;
|
||||
|
||||
constructor(params: Omit<EdgeFunction, 'type'>) {
|
||||
this.type = 'EdgeFunction';
|
||||
@@ -53,6 +53,6 @@ export class EdgeFunction {
|
||||
this.envVarsInUse = params.envVarsInUse;
|
||||
this.assets = params.assets;
|
||||
this.regions = params.regions;
|
||||
this.cron = params.cron;
|
||||
this.framework = params.framework;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ export function getPrettyError(obj: {
|
||||
message?: string;
|
||||
params: any;
|
||||
}): NowBuildError {
|
||||
const docsUrl = 'https://vercel.com/docs/configuration';
|
||||
const docsUrl =
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration';
|
||||
try {
|
||||
const { dataPath, params, message: ajvMessage } = obj;
|
||||
const prop = getTopLevelPropertyName(dataPath);
|
||||
@@ -63,7 +64,7 @@ export function getPrettyError(obj: {
|
||||
return new NowBuildError({
|
||||
code: 'INVALID_VERCEL_CONFIG',
|
||||
message: message,
|
||||
link: prop ? `${docsUrl}#project/${prop.toLowerCase()}` : docsUrl,
|
||||
link: prop ? `${docsUrl}#${prop.toLowerCase()}` : docsUrl,
|
||||
action: 'View Documentation',
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import minimatch from 'minimatch';
|
||||
import { readlink } from 'fs-extra';
|
||||
import { isSymbolicLink, isDirectory } from './fs/download';
|
||||
import streamToBuffer from './fs/stream-to-buffer';
|
||||
import type { Files, Config, Cron } from './types';
|
||||
import type { Files, Config, FunctionFramework } from './types';
|
||||
|
||||
interface Environment {
|
||||
[key: string]: string;
|
||||
@@ -25,7 +25,7 @@ export interface LambdaOptionsBase {
|
||||
supportsWrapper?: boolean;
|
||||
experimentalResponseStreaming?: boolean;
|
||||
operationType?: string;
|
||||
cron?: Cron;
|
||||
framework?: FunctionFramework;
|
||||
}
|
||||
|
||||
export interface LambdaOptionsWithFiles extends LambdaOptionsBase {
|
||||
@@ -63,7 +63,6 @@ export class Lambda {
|
||||
environment: Environment;
|
||||
allowQuery?: string[];
|
||||
regions?: string[];
|
||||
cron?: Cron;
|
||||
/**
|
||||
* @deprecated Use `await lambda.createZip()` instead.
|
||||
*/
|
||||
@@ -71,6 +70,7 @@ export class Lambda {
|
||||
supportsMultiPayloads?: boolean;
|
||||
supportsWrapper?: boolean;
|
||||
experimentalResponseStreaming?: boolean;
|
||||
framework?: FunctionFramework;
|
||||
|
||||
constructor(opts: LambdaOptions) {
|
||||
const {
|
||||
@@ -81,11 +81,11 @@ export class Lambda {
|
||||
environment = {},
|
||||
allowQuery,
|
||||
regions,
|
||||
cron,
|
||||
supportsMultiPayloads,
|
||||
supportsWrapper,
|
||||
experimentalResponseStreaming,
|
||||
operationType,
|
||||
framework,
|
||||
} = opts;
|
||||
if ('files' in opts) {
|
||||
assert(typeof opts.files === 'object', '"files" must be an object');
|
||||
@@ -135,8 +135,18 @@ export class Lambda {
|
||||
);
|
||||
}
|
||||
|
||||
if (cron !== undefined) {
|
||||
assert(typeof cron === 'string', '"cron" is not a string');
|
||||
if (framework !== undefined) {
|
||||
assert(typeof framework === 'object', '"framework" is not an object');
|
||||
assert(
|
||||
typeof framework.slug === 'string',
|
||||
'"framework.slug" is not a string'
|
||||
);
|
||||
if (framework.version !== undefined) {
|
||||
assert(
|
||||
typeof framework.version === 'string',
|
||||
'"framework.version" is not a string'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.type = 'Lambda';
|
||||
@@ -149,11 +159,11 @@ export class Lambda {
|
||||
this.environment = environment;
|
||||
this.allowQuery = allowQuery;
|
||||
this.regions = regions;
|
||||
this.cron = cron;
|
||||
this.zipBuffer = 'zipBuffer' in opts ? opts.zipBuffer : undefined;
|
||||
this.supportsMultiPayloads = supportsMultiPayloads;
|
||||
this.supportsWrapper = supportsWrapper;
|
||||
this.experimentalResponseStreaming = experimentalResponseStreaming;
|
||||
this.framework = framework;
|
||||
}
|
||||
|
||||
async createZip(): Promise<Buffer> {
|
||||
@@ -228,7 +238,7 @@ export async function getLambdaOptionsFromFunction({
|
||||
sourceFile,
|
||||
config,
|
||||
}: GetLambdaOptionsFromFunctionOptions): Promise<
|
||||
Pick<LambdaOptions, 'memory' | 'maxDuration' | 'cron'>
|
||||
Pick<LambdaOptions, 'memory' | 'maxDuration'>
|
||||
> {
|
||||
if (config?.functions) {
|
||||
for (const [pattern, fn] of Object.entries(config.functions)) {
|
||||
@@ -236,7 +246,6 @@ export async function getLambdaOptionsFromFunction({
|
||||
return {
|
||||
memory: fn.memory,
|
||||
maxDuration: fn.maxDuration,
|
||||
cron: fn.cron,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,8 @@ export const functionsSchema = {
|
||||
maxLength: 256,
|
||||
},
|
||||
memory: {
|
||||
// Number between 128 and 3008 in steps of 64
|
||||
enum: Object.keys(Array.from({ length: 50 }))
|
||||
.slice(2, 48)
|
||||
.map(x => Number(x) * 64),
|
||||
minimum: 128,
|
||||
maximum: 3008,
|
||||
},
|
||||
maxDuration: {
|
||||
type: 'number',
|
||||
@@ -31,11 +29,6 @@ export const functionsSchema = {
|
||||
type: 'string',
|
||||
maxLength: 256,
|
||||
},
|
||||
cron: {
|
||||
type: 'string',
|
||||
minLength: 9,
|
||||
maxLength: 256,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -319,7 +319,6 @@ export interface BuilderFunctions {
|
||||
runtime?: string;
|
||||
includeFiles?: string;
|
||||
excludeFiles?: string;
|
||||
cron?: Cron;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -411,7 +410,16 @@ export interface BuildResultBuildOutput {
|
||||
buildOutputPath: string;
|
||||
}
|
||||
|
||||
export type Cron = string;
|
||||
export interface Cron {
|
||||
path: string;
|
||||
schedule: string;
|
||||
}
|
||||
|
||||
/** The framework which created the function */
|
||||
export interface FunctionFramework {
|
||||
slug: string;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a Builder implements `version: 2`, the `build()` function is expected
|
||||
|
||||
4
packages/build-utils/test/unit.test.ts
vendored
4
packages/build-utils/test/unit.test.ts
vendored
@@ -502,6 +502,10 @@ it('should retry npm install when peer deps invalid and npm@8 on node@16', async
|
||||
console.log(`Skipping test on node@${nodeMajor}`);
|
||||
return;
|
||||
}
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
return;
|
||||
}
|
||||
const fixture = path.join(__dirname, 'fixtures', '15-npm-8-legacy-peer-deps');
|
||||
const nodeVersion = { major: nodeMajor } as any;
|
||||
await runNpmInstall(fixture, [], {}, {}, nodeVersion);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "28.15.4",
|
||||
"version": "28.16.4",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -14,8 +14,8 @@
|
||||
"preinstall": "node ./scripts/preinstall.js",
|
||||
"test": "jest --env node --verbose --bail",
|
||||
"test-unit": "pnpm test test/unit/",
|
||||
"test-integration-cli": "rimraf test/fixtures/integration && ava test/integration.js --serial --fail-fast --verbose",
|
||||
"test-integration-dev": "pnpm test test/dev/",
|
||||
"test-cli": "rimraf test/fixtures/integration && ava test/integration.js --serial --fail-fast --verbose",
|
||||
"test-dev": "pnpm test test/dev/",
|
||||
"coverage": "codecov",
|
||||
"build": "ts-node ./scripts/build.ts",
|
||||
"dev": "ts-node ./src/index.ts"
|
||||
@@ -41,16 +41,16 @@
|
||||
"node": ">= 14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "6.2.2",
|
||||
"@vercel/go": "2.3.4",
|
||||
"@vercel/hydrogen": "0.0.50",
|
||||
"@vercel/next": "3.4.3",
|
||||
"@vercel/node": "2.9.3",
|
||||
"@vercel/python": "3.1.46",
|
||||
"@vercel/redwood": "1.1.2",
|
||||
"@vercel/remix": "1.2.13",
|
||||
"@vercel/ruby": "1.3.62",
|
||||
"@vercel/static-build": "1.3.6"
|
||||
"@vercel/build-utils": "6.3.0",
|
||||
"@vercel/go": "2.3.7",
|
||||
"@vercel/hydrogen": "0.0.53",
|
||||
"@vercel/next": "3.5.2",
|
||||
"@vercel/node": "2.9.6",
|
||||
"@vercel/python": "3.1.49",
|
||||
"@vercel/redwood": "1.1.5",
|
||||
"@vercel/remix": "1.3.5",
|
||||
"@vercel/ruby": "1.3.66",
|
||||
"@vercel/static-build": "1.3.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alex_neo/jest-expect-message": "1.0.5",
|
||||
@@ -93,13 +93,13 @@
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@types/yauzl-promise": "2.1.0",
|
||||
"@vercel/client": "12.3.8",
|
||||
"@vercel/client": "12.4.0",
|
||||
"@vercel/error-utils": "1.0.8",
|
||||
"@vercel/frameworks": "1.3.0",
|
||||
"@vercel/fs-detectors": "3.7.11",
|
||||
"@vercel/frameworks": "1.3.1",
|
||||
"@vercel/fs-detectors": "3.8.0",
|
||||
"@vercel/fun": "1.0.4",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/routing-utils": "2.1.8",
|
||||
"@vercel/routing-utils": "2.1.9",
|
||||
"@zeit/source-map-support": "0.6.2",
|
||||
"ajv": "6.12.2",
|
||||
"alpha-sort": "2.0.1",
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
BuildResultV2Typical,
|
||||
BuildResultV3,
|
||||
NowBuildError,
|
||||
Cron,
|
||||
} from '@vercel/build-utils';
|
||||
import {
|
||||
detectBuilders,
|
||||
@@ -88,6 +89,7 @@ interface BuildOutputConfig {
|
||||
framework?: {
|
||||
version: string;
|
||||
};
|
||||
crons?: Cron[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -623,6 +625,7 @@ async function doBuild(
|
||||
});
|
||||
|
||||
const mergedImages = mergeImages(localConfig.images, buildResults.values());
|
||||
const mergedCrons = mergeCrons(localConfig.crons, buildResults.values());
|
||||
const mergedWildcard = mergeWildcard(buildResults.values());
|
||||
const mergedOverrides: Record<string, PathOverride> =
|
||||
overrides.length > 0 ? Object.assign({}, ...overrides) : undefined;
|
||||
@@ -638,6 +641,7 @@ async function doBuild(
|
||||
wildcard: mergedWildcard,
|
||||
overrides: mergedOverrides,
|
||||
framework,
|
||||
crons: mergedCrons,
|
||||
};
|
||||
await fs.writeJSON(join(outputDir, 'config.json'), config, { spaces: 2 });
|
||||
|
||||
@@ -701,7 +705,7 @@ function expandBuild(files: string[], build: Builder): Builder[] {
|
||||
throw new NowBuildError({
|
||||
code: `invalid_build_specification`,
|
||||
message: 'Field `use` is missing in build specification',
|
||||
link: 'https://vercel.com/docs/configuration#project/builds',
|
||||
link: 'https://vercel.com/docs/concepts/projects/project-configuration#builds',
|
||||
action: 'View Documentation',
|
||||
});
|
||||
}
|
||||
@@ -711,7 +715,7 @@ function expandBuild(files: string[], build: Builder): Builder[] {
|
||||
throw new NowBuildError({
|
||||
code: `invalid_build_specification`,
|
||||
message: 'A build `src` path resolves to an empty string',
|
||||
link: 'https://vercel.com/docs/configuration#project/builds',
|
||||
link: 'https://vercel.com/docs/concepts/projects/project-configuration#builds',
|
||||
action: 'View Documentation',
|
||||
});
|
||||
}
|
||||
@@ -746,6 +750,18 @@ function mergeImages(
|
||||
return images;
|
||||
}
|
||||
|
||||
function mergeCrons(
|
||||
crons: BuildOutputConfig['crons'] = [],
|
||||
buildResults: Iterable<BuildResult | BuildOutputConfig>
|
||||
): BuildOutputConfig['crons'] {
|
||||
for (const result of buildResults) {
|
||||
if ('crons' in result && result.crons) {
|
||||
crons = crons.concat(result.crons);
|
||||
}
|
||||
}
|
||||
return crons;
|
||||
}
|
||||
|
||||
function mergeWildcard(
|
||||
buildResults: Iterable<BuildResult | BuildOutputConfig>
|
||||
): BuildResultV2Typical['wildcard'] {
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
Builder,
|
||||
BuildResultV2,
|
||||
BuildResultV3,
|
||||
Cron,
|
||||
File,
|
||||
FileFsRef,
|
||||
BuilderV2,
|
||||
@@ -41,7 +40,6 @@ export const OUTPUT_DIR = join(VERCEL_DIR, 'output');
|
||||
* An entry in the "functions" object in `vercel.json`.
|
||||
*/
|
||||
interface FunctionConfiguration {
|
||||
cron?: Cron;
|
||||
memory?: number;
|
||||
maxDuration?: number;
|
||||
}
|
||||
@@ -372,14 +370,12 @@ async function writeLambda(
|
||||
throw new Error('Malformed `Lambda` - no "files" present');
|
||||
}
|
||||
|
||||
const cron = functionConfiguration?.cron ?? lambda.cron;
|
||||
const memory = functionConfiguration?.memory ?? lambda.memory;
|
||||
const maxDuration = functionConfiguration?.maxDuration ?? lambda.maxDuration;
|
||||
|
||||
const config = {
|
||||
...lambda,
|
||||
handler: normalizePath(lambda.handler),
|
||||
cron,
|
||||
memory,
|
||||
maxDuration,
|
||||
type: undefined,
|
||||
|
||||
@@ -22,7 +22,7 @@ const { format, inspect } = require('util');
|
||||
|
||||
/**
|
||||
* An simple output helper which accumulates error and debug log messages in
|
||||
* memory for potential persistance to disk while immediately outputting errors
|
||||
* memory for potential persistence to disk while immediately outputting errors
|
||||
* and debug messages, when the `--debug` flag is set, to `stderr`.
|
||||
*/
|
||||
class WorkerOutput {
|
||||
|
||||
@@ -76,6 +76,10 @@ async function isGlobal() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (installPath.includes(['', 'fnm', 'node-versions', ''].join(sep))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const prefixPath =
|
||||
process.env.PREFIX ||
|
||||
process.env.npm_config_prefix ||
|
||||
|
||||
@@ -93,6 +93,29 @@ const imagesSchema = {
|
||||
},
|
||||
};
|
||||
|
||||
const cronsSchema = {
|
||||
type: 'array',
|
||||
minItems: 0,
|
||||
items: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
required: ['path', 'schedule'],
|
||||
properties: {
|
||||
path: {
|
||||
type: 'string',
|
||||
minLength: 1,
|
||||
maxLength: 512,
|
||||
pattern: '^/.*',
|
||||
},
|
||||
schedule: {
|
||||
type: 'string',
|
||||
minLength: 9,
|
||||
maxLength: 256,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const vercelConfigSchema = {
|
||||
type: 'object',
|
||||
// These are not all possibilities because `vc dev`
|
||||
@@ -108,6 +131,7 @@ const vercelConfigSchema = {
|
||||
trailingSlash: trailingSlashSchema,
|
||||
functions: functionsSchema,
|
||||
images: imagesSchema,
|
||||
crons: cronsSchema,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.build
|
||||
|
||||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
|
||||
# Mac files
|
||||
.DS_Store
|
||||
|
||||
# Yarn
|
||||
yarn-error.log
|
||||
.pnp/
|
||||
.pnp.js
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
.now
|
||||
.vercel
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Implement Gatsby's Browser APIs in this file.
|
||||
*
|
||||
* See: https://www.gatsbyjs.org/docs/browser-apis/
|
||||
*/
|
||||
|
||||
// You can delete this file if you're not using it
|
||||
@@ -1,16 +0,0 @@
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: 'Gatsby Default Starter',
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
resolve: `gatsby-plugin-manifest`,
|
||||
options: {
|
||||
name: `05-gatsby`,
|
||||
short_name: `starter`,
|
||||
start_url: `/`,
|
||||
icon: 'src/images/gatsby-icon.png',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Implement Gatsby's Node APIs in this file.
|
||||
*
|
||||
* See: https://www.gatsbyjs.org/docs/node-apis/
|
||||
*/
|
||||
|
||||
// You can delete this file if you're not using it
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
|
||||
*
|
||||
* See: https://www.gatsbyjs.org/docs/ssr-apis/
|
||||
*/
|
||||
|
||||
// You can delete this file if you're not using it
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "gatsby",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"gatsby": "^2.18.14",
|
||||
"gatsby-image": "^2.0.15",
|
||||
"gatsby-plugin-manifest": "^2.0.5",
|
||||
"react": "^16.5.1",
|
||||
"react-dom": "^16.5.1"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "gatsby develop",
|
||||
"build": "gatsby build"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,11 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
function Custom404() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Custom Gatsby 404</h1>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default Custom404;
|
||||
@@ -1,12 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
function Index() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Gatsby Default Starter</h1>
|
||||
<p>Hello World</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default Index;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
||||
*.log
|
||||
.cache
|
||||
.DS_Store
|
||||
src/.temp
|
||||
node_modules
|
||||
dist
|
||||
.env
|
||||
.env.*
|
||||
!yarn.lock
|
||||
|
||||
.now
|
||||
.vercel
|
||||
@@ -1,2 +0,0 @@
|
||||
README.md
|
||||
yarn.lock
|
||||
@@ -1,19 +0,0 @@
|
||||
# Gridsome Example
|
||||
|
||||
This directory is a brief example of a [Gridsome](https://gridsome.org/) app that can be deployed to Vercel with zero configuration.
|
||||
|
||||
## How we created this example
|
||||
|
||||
To get started with Gridsome on Vercel, you can use the [Gridsome CLI](https://gridsome.org/docs/gridsome-cli/) to initialize the project:
|
||||
|
||||
```shell
|
||||
$ gridsome create my-website
|
||||
```
|
||||
|
||||
## Deploying this Example
|
||||
|
||||
Once initialized, you can deploy the Gridsome example with just a single command:
|
||||
|
||||
```shell
|
||||
$ vercel
|
||||
```
|
||||
@@ -1,10 +0,0 @@
|
||||
// This is where project configuration and plugin options are located.
|
||||
// Learn more: https://gridsome.org/docs/config
|
||||
|
||||
// Changes here require a server restart.
|
||||
// To restart press CTRL + C in terminal and run `gridsome develop`
|
||||
|
||||
module.exports = {
|
||||
siteName: 'Gridsome',
|
||||
plugins: []
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Server API makes it possible to hook into various parts of Gridsome
|
||||
// on server-side and add custom data to the GraphQL data layer.
|
||||
// Learn more: https://gridsome.org/docs/server-api
|
||||
|
||||
// Changes here require a server restart.
|
||||
// To restart press CTRL + C in terminal and run `gridsome develop`
|
||||
|
||||
module.exports = function (api) {
|
||||
api.loadSource(({ addContentType }) => {
|
||||
// Use the Data Store API here: https://gridsome.org/docs/data-store-api
|
||||
})
|
||||
|
||||
api.createPages(({ createPage }) => {
|
||||
// Use the Pages API here: https://gridsome.org/docs/pages-api
|
||||
})
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "gridsomee",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "gridsome build",
|
||||
"dev": "gridsome develop -p $PORT",
|
||||
"explore": "gridsome explore"
|
||||
},
|
||||
"dependencies": {
|
||||
"gridsome": "0.7.23"
|
||||
},
|
||||
"engines": {
|
||||
"node": "14.x"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
Add components that will be imported to Pages and Layouts to this folder.
|
||||
Learn more about components here: https://gridsome.org/docs/components
|
||||
|
||||
You can delete this file.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
@@ -1,50 +0,0 @@
|
||||
<template>
|
||||
<div class="layout">
|
||||
<header class="header">
|
||||
<strong>
|
||||
<g-link to="/">{{ $static.metaData.siteName }}</g-link>
|
||||
</strong>
|
||||
<nav class="nav">
|
||||
<g-link class="nav__link" to="/">Home</g-link>
|
||||
<g-link class="nav__link" to="/about">About</g-link>
|
||||
</nav>
|
||||
</header>
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<static-query>
|
||||
query {
|
||||
metaData {
|
||||
siteName
|
||||
}
|
||||
}
|
||||
</static-query>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
|
||||
margin:0;
|
||||
padding:0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.layout {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.nav__link {
|
||||
margin-left: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +0,0 @@
|
||||
Layout components are used to wrap pages and templates. Layouts should contain components like headers, footers or sidebars that will be used across the site.
|
||||
|
||||
Learn more about Layouts: https://gridsome.org/docs/layouts
|
||||
|
||||
You can delete this file.
|
||||
@@ -1,9 +0,0 @@
|
||||
// This is the main.js file. Import global CSS and scripts here.
|
||||
// The Client API can be used here. Learn more: gridsome.org/docs/client-api
|
||||
|
||||
import DefaultLayout from '~/layouts/Default.vue'
|
||||
|
||||
export default function (Vue, { router, head, isClient }) {
|
||||
// Set default layout as a global component
|
||||
Vue.component('Layout', DefaultLayout)
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<template>
|
||||
<Layout>
|
||||
<h1>Not Found</h1>
|
||||
<p>This is a Custom Gridsome 404.</p>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
metaInfo: {
|
||||
title: 'Not Found'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,14 +0,0 @@
|
||||
<template>
|
||||
<Layout>
|
||||
<h1>About us</h1>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error doloremque omnis animi, eligendi magni a voluptatum, vitae, consequuntur rerum illum odit fugit assumenda rem dolores inventore iste reprehenderit maxime! Iusto.</p>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
metaInfo: {
|
||||
title: 'About us'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<Layout>
|
||||
|
||||
<!-- Learn how to use images here: https://gridsome.org/docs/images -->
|
||||
<g-image alt="Example image" src="~/favicon.png" width="135" />
|
||||
|
||||
<h1>Gridsome on Vercel</h1>
|
||||
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Pariatur excepturi labore tempore expedita, et iste tenetur suscipit explicabo! Dolores, aperiam non officia eos quod asperiores
|
||||
</p>
|
||||
|
||||
<p class="home-links">
|
||||
<a href="https://gridsome.org/docs" target="_blank" rel="noopener">Gridsome Docs</a>
|
||||
<a href="https://github.com/gridsome/gridsome" target="_blank" rel="noopener">GitHub</a>
|
||||
</p>
|
||||
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
metaInfo: {
|
||||
title: 'Hello, world!'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.home-links a {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +0,0 @@
|
||||
Pages are usually used for normal pages or for listing items from a GraphQL collection.
|
||||
Add .vue files here to create pages. For example **About.vue** will be **site.com/about**.
|
||||
Learn more about pages: https://gridsome.org/docs/pages
|
||||
|
||||
You can delete this file.
|
||||
@@ -1,7 +0,0 @@
|
||||
Templates for **GraphQL collections** should be added here.
|
||||
To create a template for a collection called `WordPressPost`
|
||||
create a file named `WordPressPost.vue` in this folder.
|
||||
|
||||
Learn more: https://gridsome.org/docs/templates
|
||||
|
||||
You can delete this file.
|
||||
@@ -1,3 +0,0 @@
|
||||
Add static files here. Files in this directory will be copied directly to `dist` folder during build. For example, /static/robots.txt will be located at https://yoursite.com/robots.txt.
|
||||
|
||||
This file should be deleted.
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"redirects": [{ "source": "/support", "destination": "/about?ref=support" }]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -105,7 +105,7 @@ test('[vercel dev] throws an error when an edge function has no response', async
|
||||
expect(await res.status).toBe(500);
|
||||
expect(await res.text()).toMatch('FUNCTION_INVOCATION_FAILED');
|
||||
expect(stdout).toMatch(
|
||||
/Error from API Route api\/edge-no-response: Edge Function "api\/edge-no-response.js" did not return a response./g
|
||||
/Error from API Route \/api\/edge-no-response: Edge Function "api\/edge-no-response.js" did not return a response./g
|
||||
);
|
||||
} finally {
|
||||
await dev.kill();
|
||||
@@ -161,7 +161,7 @@ test('[vercel dev] should handle runtime errors thrown in edge functions', async
|
||||
/<strong>500<\/strong>: INTERNAL_SERVER_ERROR/g
|
||||
);
|
||||
expect(stdout).toMatch(
|
||||
/Error from API Route api\/edge-error-runtime: intentional runtime error/g
|
||||
/Error from API Route \/api\/edge-error-runtime: intentional runtime error/g
|
||||
);
|
||||
} finally {
|
||||
await dev.kill();
|
||||
|
||||
@@ -70,27 +70,6 @@ test(
|
||||
await testPath(200, '/', /React App/m);
|
||||
})
|
||||
);
|
||||
/*
|
||||
test(
|
||||
'[vercel dev] 05-gatsby',
|
||||
testFixtureStdio('05-gatsby', async (testPath: any) => {
|
||||
await testPath(200, '/', /Gatsby Default Starter/m);
|
||||
})
|
||||
);
|
||||
*/
|
||||
test(
|
||||
'[vercel dev] 06-gridsome',
|
||||
testFixtureStdio('06-gridsome', async (testPath: any) => {
|
||||
await testPath(200, '/');
|
||||
await testPath(200, '/about');
|
||||
await testPath(308, '/support', 'Redirecting to /about?ref=support (308)', {
|
||||
Location: '/about?ref=support',
|
||||
});
|
||||
// Bug with gridsome's dev server: https://github.com/gridsome/gridsome/issues/831
|
||||
// Works in prod only so leave out for now
|
||||
// await testPath(404, '/nothing');
|
||||
})
|
||||
);
|
||||
|
||||
test(
|
||||
'[vercel dev] 07-hexo-node',
|
||||
|
||||
@@ -10,7 +10,7 @@ const { version: cliVersion } = require('../../package.json');
|
||||
const {
|
||||
fetchCachedToken,
|
||||
} = require('../../../../test/lib/deployment/now-deploy');
|
||||
const { spawnSync } = require('child_process');
|
||||
const { spawnSync, execFileSync } = require('child_process');
|
||||
|
||||
jest.setTimeout(6 * 60 * 1000);
|
||||
|
||||
@@ -522,7 +522,7 @@ async function ps(parentPid, pids = {}) {
|
||||
: ['ps', '-o', 'pid', '--no-headers', '--ppid', parentPid];
|
||||
|
||||
try {
|
||||
const { stdout: buf } = spawnSync(cmd[0], cmd.slice(1), {
|
||||
const buf = execFileSync(cmd[0], cmd.slice(1), {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
for (let pid of buf.match(/\d+/g)) {
|
||||
|
||||
7
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/.vercel/project.json
vendored
Normal file
7
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/.vercel/project.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"orgId": ".",
|
||||
"projectId": ".",
|
||||
"settings": {
|
||||
"framework": null
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
export default function (req, res) {
|
||||
res.json('hello from the edge');
|
||||
res.send('Hello from cron job!');
|
||||
}
|
||||
9
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/build.js
vendored
Normal file
9
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/build.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
fs.rmSync(path.join(__dirname, '.vercel', 'output'), { recursive: true });
|
||||
fs.mkdirSync(path.join(__dirname, '.vercel', 'output'));
|
||||
fs.copyFileSync(
|
||||
path.join(__dirname, 'output', 'config.json'),
|
||||
path.join(__dirname, '.vercel', 'output', 'config.json')
|
||||
);
|
||||
1
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/index.html
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/index.html
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<h1>Vercel</h1>
|
||||
9
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/output/config.json
vendored
Normal file
9
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/output/config.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": 3,
|
||||
"crons": [
|
||||
{
|
||||
"path": "/api/cron-job-build-output",
|
||||
"schedule": "0 0 * * *"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/package.json
vendored
Normal file
5
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/package.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"scripts": {
|
||||
"build": "node build"
|
||||
}
|
||||
}
|
||||
8
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/vercel.json
vendored
Normal file
8
packages/cli/test/fixtures/unit/commands/build/with-cron-merge/vercel.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"crons": [
|
||||
{
|
||||
"path": "/api/cron-job",
|
||||
"schedule": "0 0 * * *"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
export default function (req, res) {
|
||||
res.end('serverless says hello');
|
||||
res.send('Hello from cron job!');
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
export const config = {
|
||||
runtime: 'edge',
|
||||
cron: '* * * * *',
|
||||
};
|
||||
|
||||
export default async function edge(request, event) {
|
||||
const requestBody = await request.text();
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
headerContentType: request.headers.get('content-type'),
|
||||
url: request.url,
|
||||
method: request.method,
|
||||
body: requestBody,
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export default function (req, res) {
|
||||
res.json({ memory: parseInt(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE) });
|
||||
}
|
||||
|
||||
export const config = {
|
||||
cron: '* * * * *',
|
||||
};
|
||||
@@ -1,10 +1,8 @@
|
||||
{
|
||||
"functions": {
|
||||
"api/overwrite/serverless.js": {
|
||||
"cron": "0 10-20 * * *"
|
||||
},
|
||||
"api/overwrite/edge.js": {
|
||||
"cron": "10 * * * *"
|
||||
"crons": [
|
||||
{
|
||||
"path": "/api/cron-job",
|
||||
"schedule": "0 0 * * *"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ module.exports = async function prepare(session, binaryPath, tmpFixturesDir) {
|
||||
},
|
||||
}),
|
||||
},
|
||||
'lambda-with-200-memory': {
|
||||
'lambda-with-123-memory': {
|
||||
'api/memory.js': `
|
||||
module.exports = (req, res) => {
|
||||
res.json({ memory: parseInt(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE) });
|
||||
@@ -280,7 +280,7 @@ module.exports = async function prepare(session, binaryPath, tmpFixturesDir) {
|
||||
'now.json': JSON.stringify({
|
||||
functions: {
|
||||
'api/**/*.js': {
|
||||
memory: 200,
|
||||
memory: 123,
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
26
packages/cli/test/integration.js
vendored
26
packages/cli/test/integration.js
vendored
@@ -1967,7 +1967,11 @@ test('try to create a builds deployments with wrong now.json', async t => {
|
||||
'Error: Invalid now.json - should NOT have additional property `builder`. Did you mean `builds`?'
|
||||
)
|
||||
);
|
||||
t.true(stderr.includes('https://vercel.com/docs/configuration'));
|
||||
t.true(
|
||||
stderr.includes(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
test('try to create a builds deployments with wrong vercel.json', async t => {
|
||||
@@ -1991,7 +1995,11 @@ test('try to create a builds deployments with wrong vercel.json', async t => {
|
||||
'Error: Invalid vercel.json - should NOT have additional property `fake`. Please remove it.'
|
||||
)
|
||||
);
|
||||
t.true(stderr.includes('https://vercel.com/docs/configuration'));
|
||||
t.true(
|
||||
stderr.includes(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
test('try to create a builds deployments with wrong `build.env` property', async t => {
|
||||
@@ -2014,7 +2022,9 @@ test('try to create a builds deployments with wrong `build.env` property', async
|
||||
formatOutput({ stdout, stderr })
|
||||
);
|
||||
t.true(
|
||||
stderr.includes('https://vercel.com/docs/configuration'),
|
||||
stderr.includes(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration'
|
||||
),
|
||||
formatOutput({ stdout, stderr })
|
||||
);
|
||||
});
|
||||
@@ -2625,7 +2635,7 @@ test('next unsupported functions config shows warning link', async t => {
|
||||
t.is(output.exitCode, 0, formatOutput(output));
|
||||
t.regex(
|
||||
output.stderr,
|
||||
/Ignoring function property `runtime`\. When using Next\.js, only `memory`, `maxDuration`, and `cron` can be used\./gm,
|
||||
/Ignoring function property `runtime`\. When using Next\.js, only `memory` and `maxDuration` can be used\./gm,
|
||||
formatOutput(output)
|
||||
);
|
||||
t.regex(
|
||||
@@ -2719,11 +2729,15 @@ test('deploy a Lambda with 128MB of memory', async t => {
|
||||
});
|
||||
|
||||
test('fail to deploy a Lambda with an incorrect value for of memory', async t => {
|
||||
const directory = fixture('lambda-with-200-memory');
|
||||
const directory = fixture('lambda-with-123-memory');
|
||||
const output = await execute([directory, '--yes']);
|
||||
|
||||
t.is(output.exitCode, 1, formatOutput(output));
|
||||
t.regex(output.stderr, /steps of 64/gm, formatOutput(output));
|
||||
t.regex(
|
||||
output.stderr,
|
||||
/Serverless Functions.+memory/gm,
|
||||
formatOutput(output)
|
||||
);
|
||||
t.regex(output.stderr, /Learn More/gm, formatOutput(output));
|
||||
});
|
||||
|
||||
|
||||
@@ -1080,7 +1080,7 @@ describe('build', () => {
|
||||
await expect(client.stderr).toOutput(
|
||||
'Error: Invalid vercel.json - `rewrites[2]` should NOT have additional property `src`. Did you mean `source`?' +
|
||||
'\n' +
|
||||
'View Documentation: https://vercel.com/docs/configuration#project/rewrites'
|
||||
'View Documentation: https://vercel.com/docs/concepts/projects/project-configuration#rewrites'
|
||||
);
|
||||
const builds = await fs.readJSON(join(output, 'builds.json'));
|
||||
expect(builds.builds).toBeUndefined();
|
||||
@@ -1091,7 +1091,7 @@ describe('build', () => {
|
||||
stack: expect.stringContaining('at validateConfig'),
|
||||
hideStackTrace: true,
|
||||
code: 'INVALID_VERCEL_CONFIG',
|
||||
link: 'https://vercel.com/docs/configuration#project/rewrites',
|
||||
link: 'https://vercel.com/docs/concepts/projects/project-configuration#rewrites',
|
||||
action: 'View Documentation',
|
||||
});
|
||||
const configJson = await fs.readJSON(join(output, 'config.json'));
|
||||
@@ -1104,32 +1104,46 @@ describe('build', () => {
|
||||
|
||||
it('should include crons property in build output', async () => {
|
||||
const cwd = fixture('with-cron');
|
||||
const output = join(cwd, '.vercel', 'output', 'functions', 'api');
|
||||
const output = join(cwd, '.vercel', 'output');
|
||||
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
const exitCode = await build(client);
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const edge = await fs.readJSON(
|
||||
join(output, 'edge.func', '.vc-config.json')
|
||||
);
|
||||
expect(edge).toHaveProperty('cron', '* * * * *');
|
||||
const config = await fs.readJSON(join(output, 'config.json'));
|
||||
expect(config).toHaveProperty('crons', [
|
||||
{
|
||||
path: '/api/cron-job',
|
||||
schedule: '0 0 * * *',
|
||||
},
|
||||
]);
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
delete process.env.__VERCEL_BUILD_RUNNING;
|
||||
}
|
||||
});
|
||||
|
||||
const serverless = await fs.readJSON(
|
||||
join(output, 'serverless.func', '.vc-config.json')
|
||||
);
|
||||
expect(serverless).toHaveProperty('cron', '* * * * *');
|
||||
it('should merge crons property from build output with vercel.json crons property', async () => {
|
||||
const cwd = fixture('with-cron-merge');
|
||||
const output = join(cwd, '.vercel', 'output');
|
||||
|
||||
const overwriteServerless = await fs.readJSON(
|
||||
join(output, 'overwrite', 'serverless.func', '.vc-config.json')
|
||||
);
|
||||
expect(overwriteServerless).toHaveProperty('cron', '0 10-20 * * *');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
const exitCode = await build(client);
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const overwriteEdge = await fs.readJSON(
|
||||
join(output, 'overwrite', 'edge.func', '.vc-config.json')
|
||||
);
|
||||
expect(overwriteEdge).toHaveProperty('cron', '10 * * * *');
|
||||
const config = await fs.readJSON(join(output, 'config.json'));
|
||||
expect(config).toHaveProperty('crons', [
|
||||
{
|
||||
path: '/api/cron-job',
|
||||
schedule: '0 0 * * *',
|
||||
},
|
||||
{
|
||||
path: '/api/cron-job-build-output',
|
||||
schedule: '0 0 * * *',
|
||||
},
|
||||
]);
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
delete process.env.__VERCEL_BUILD_RUNNING;
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `rewrites[0]` should NOT have additional property `src`. Did you mean `source`?'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/rewrites'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#rewrites'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -54,7 +54,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `routes[0]` should NOT have additional property `source`. Did you mean `src`?'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/routes'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#routes'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -67,7 +67,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `routes` should be array.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/routes'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#routes'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -84,7 +84,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `redirects[0]` missing required property `source`.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/redirects'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#redirects'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -97,7 +97,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `redirects[0].permanent` should be boolean.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/redirects'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#redirects'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -110,7 +110,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `cleanUrls` should be boolean.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/cleanurls'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#cleanurls'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -123,7 +123,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `trailingSlash` should be boolean.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/trailingslash'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#trailingslash'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -136,7 +136,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `headers[0]` should NOT have additional property `Content-Type`. Please remove it.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/headers'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -149,7 +149,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `headers[0].source` should be string.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/headers'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -162,7 +162,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `headers[0]` should NOT have additional property `stuff`. Please remove it.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/headers'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -175,7 +175,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `headers[0].headers[0]` should NOT have additional property `Content-Type`. Please remove it.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/headers'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -190,7 +190,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `headers[0].headers[0]` should NOT have additional property `val`. Please remove it.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/headers'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -205,7 +205,7 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `redirects` should NOT have more than 1024 items.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/redirects'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#redirects'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -229,7 +229,39 @@ describe('validateConfig', () => {
|
||||
'Invalid vercel.json - `headers[1].headers` should NOT have more than 1024 items.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/configuration#project/headers'
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
|
||||
);
|
||||
});
|
||||
|
||||
it('should error with too low memory value', async () => {
|
||||
const error = validateConfig({
|
||||
functions: {
|
||||
'api/test.js': {
|
||||
memory: 127,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(error!.message).toEqual(
|
||||
"Invalid vercel.json - `functions['api/test.js'].memory` should be >= 128."
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#functions'
|
||||
);
|
||||
});
|
||||
|
||||
it('should error with too high memory value', async () => {
|
||||
const error = validateConfig({
|
||||
functions: {
|
||||
'api/test.js': {
|
||||
memory: 3009,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(error!.message).toEqual(
|
||||
"Invalid vercel.json - `functions['api/test.js'].memory` should be <= 3008."
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#functions'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -253,4 +285,90 @@ describe('validateConfig', () => {
|
||||
|
||||
expect(error!.link).toEqual('https://vercel.link/functions-and-builds');
|
||||
});
|
||||
|
||||
it('should error when crons have missing schedule', () => {
|
||||
const error = validateConfig({
|
||||
// @ts-ignore
|
||||
crons: [{ path: '/api/test.js' }],
|
||||
});
|
||||
expect(error!.message).toEqual(
|
||||
'Invalid vercel.json - `crons[0]` missing required property `schedule`.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#crons'
|
||||
);
|
||||
});
|
||||
|
||||
it('should error when crons have missing path', () => {
|
||||
const error = validateConfig({
|
||||
// @ts-ignore
|
||||
crons: [{ schedule: '* * * * *' }],
|
||||
});
|
||||
expect(error!.message).toEqual(
|
||||
'Invalid vercel.json - `crons[0]` missing required property `path`.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#crons'
|
||||
);
|
||||
});
|
||||
|
||||
it('should error when path is too long', () => {
|
||||
const error = validateConfig({
|
||||
crons: [{ path: '/' + 'x'.repeat(512), schedule: '* * * * *' }],
|
||||
});
|
||||
expect(error!.message).toEqual(
|
||||
'Invalid vercel.json - `crons[0].path` should NOT be longer than 512 characters.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#crons'
|
||||
);
|
||||
});
|
||||
|
||||
it('should error when schedule is too long', () => {
|
||||
const error = validateConfig({
|
||||
crons: [{ path: '/', schedule: '*'.repeat(257) }],
|
||||
});
|
||||
expect(error!.message).toEqual(
|
||||
'Invalid vercel.json - `crons[0].schedule` should NOT be longer than 256 characters.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#crons'
|
||||
);
|
||||
});
|
||||
|
||||
it('should error when path is empty', () => {
|
||||
const error = validateConfig({
|
||||
crons: [{ path: '', schedule: '* * * * *' }],
|
||||
});
|
||||
expect(error!.message).toEqual(
|
||||
'Invalid vercel.json - `crons[0].path` should NOT be shorter than 1 characters.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#crons'
|
||||
);
|
||||
});
|
||||
|
||||
it('should error when schedule is too short', () => {
|
||||
const error = validateConfig({
|
||||
crons: [{ path: '/', schedule: '* * * * ' }],
|
||||
});
|
||||
expect(error!.message).toEqual(
|
||||
'Invalid vercel.json - `crons[0].schedule` should NOT be shorter than 9 characters.'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#crons'
|
||||
);
|
||||
});
|
||||
|
||||
it("should error when path doesn't start with `/`", () => {
|
||||
const error = validateConfig({
|
||||
crons: [{ path: 'api/cron', schedule: '* * * * *' }],
|
||||
});
|
||||
expect(error!.message).toEqual(
|
||||
'Invalid vercel.json - `crons[0].path` should match pattern "^/.*".'
|
||||
);
|
||||
expect(error!.link).toEqual(
|
||||
'https://vercel.com/docs/concepts/projects/project-configuration#crons'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "12.3.8",
|
||||
"version": "12.4.0",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test-integration-once": "pnpm test tests/create-deployment.test.ts tests/create-legacy-deployment.test.ts tests/paths.test.ts",
|
||||
"test-e2e": "pnpm test tests/create-deployment.test.ts tests/create-legacy-deployment.test.ts tests/paths.test.ts",
|
||||
"test": "jest --env node --verbose --runInBand --bail",
|
||||
"test-unit": "pnpm test tests/unit.*test.*"
|
||||
},
|
||||
@@ -43,8 +43,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "6.2.2",
|
||||
"@vercel/routing-utils": "2.1.8",
|
||||
"@vercel/build-utils": "6.3.0",
|
||||
"@vercel/routing-utils": "2.1.9",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "3.0.0",
|
||||
|
||||
@@ -3,6 +3,7 @@ import type {
|
||||
BuilderFunctions,
|
||||
Images,
|
||||
ProjectSettings,
|
||||
Cron,
|
||||
} from '@vercel/build-utils';
|
||||
import type { Header, Route, Redirect, Rewrite } from '@vercel/routing-utils';
|
||||
|
||||
@@ -154,6 +155,7 @@ export interface VercelConfig {
|
||||
framework?: string | null;
|
||||
outputDirectory?: string | null;
|
||||
images?: Images;
|
||||
crons?: Cron[];
|
||||
}
|
||||
|
||||
export interface GitMetadata {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/frameworks",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.1",
|
||||
"main": "./dist/frameworks.js",
|
||||
"types": "./dist/frameworks.d.ts",
|
||||
"files": [
|
||||
@@ -21,7 +21,7 @@
|
||||
"@types/js-yaml": "3.12.1",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/node-fetch": "2.5.8",
|
||||
"@vercel/routing-utils": "2.1.8",
|
||||
"@vercel/routing-utils": "2.1.9",
|
||||
"ajv": "6.12.2",
|
||||
"typescript": "4.3.4"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/fs-detectors",
|
||||
"version": "3.7.11",
|
||||
"version": "3.8.0",
|
||||
"description": "Vercel filesystem detectors",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -20,8 +20,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/error-utils": "1.0.8",
|
||||
"@vercel/frameworks": "1.3.0",
|
||||
"@vercel/routing-utils": "2.1.8",
|
||||
"@vercel/frameworks": "1.3.1",
|
||||
"@vercel/routing-utils": "2.1.9",
|
||||
"glob": "8.0.3",
|
||||
"js-yaml": "4.1.0",
|
||||
"json5": "2.2.2",
|
||||
@@ -35,7 +35,7 @@
|
||||
"@types/minimatch": "3.0.5",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/semver": "7.3.10",
|
||||
"@vercel/build-utils": "6.2.2",
|
||||
"@vercel/build-utils": "6.3.0",
|
||||
"typescript": "4.3.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,12 +602,11 @@ function validateFunctions({ functions = {} }: Options) {
|
||||
|
||||
if (
|
||||
func.memory !== undefined &&
|
||||
(func.memory < 128 || func.memory > 3008 || func.memory % 64 !== 0)
|
||||
(func.memory < 128 || func.memory > 3008)
|
||||
) {
|
||||
return {
|
||||
code: 'invalid_function_memory',
|
||||
message:
|
||||
'Functions must have a memory value between 128 and 3008 in steps of 64.',
|
||||
message: 'Functions must have a memory value between 128 and 3008',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -473,7 +473,7 @@ describe('Test `detectBuilders`', () => {
|
||||
});
|
||||
|
||||
it('invalid function memory', async () => {
|
||||
const functions = { 'pages/index.ts': { memory: 200 } };
|
||||
const functions = { 'pages/index.ts': { memory: 127 } };
|
||||
const files = ['pages/index.ts'];
|
||||
const { builders, errors } = await detectBuilders(files, null, {
|
||||
functions,
|
||||
@@ -484,6 +484,17 @@ describe('Test `detectBuilders`', () => {
|
||||
expect(errors![0].code).toBe('invalid_function_memory');
|
||||
});
|
||||
|
||||
it('should build with function memory not dividable by 64', async () => {
|
||||
const functions = { 'api/index.ts': { memory: 1000 } };
|
||||
const files = ['api/index.ts'];
|
||||
const { builders, errors } = await detectBuilders(files, null, {
|
||||
functions,
|
||||
});
|
||||
|
||||
expect(builders![0].use).toBe('@vercel/node');
|
||||
expect(errors).toBeNull();
|
||||
});
|
||||
|
||||
it('missing runtime version', async () => {
|
||||
const functions = { 'pages/index.ts': { runtime: 'haha' } };
|
||||
const files = ['pages/index.ts'];
|
||||
@@ -1720,7 +1731,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
|
||||
});
|
||||
|
||||
it('invalid function memory', async () => {
|
||||
const functions = { 'pages/index.ts': { memory: 200 } };
|
||||
const functions = { 'pages/index.ts': { memory: 127 } };
|
||||
const files = ['pages/index.ts'];
|
||||
const { builders, errors } = await detectBuilders(files, null, {
|
||||
functions,
|
||||
@@ -1732,6 +1743,18 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
|
||||
expect(errors![0].code).toBe('invalid_function_memory');
|
||||
});
|
||||
|
||||
it('should build with function memory not dividable by 64', async () => {
|
||||
const functions = { 'api/index.ts': { memory: 1000 } };
|
||||
const files = ['api/index.ts'];
|
||||
const { builders, errors } = await detectBuilders(files, null, {
|
||||
functions,
|
||||
featHandleMiss,
|
||||
});
|
||||
|
||||
expect(builders![0].use).toBe('@vercel/node');
|
||||
expect(errors).toBeNull();
|
||||
});
|
||||
|
||||
it('missing runtime version', async () => {
|
||||
const functions = { 'pages/index.ts': { runtime: 'haha' } };
|
||||
const files = ['pages/index.ts'];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/gatsby-plugin-vercel-builder",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.7",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist",
|
||||
@@ -14,9 +14,9 @@
|
||||
"build:src": "tsc -p tsconfig.src.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "6.2.2",
|
||||
"@vercel/node": "2.9.3",
|
||||
"@vercel/routing-utils": "2.1.8",
|
||||
"@vercel/build-utils": "6.3.0",
|
||||
"@vercel/node": "2.9.6",
|
||||
"@vercel/routing-utils": "2.1.9",
|
||||
"ajv": "8.12.0",
|
||||
"esbuild": "0.14.47",
|
||||
"etag": "1.8.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "2.3.4",
|
||||
"version": "2.3.7",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
@@ -12,7 +12,7 @@
|
||||
"scripts": {
|
||||
"build": "node build",
|
||||
"test": "jest --env node --verbose --runInBand --bail",
|
||||
"test-integration-once": "pnpm test"
|
||||
"test-e2e": "pnpm test"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
@@ -36,7 +36,7 @@
|
||||
"@types/node": "14.18.33",
|
||||
"@types/node-fetch": "^2.3.0",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@vercel/build-utils": "6.2.2",
|
||||
"@vercel/build-utils": "6.3.0",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"async-retry": "1.3.1",
|
||||
"execa": "^1.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/hydrogen",
|
||||
"version": "0.0.50",
|
||||
"version": "0.0.53",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -11,7 +11,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node build.js",
|
||||
"test-integration-once": "pnpm test test/test.js",
|
||||
"test-e2e": "pnpm test test/test.js",
|
||||
"test": "jest --env node --verbose --bail --runInBand"
|
||||
},
|
||||
"files": [
|
||||
@@ -21,8 +21,8 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "14.18.33",
|
||||
"@vercel/build-utils": "6.2.2",
|
||||
"@vercel/static-config": "2.0.12",
|
||||
"@vercel/build-utils": "6.3.0",
|
||||
"@vercel/static-config": "2.0.13",
|
||||
"execa": "3.2.0",
|
||||
"fs-extra": "11.1.0",
|
||||
"ts-morph": "12.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/next",
|
||||
"version": "3.4.3",
|
||||
"version": "3.5.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||
@@ -11,7 +11,7 @@
|
||||
"test-unit": "pnpm test test/unit/",
|
||||
"test-next-local": "pnpm test test/integration/*.test.js test/integration/*.test.ts",
|
||||
"test-next-local:middleware": "pnpm test test/integration/middleware.test.ts",
|
||||
"test-integration-once": "rm -f test/builder-info.json; pnpm test test/fixtures/**/*.test.js"
|
||||
"test-e2e": "rm -f test/builder-info.json; pnpm test test/fixtures/**/*.test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -45,9 +45,9 @@
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/text-table": "0.2.1",
|
||||
"@types/webpack-sources": "3.2.0",
|
||||
"@vercel/build-utils": "6.2.2",
|
||||
"@vercel/build-utils": "6.3.0",
|
||||
"@vercel/nft": "0.22.5",
|
||||
"@vercel/routing-utils": "2.1.8",
|
||||
"@vercel/routing-utils": "2.1.9",
|
||||
"async-sema": "3.0.1",
|
||||
"buffer-crc32": "0.2.13",
|
||||
"bytes": "3.1.2",
|
||||
|
||||
@@ -88,6 +88,8 @@ import {
|
||||
PseudoLayerResult,
|
||||
updateRouteSrc,
|
||||
validateEntrypoint,
|
||||
getOperationType,
|
||||
isApiPage,
|
||||
} from './utils';
|
||||
|
||||
export const version = 2;
|
||||
@@ -1090,10 +1092,14 @@ export const build: BuildV2 = async ({
|
||||
handler: '___next_launcher.cjs',
|
||||
runtime: nodeVersion.runtime,
|
||||
...lambdaOptions,
|
||||
operationType: 'SSR',
|
||||
operationType: 'SSR', // always SSR because we're in legacy mode
|
||||
shouldAddHelpers: false,
|
||||
shouldAddSourcemapSupport: false,
|
||||
supportsMultiPayloads: !!process.env.NEXT_PRIVATE_MULTI_PAYLOAD,
|
||||
framework: {
|
||||
slug: 'nextjs',
|
||||
version: nextVersion,
|
||||
},
|
||||
});
|
||||
debug(`Created serverless function for page: "${page}"`);
|
||||
})
|
||||
@@ -1122,10 +1128,6 @@ export const build: BuildV2 = async ({
|
||||
outputDirectory,
|
||||
appPathRoutesManifest,
|
||||
});
|
||||
const isApiPage = (page: string) =>
|
||||
page
|
||||
.replace(/\\/g, '/')
|
||||
.match(/(serverless|server)\/pages\/api(\/|\.js$)/);
|
||||
|
||||
const canUsePreviewMode = Object.keys(pages).some(page =>
|
||||
isApiPage(pages[page].fsPath)
|
||||
@@ -1594,6 +1596,10 @@ export const build: BuildV2 = async ({
|
||||
internalPages: [],
|
||||
});
|
||||
|
||||
for (const group of initialApiLambdaGroups) {
|
||||
group.isApiLambda = true;
|
||||
}
|
||||
|
||||
debug(
|
||||
JSON.stringify(
|
||||
{
|
||||
@@ -1815,7 +1821,12 @@ export const build: BuildV2 = async ({
|
||||
path.relative(baseDir, entryPath),
|
||||
'___next_launcher.cjs'
|
||||
),
|
||||
operationType: getOperationType({
|
||||
prerenderManifest,
|
||||
pageFileName,
|
||||
}),
|
||||
runtime: nodeVersion.runtime,
|
||||
nextVersion,
|
||||
...lambdaOptions,
|
||||
});
|
||||
} else {
|
||||
@@ -1834,7 +1845,9 @@ export const build: BuildV2 = async ({
|
||||
path.relative(baseDir, entryPath),
|
||||
'___next_launcher.cjs'
|
||||
),
|
||||
operationType: getOperationType({ pageFileName }), // can only be API or SSR
|
||||
runtime: nodeVersion.runtime,
|
||||
nextVersion,
|
||||
...lambdaOptions,
|
||||
});
|
||||
}
|
||||
@@ -2034,6 +2047,11 @@ export const build: BuildV2 = async ({
|
||||
pageLambdaMap[page] = group.lambdaIdentifier;
|
||||
}
|
||||
|
||||
const operationType = getOperationType({
|
||||
group,
|
||||
prerenderManifest,
|
||||
});
|
||||
|
||||
lambdas[group.lambdaIdentifier] =
|
||||
await createLambdaFromPseudoLayers({
|
||||
files: {
|
||||
@@ -2045,7 +2063,9 @@ export const build: BuildV2 = async ({
|
||||
path.relative(baseDir, entryPath),
|
||||
'___next_launcher.cjs'
|
||||
),
|
||||
operationType,
|
||||
runtime: nodeVersion.runtime,
|
||||
nextVersion,
|
||||
});
|
||||
}
|
||||
)
|
||||
@@ -2096,6 +2116,8 @@ export const build: BuildV2 = async ({
|
||||
...Object.entries(prerenderManifest.fallbackRoutes),
|
||||
...Object.entries(prerenderManifest.blockingFallbackRoutes),
|
||||
].forEach(([, { dataRouteRegex, dataRoute }]) => {
|
||||
if (!dataRoute || !dataRouteRegex) return;
|
||||
|
||||
dataRoutes.push({
|
||||
// Next.js provided data route regex
|
||||
src: dataRouteRegex.replace(
|
||||
@@ -2644,7 +2666,10 @@ async function getServerlessPages(params: {
|
||||
const [pages, appPaths, middlewareManifest] = await Promise.all([
|
||||
glob('**/!(_middleware).js', params.pagesDir),
|
||||
params.appPathRoutesManifest
|
||||
? glob('**/page.js', path.join(params.pagesDir, '../app'))
|
||||
? Promise.all([
|
||||
glob('**/page.js', path.join(params.pagesDir, '../app')),
|
||||
glob('**/route.js', path.join(params.pagesDir, '../app')),
|
||||
]).then(items => Object.assign(...items))
|
||||
: Promise.resolve({}),
|
||||
getMiddlewareManifest(params.entryPath, params.outputDirectory),
|
||||
]);
|
||||
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
getMiddlewareBundle,
|
||||
getFilesMapFromReasons,
|
||||
UnwrapPromise,
|
||||
getOperationType,
|
||||
} from './utils';
|
||||
import {
|
||||
nodeFileTrace,
|
||||
@@ -181,7 +182,10 @@ export async function serverBuild({
|
||||
}
|
||||
|
||||
const pageMatchesApi = (page: string) => {
|
||||
return page.startsWith('api/') || page === 'api.js';
|
||||
return (
|
||||
!appPathRoutesManifest?.[page] &&
|
||||
(page.startsWith('api/') || page === 'api.js')
|
||||
);
|
||||
};
|
||||
|
||||
const { i18n } = routesManifest;
|
||||
@@ -748,6 +752,10 @@ export async function serverBuild({
|
||||
internalPages,
|
||||
});
|
||||
|
||||
for (const group of apiLambdaGroups) {
|
||||
group.isApiLambda = true;
|
||||
}
|
||||
|
||||
debug(
|
||||
JSON.stringify(
|
||||
{
|
||||
@@ -856,6 +864,8 @@ export async function serverBuild({
|
||||
}
|
||||
}
|
||||
|
||||
const operationType = getOperationType({ group, prerenderManifest });
|
||||
|
||||
const lambda = await createLambdaFromPseudoLayers({
|
||||
files: {
|
||||
...launcherFiles,
|
||||
@@ -869,11 +879,12 @@ export async function serverBuild({
|
||||
),
|
||||
'___next_launcher.cjs'
|
||||
),
|
||||
operationType,
|
||||
memory: group.memory,
|
||||
runtime: nodeVersion.runtime,
|
||||
maxDuration: group.maxDuration,
|
||||
isStreaming: group.isStreaming,
|
||||
cron: group.cron,
|
||||
nextVersion,
|
||||
});
|
||||
|
||||
for (const page of group.pages) {
|
||||
@@ -974,6 +985,7 @@ export async function serverBuild({
|
||||
routesManifest,
|
||||
isCorrectMiddlewareOrder,
|
||||
prerenderBypassToken: prerenderManifest.bypassToken || '',
|
||||
nextVersion,
|
||||
});
|
||||
|
||||
const isNextDataServerResolving =
|
||||
@@ -1127,8 +1139,19 @@ export async function serverBuild({
|
||||
// to match prerenders so we can route the same when the
|
||||
// __rsc__ header is present
|
||||
const edgeFunctions = middleware.edgeFunctions;
|
||||
// allow looking up original route from normalized route
|
||||
const inverseAppPathManifest: Record<string, string> = {};
|
||||
|
||||
for (const ogRoute of Object.keys(appPathRoutesManifest)) {
|
||||
inverseAppPathManifest[appPathRoutesManifest[ogRoute]] = ogRoute;
|
||||
}
|
||||
|
||||
for (let route of Object.values(appPathRoutesManifest)) {
|
||||
const ogRoute = inverseAppPathManifest[route];
|
||||
|
||||
if (ogRoute.endsWith('/route')) {
|
||||
continue;
|
||||
}
|
||||
route = path.posix.join('./', route === '/' ? '/index' : route);
|
||||
|
||||
if (lambdas[route]) {
|
||||
@@ -1141,6 +1164,10 @@ export async function serverBuild({
|
||||
}
|
||||
|
||||
const rscHeader = routesManifest.rsc?.header?.toLowerCase() || '__rsc__';
|
||||
const rscVaryHeader =
|
||||
routesManifest?.rsc?.varyHeader ||
|
||||
'RSC, Next-Router-State-Tree, Next-Router-Prefetch';
|
||||
|
||||
const completeDynamicRoutes: typeof dynamicRoutes = [];
|
||||
|
||||
if (appDir) {
|
||||
@@ -1413,7 +1440,9 @@ export async function serverBuild({
|
||||
},
|
||||
],
|
||||
dest: path.posix.join('/', entryDirectory, '/index.rsc'),
|
||||
headers: { vary: rscVaryHeader },
|
||||
continue: true,
|
||||
override: true,
|
||||
},
|
||||
{
|
||||
src: `^${path.posix.join(
|
||||
@@ -1428,7 +1457,9 @@ export async function serverBuild({
|
||||
},
|
||||
],
|
||||
dest: path.posix.join('/', entryDirectory, '/$1.rsc'),
|
||||
headers: { vary: rscVaryHeader },
|
||||
continue: true,
|
||||
override: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
NodejsLambda,
|
||||
EdgeFunction,
|
||||
Images,
|
||||
Cron,
|
||||
} from '@vercel/build-utils';
|
||||
import { NodeFileTraceReasons } from '@vercel/nft';
|
||||
import type {
|
||||
@@ -269,12 +268,7 @@ export async function getRoutesManifest(
|
||||
|
||||
if (shouldHaveManifest && !hasRoutesManifest) {
|
||||
throw new NowBuildError({
|
||||
message:
|
||||
`The file "${pathRoutesManifest}" couldn't be found. This is normally caused by a misconfiguration in your project.\n` +
|
||||
'Please check the following, and reach out to support if you cannot resolve the problem:\n' +
|
||||
' 1. If present, be sure your `build` script in "package.json" calls `next build`.' +
|
||||
' 2. Navigate to your project\'s settings in the Vercel dashboard, and verify that the "Build Command" is not overridden, or that it calls `next build`.' +
|
||||
' 3. Navigate to your project\'s settings in the Vercel dashboard, and verify that the "Output Directory" is not overridden. Note that `next export` does **not** require you change this setting, even if you customize the `next export` output directory.',
|
||||
message: `The file "${pathRoutesManifest}" couldn't be found. This is often caused by a misconfiguration in your project.`,
|
||||
link: 'https://err.sh/vercel/vercel/now-next-routes-manifest',
|
||||
code: 'NEXT_NO_ROUTES_MANIFEST',
|
||||
});
|
||||
@@ -780,6 +774,7 @@ export async function createPseudoLayer(files: {
|
||||
interface CreateLambdaFromPseudoLayersOptions extends LambdaOptionsWithFiles {
|
||||
layers: PseudoLayer[];
|
||||
isStreaming?: boolean;
|
||||
nextVersion?: string;
|
||||
}
|
||||
|
||||
// measured with 1, 2, 5, 10, and `os.cpus().length || 5`
|
||||
@@ -790,6 +785,7 @@ export async function createLambdaFromPseudoLayers({
|
||||
files: baseFiles,
|
||||
layers,
|
||||
isStreaming,
|
||||
nextVersion,
|
||||
...lambdaOptions
|
||||
}: CreateLambdaFromPseudoLayersOptions) {
|
||||
await createLambdaSema.acquire();
|
||||
@@ -833,6 +829,10 @@ export async function createLambdaFromPseudoLayers({
|
||||
shouldAddHelpers: false,
|
||||
shouldAddSourcemapSupport: false,
|
||||
supportsMultiPayloads: !!process.env.NEXT_PRIVATE_MULTI_PAYLOAD,
|
||||
framework: {
|
||||
slug: 'nextjs',
|
||||
version: nextVersion,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -849,16 +849,18 @@ export type NextPrerenderedRoutes = {
|
||||
staticRoutes: {
|
||||
[route: string]: {
|
||||
initialRevalidate: number | false;
|
||||
dataRoute: string;
|
||||
dataRoute: string | null;
|
||||
srcRoute: string | null;
|
||||
initialStatus?: number;
|
||||
initialHeaders?: Record<string, string>;
|
||||
};
|
||||
};
|
||||
|
||||
blockingFallbackRoutes: {
|
||||
[route: string]: {
|
||||
routeRegex: string;
|
||||
dataRoute: string;
|
||||
dataRouteRegex: string;
|
||||
dataRoute: string | null;
|
||||
dataRouteRegex: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -866,16 +868,16 @@ export type NextPrerenderedRoutes = {
|
||||
[route: string]: {
|
||||
fallback: string;
|
||||
routeRegex: string;
|
||||
dataRoute: string;
|
||||
dataRouteRegex: string;
|
||||
dataRoute: string | null;
|
||||
dataRouteRegex: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
omittedRoutes: {
|
||||
[route: string]: {
|
||||
routeRegex: string;
|
||||
dataRoute: string;
|
||||
dataRouteRegex: string;
|
||||
dataRoute: string | null;
|
||||
dataRouteRegex: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1068,6 +1070,30 @@ export async function getPrerenderManifest(
|
||||
previewModeId: string;
|
||||
};
|
||||
notFoundRoutes?: string[];
|
||||
}
|
||||
| {
|
||||
version: 4;
|
||||
routes: {
|
||||
[route: string]: {
|
||||
initialRevalidateSeconds: number | false;
|
||||
srcRoute: string | null;
|
||||
dataRoute: string | null;
|
||||
initialStatus?: number;
|
||||
initialHeaders?: Record<string, string>;
|
||||
};
|
||||
};
|
||||
dynamicRoutes: {
|
||||
[route: string]: {
|
||||
routeRegex: string;
|
||||
fallback: string | false;
|
||||
dataRoute: string | null;
|
||||
dataRouteRegex: string | null;
|
||||
};
|
||||
};
|
||||
preview: {
|
||||
previewModeId: string;
|
||||
};
|
||||
notFoundRoutes?: string[];
|
||||
} = JSON.parse(await fs.readFile(pathPrerenderManifest, 'utf8'));
|
||||
|
||||
switch (manifest.version) {
|
||||
@@ -1122,7 +1148,8 @@ export async function getPrerenderManifest(
|
||||
return ret;
|
||||
}
|
||||
case 2:
|
||||
case 3: {
|
||||
case 3:
|
||||
case 4: {
|
||||
const routes = Object.keys(manifest.routes);
|
||||
const lazyRoutes = Object.keys(manifest.dynamicRoutes);
|
||||
|
||||
@@ -1143,6 +1170,15 @@ export async function getPrerenderManifest(
|
||||
routes.forEach(route => {
|
||||
const { initialRevalidateSeconds, dataRoute, srcRoute } =
|
||||
manifest.routes[route];
|
||||
|
||||
let initialStatus: undefined | number;
|
||||
let initialHeaders: undefined | Record<string, string>;
|
||||
|
||||
if (manifest.version === 4) {
|
||||
initialStatus = manifest.routes[route].initialStatus;
|
||||
initialHeaders = manifest.routes[route].initialHeaders;
|
||||
}
|
||||
|
||||
ret.staticRoutes[route] = {
|
||||
initialRevalidate:
|
||||
initialRevalidateSeconds === false
|
||||
@@ -1150,6 +1186,8 @@ export async function getPrerenderManifest(
|
||||
: Math.max(1, initialRevalidateSeconds),
|
||||
dataRoute,
|
||||
srcRoute,
|
||||
initialStatus,
|
||||
initialHeaders,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1310,10 +1348,10 @@ export function addLocaleOrDefault(
|
||||
export type LambdaGroup = {
|
||||
pages: string[];
|
||||
memory?: number;
|
||||
cron?: Cron;
|
||||
maxDuration?: number;
|
||||
isStreaming?: boolean;
|
||||
isPrerenders?: boolean;
|
||||
isApiLambda: boolean;
|
||||
pseudoLayer: PseudoLayer;
|
||||
pseudoLayerBytes: number;
|
||||
pseudoLayerUncompressedBytes: number;
|
||||
@@ -1363,7 +1401,7 @@ export async function getPageLambdaGroups({
|
||||
const routeName = normalizePage(page.replace(/\.js$/, ''));
|
||||
const isPrerenderRoute = prerenderRoutes.has(routeName);
|
||||
|
||||
let opts: { memory?: number; maxDuration?: number; cron?: Cron } = {};
|
||||
let opts: { memory?: number; maxDuration?: number } = {};
|
||||
|
||||
if (config && config.functions) {
|
||||
const sourceFile = await getSourceFilePathFromPage({
|
||||
@@ -1381,8 +1419,7 @@ export async function getPageLambdaGroups({
|
||||
const matches =
|
||||
group.maxDuration === opts.maxDuration &&
|
||||
group.memory === opts.memory &&
|
||||
group.isPrerenders === isPrerenderRoute &&
|
||||
!opts.cron; // Functions with a cronjob must be on their own
|
||||
group.isPrerenders === isPrerenderRoute;
|
||||
|
||||
if (matches) {
|
||||
let newTracedFilesSize = group.pseudoLayerBytes;
|
||||
@@ -1421,6 +1458,7 @@ export async function getPageLambdaGroups({
|
||||
pages: [page],
|
||||
...opts,
|
||||
isPrerenders: isPrerenderRoute,
|
||||
isApiLambda: !!isApiPage(page),
|
||||
pseudoLayerBytes: initialPseudoLayer.pseudoLayerBytes,
|
||||
pseudoLayerUncompressedBytes: initialPseudoLayerUncompressed,
|
||||
pseudoLayer: Object.assign({}, initialPseudoLayer.pseudoLayer),
|
||||
@@ -1652,7 +1690,7 @@ export const onPrerenderRouteInitial = (
|
||||
const { initialRevalidate, srcRoute, dataRoute } = pr;
|
||||
const route = srcRoute || routeKey;
|
||||
|
||||
const isAppPathRoute = appDir && dataRoute?.endsWith('.rsc');
|
||||
const isAppPathRoute = appDir && (!dataRoute || dataRoute?.endsWith('.rsc'));
|
||||
|
||||
const routeNoLocale = routesManifest?.i18n
|
||||
? normalizeLocalePath(routeKey, routesManifest.i18n.locales).pathname
|
||||
@@ -1810,7 +1848,9 @@ export const onPrerenderRoute =
|
||||
|
||||
let initialRevalidate: false | number;
|
||||
let srcRoute: string | null;
|
||||
let dataRoute: string;
|
||||
let dataRoute: string | null;
|
||||
let initialStatus: number | undefined;
|
||||
let initialHeaders: Record<string, string> | undefined;
|
||||
|
||||
if (isFallback || isBlocking) {
|
||||
const pr = isFallback
|
||||
@@ -1833,44 +1873,60 @@ export const onPrerenderRoute =
|
||||
dataRoute = prerenderManifest.omittedRoutes[routeKey].dataRoute;
|
||||
} else {
|
||||
const pr = prerenderManifest.staticRoutes[routeKey];
|
||||
({ initialRevalidate, srcRoute, dataRoute } = pr);
|
||||
({
|
||||
initialRevalidate,
|
||||
srcRoute,
|
||||
dataRoute,
|
||||
initialHeaders,
|
||||
initialStatus,
|
||||
} = pr);
|
||||
}
|
||||
|
||||
let isAppPathRoute = false;
|
||||
// TODO: leverage manifest to determine app paths more accurately
|
||||
if (appDir && srcRoute && dataRoute.endsWith('.rsc')) {
|
||||
if (appDir && srcRoute && (!dataRoute || dataRoute?.endsWith('.rsc'))) {
|
||||
isAppPathRoute = true;
|
||||
}
|
||||
|
||||
const isOmittedOrNotFound = isOmitted || isNotFound;
|
||||
const htmlFsRef =
|
||||
isBlocking || (isNotFound && !static404Page)
|
||||
? // Blocking pages do not have an HTML fallback
|
||||
null
|
||||
: new FileFsRef({
|
||||
fsPath: path.join(
|
||||
isAppPathRoute && !isOmittedOrNotFound && appDir
|
||||
? appDir
|
||||
: pagesDir,
|
||||
isFallback
|
||||
? // Fallback pages have a special file.
|
||||
addLocaleOrDefault(
|
||||
prerenderManifest.fallbackRoutes[routeKey].fallback,
|
||||
routesManifest,
|
||||
locale
|
||||
)
|
||||
: // Otherwise, the route itself should exist as a static HTML
|
||||
// file.
|
||||
`${
|
||||
isOmittedOrNotFound
|
||||
? addLocaleOrDefault('/404', routesManifest, locale)
|
||||
: routeFileNoExt
|
||||
}.html`
|
||||
),
|
||||
});
|
||||
let htmlFsRef: FileFsRef | null;
|
||||
|
||||
if (appDir && !dataRoute && isAppPathRoute && !(isBlocking || isFallback)) {
|
||||
const contentType = initialHeaders?.['content-type'];
|
||||
htmlFsRef = new FileFsRef({
|
||||
fsPath: path.join(appDir, `${routeFileNoExt}.body`),
|
||||
contentType: contentType || 'text/html;charset=utf-8',
|
||||
});
|
||||
} else {
|
||||
htmlFsRef =
|
||||
isBlocking || (isNotFound && !static404Page)
|
||||
? // Blocking pages do not have an HTML fallback
|
||||
null
|
||||
: new FileFsRef({
|
||||
fsPath: path.join(
|
||||
isAppPathRoute && !isOmittedOrNotFound && appDir
|
||||
? appDir
|
||||
: pagesDir,
|
||||
isFallback
|
||||
? // Fallback pages have a special file.
|
||||
addLocaleOrDefault(
|
||||
prerenderManifest.fallbackRoutes[routeKey].fallback,
|
||||
routesManifest,
|
||||
locale
|
||||
)
|
||||
: // Otherwise, the route itself should exist as a static HTML
|
||||
// file.
|
||||
`${
|
||||
isOmittedOrNotFound
|
||||
? addLocaleOrDefault('/404', routesManifest, locale)
|
||||
: routeFileNoExt
|
||||
}.html`
|
||||
),
|
||||
});
|
||||
}
|
||||
const jsonFsRef =
|
||||
// JSON data does not exist for fallback or blocking pages
|
||||
isFallback || isBlocking || (isNotFound && !static404Page)
|
||||
isFallback || isBlocking || (isNotFound && !static404Page) || !dataRoute
|
||||
? null
|
||||
: new FileFsRef({
|
||||
fsPath: path.join(
|
||||
@@ -1908,16 +1964,20 @@ export const onPrerenderRoute =
|
||||
);
|
||||
|
||||
let lambda: undefined | Lambda;
|
||||
let outputPathData = path.posix.join(entryDirectory, dataRoute);
|
||||
let outputPathData: null | string = null;
|
||||
|
||||
if (nonDynamicSsg || isFallback || isOmitted) {
|
||||
outputPathData = outputPathData.replace(
|
||||
new RegExp(`${escapeStringRegexp(origRouteFileNoExt)}.json$`),
|
||||
// ensure we escape "$" correctly while replacing as "$" is a special
|
||||
// character, we need to do double escaping as first is for the initial
|
||||
// replace on the routeFile and then the second on the outputPath
|
||||
`${routeFileNoExt.replace(/\$/g, '$$$$')}.json`
|
||||
);
|
||||
if (dataRoute) {
|
||||
outputPathData = path.posix.join(entryDirectory, dataRoute);
|
||||
|
||||
if (nonDynamicSsg || isFallback || isOmitted) {
|
||||
outputPathData = outputPathData.replace(
|
||||
new RegExp(`${escapeStringRegexp(origRouteFileNoExt)}.json$`),
|
||||
// ensure we escape "$" correctly while replacing as "$" is a special
|
||||
// character, we need to do double escaping as first is for the initial
|
||||
// replace on the routeFile and then the second on the outputPath
|
||||
`${routeFileNoExt.replace(/\$/g, '$$$$')}.json`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isSharedLambdas) {
|
||||
@@ -1954,7 +2014,7 @@ export const onPrerenderRoute =
|
||||
if (htmlFsRef == null || jsonFsRef == null) {
|
||||
throw new NowBuildError({
|
||||
code: 'NEXT_HTMLFSREF_JSONFSREF',
|
||||
message: 'invariant: htmlFsRef != null && jsonFsRef != null',
|
||||
message: `invariant: htmlFsRef != null && jsonFsRef != null ${routeFileNoExt}`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1966,7 +2026,10 @@ export const onPrerenderRoute =
|
||||
) {
|
||||
htmlFsRef.contentType = htmlContentType;
|
||||
prerenders[outputPathPage] = htmlFsRef;
|
||||
prerenders[outputPathData] = jsonFsRef;
|
||||
|
||||
if (outputPathData) {
|
||||
prerenders[outputPathData] = jsonFsRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
const isNotFoundPreview =
|
||||
@@ -2028,10 +2091,10 @@ export const onPrerenderRoute =
|
||||
allowQuery = [];
|
||||
}
|
||||
}
|
||||
const rscVaryHeader =
|
||||
routesManifest?.rsc?.varyHeader ||
|
||||
'__rsc__, __next_router_state_tree__, __next_router_prefetch__';
|
||||
const rscContentTypeHeader = routesManifest?.rsc?.contentTypeHeader || 'application/octet-stream';
|
||||
|
||||
const rscEnabled = !!routesManifest?.rsc;
|
||||
const rscVaryHeader = routesManifest?.rsc?.varyHeader || 'RSC, Next-Router-State-Tree, Next-Router-Prefetch';
|
||||
const rscContentTypeHeader = routesManifest?.rsc?.contentTypeHeader || 'text/x-component';
|
||||
|
||||
prerenders[outputPathPage] = new Prerender({
|
||||
expiration: initialRevalidate,
|
||||
@@ -2040,27 +2103,8 @@ export const onPrerenderRoute =
|
||||
fallback: htmlFsRef,
|
||||
group: prerenderGroup,
|
||||
bypassToken: prerenderManifest.bypassToken,
|
||||
...(isNotFound
|
||||
? {
|
||||
initialStatus: 404,
|
||||
}
|
||||
: {}),
|
||||
|
||||
...(isAppPathRoute
|
||||
? {
|
||||
initialHeaders: {
|
||||
vary: rscVaryHeader,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
prerenders[outputPathData] = new Prerender({
|
||||
expiration: initialRevalidate,
|
||||
lambda,
|
||||
allowQuery,
|
||||
fallback: jsonFsRef,
|
||||
group: prerenderGroup,
|
||||
bypassToken: prerenderManifest.bypassToken,
|
||||
initialStatus,
|
||||
initialHeaders,
|
||||
|
||||
...(isNotFound
|
||||
? {
|
||||
@@ -2068,16 +2112,42 @@ export const onPrerenderRoute =
|
||||
}
|
||||
: {}),
|
||||
|
||||
...(isAppPathRoute
|
||||
...(rscEnabled
|
||||
? {
|
||||
initialHeaders: {
|
||||
'content-type': rscContentTypeHeader,
|
||||
...initialHeaders,
|
||||
vary: rscVaryHeader,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
|
||||
if (outputPathData) {
|
||||
prerenders[outputPathData] = new Prerender({
|
||||
expiration: initialRevalidate,
|
||||
lambda,
|
||||
allowQuery,
|
||||
fallback: jsonFsRef,
|
||||
group: prerenderGroup,
|
||||
bypassToken: prerenderManifest.bypassToken,
|
||||
|
||||
...(isNotFound
|
||||
? {
|
||||
initialStatus: 404,
|
||||
}
|
||||
: {}),
|
||||
|
||||
...(rscEnabled
|
||||
? {
|
||||
initialHeaders: {
|
||||
'content-type': rscContentTypeHeader,
|
||||
vary: rscVaryHeader,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
|
||||
++prerenderGroup;
|
||||
|
||||
if (routesManifest?.i18n && isBlocking) {
|
||||
@@ -2091,29 +2161,30 @@ export const onPrerenderRoute =
|
||||
path.posix.join(entryDirectory, localeRouteFileNoExt),
|
||||
isServerMode
|
||||
);
|
||||
const localeOutputPathData = outputPathData.replace(
|
||||
new RegExp(`${escapeStringRegexp(origRouteFileNoExt)}.json$`),
|
||||
`${localeRouteFileNoExt}${
|
||||
localeRouteFileNoExt !== origRouteFileNoExt &&
|
||||
origRouteFileNoExt === '/index'
|
||||
? '/index'
|
||||
: ''
|
||||
}.json`
|
||||
);
|
||||
|
||||
const origPrerenderPage = prerenders[outputPathPage];
|
||||
const origPrerenderData = prerenders[outputPathData];
|
||||
|
||||
prerenders[localeOutputPathPage] = {
|
||||
...origPrerenderPage,
|
||||
group: prerenderGroup,
|
||||
} as Prerender;
|
||||
|
||||
prerenders[localeOutputPathData] = {
|
||||
...origPrerenderData,
|
||||
group: prerenderGroup,
|
||||
} as Prerender;
|
||||
if (outputPathData) {
|
||||
const localeOutputPathData = outputPathData.replace(
|
||||
new RegExp(`${escapeStringRegexp(origRouteFileNoExt)}.json$`),
|
||||
`${localeRouteFileNoExt}${
|
||||
localeRouteFileNoExt !== origRouteFileNoExt &&
|
||||
origRouteFileNoExt === '/index'
|
||||
? '/index'
|
||||
: ''
|
||||
}.json`
|
||||
);
|
||||
const origPrerenderData = prerenders[outputPathData];
|
||||
|
||||
prerenders[localeOutputPathData] = {
|
||||
...origPrerenderData,
|
||||
group: prerenderGroup,
|
||||
} as Prerender;
|
||||
}
|
||||
++prerenderGroup;
|
||||
}
|
||||
}
|
||||
@@ -2316,12 +2387,12 @@ interface EdgeFunctionMatcher {
|
||||
}
|
||||
|
||||
export async function getMiddlewareBundle({
|
||||
config = {},
|
||||
entryPath,
|
||||
outputDirectory,
|
||||
routesManifest,
|
||||
isCorrectMiddlewareOrder,
|
||||
prerenderBypassToken,
|
||||
nextVersion,
|
||||
}: {
|
||||
config: Config;
|
||||
entryPath: string;
|
||||
@@ -2329,6 +2400,7 @@ export async function getMiddlewareBundle({
|
||||
prerenderBypassToken: string;
|
||||
routesManifest: RoutesManifest;
|
||||
isCorrectMiddlewareOrder: boolean;
|
||||
nextVersion: string;
|
||||
}): Promise<{
|
||||
staticRoutes: Route[];
|
||||
dynamicRouteMap: Map<string, RouteWithSrc>;
|
||||
@@ -2379,21 +2451,6 @@ export async function getMiddlewareBundle({
|
||||
edgeFunction.wasm
|
||||
);
|
||||
|
||||
const edgeFunctionOptions: { cron?: Cron } = {};
|
||||
if (config.functions) {
|
||||
const sourceFile = await getSourceFilePathFromPage({
|
||||
workPath: entryPath,
|
||||
page: `${edgeFunction.page}.js`,
|
||||
});
|
||||
|
||||
const opts = await getLambdaOptionsFromFunction({
|
||||
sourceFile,
|
||||
config,
|
||||
});
|
||||
|
||||
edgeFunctionOptions.cron = opts.cron;
|
||||
}
|
||||
|
||||
return {
|
||||
type,
|
||||
page: edgeFunction.page,
|
||||
@@ -2438,7 +2495,6 @@ export async function getMiddlewareBundle({
|
||||
);
|
||||
|
||||
return new EdgeFunction({
|
||||
...edgeFunctionOptions,
|
||||
deploymentTarget: 'v8-worker',
|
||||
name: edgeFunction.name,
|
||||
files: {
|
||||
@@ -2466,6 +2522,10 @@ export async function getMiddlewareBundle({
|
||||
path: `assets/${name}`,
|
||||
};
|
||||
}),
|
||||
framework: {
|
||||
slug: 'nextjs',
|
||||
version: nextVersion,
|
||||
},
|
||||
});
|
||||
})(),
|
||||
routeMatchers: getRouteMatchers(edgeFunction, routesManifest),
|
||||
@@ -2501,9 +2561,13 @@ export async function getMiddlewareBundle({
|
||||
// app/index/page -> index/index
|
||||
if (shortPath.startsWith('pages/')) {
|
||||
shortPath = shortPath.replace(/^pages\//, '');
|
||||
} else if (shortPath.startsWith('app/') && shortPath.endsWith('/page')) {
|
||||
} else if (
|
||||
shortPath.startsWith('app/') &&
|
||||
(shortPath.endsWith('/page') || shortPath.endsWith('/route'))
|
||||
) {
|
||||
shortPath =
|
||||
shortPath.replace(/^app\//, '').replace(/(^|\/)page$/, '') || 'index';
|
||||
shortPath.replace(/^app\//, '').replace(/(^|\/)(page|route)$/, '') ||
|
||||
'index';
|
||||
}
|
||||
|
||||
if (routesManifest?.basePath) {
|
||||
@@ -2689,3 +2753,49 @@ function transformSourceMap(
|
||||
|
||||
return { ...sourcemap, sources };
|
||||
}
|
||||
|
||||
interface LambdaGroupTypeInterface {
|
||||
isApiLambda: boolean;
|
||||
isPrerenders?: boolean;
|
||||
}
|
||||
|
||||
export function getOperationType({
|
||||
group,
|
||||
prerenderManifest,
|
||||
pageFileName,
|
||||
}: {
|
||||
group?: LambdaGroupTypeInterface;
|
||||
prerenderManifest?: NextPrerenderedRoutes;
|
||||
pageFileName?: string;
|
||||
}) {
|
||||
if (group?.isApiLambda || isApiPage(pageFileName)) {
|
||||
return 'API';
|
||||
}
|
||||
|
||||
if (group?.isPrerenders) {
|
||||
return 'ISR';
|
||||
}
|
||||
|
||||
if (pageFileName && prerenderManifest) {
|
||||
const { blockingFallbackRoutes = {}, fallbackRoutes = {} } =
|
||||
prerenderManifest;
|
||||
if (
|
||||
pageFileName in blockingFallbackRoutes ||
|
||||
pageFileName in fallbackRoutes
|
||||
) {
|
||||
return 'ISR';
|
||||
}
|
||||
}
|
||||
|
||||
return 'SSR';
|
||||
}
|
||||
|
||||
export function isApiPage(page: string | undefined) {
|
||||
if (!page) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return page
|
||||
.replace(/\\/g, '/')
|
||||
.match(/(serverless|server)\/pages\/api(\/|\.js$)/);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"RSC": "1"
|
||||
},
|
||||
"responseHeaders": {
|
||||
"content-type": "application/octet-stream"
|
||||
"content-type": "text/x-component"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -51,7 +51,7 @@
|
||||
"RSC": "1"
|
||||
},
|
||||
"responseHeaders": {
|
||||
"content-type": "application/octet-stream"
|
||||
"content-type": "text/x-component"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
21
packages/next/test/fixtures/00-app-dir-middleware/app/[variant]/[[...rest]]/page.js
vendored
Normal file
21
packages/next/test/fixtures/00-app-dir-middleware/app/[variant]/[[...rest]]/page.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
const paths = ['/', '/shop', '/product', '/who-we-are', '/about', '/contact'];
|
||||
|
||||
export default function Page({ params }) {
|
||||
return (
|
||||
<>
|
||||
<p>variant: {params.variant}</p>
|
||||
<p>slug: {params.rest?.join('/')}</p>
|
||||
<ul>
|
||||
{paths.map(path => {
|
||||
return (
|
||||
<li key={path}>
|
||||
<Link href={path}>to {path}</Link>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
}
|
||||
10
packages/next/test/fixtures/00-app-dir-middleware/app/layout.js
vendored
Normal file
10
packages/next/test/fixtures/00-app-dir-middleware/app/layout.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function Root({ children }) {
|
||||
return (
|
||||
<html className="this-is-the-document-html">
|
||||
<head>
|
||||
<title>{`hello world`}</title>
|
||||
</head>
|
||||
<body className="this-is-the-document-body">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
12
packages/next/test/fixtures/00-app-dir-middleware/index.test.js
vendored
Normal file
12
packages/next/test/fixtures/00-app-dir-middleware/index.test.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/* eslint-env jest */
|
||||
const path = require('path');
|
||||
const { deployAndTest } = require('../../utils');
|
||||
|
||||
const ctx = {};
|
||||
|
||||
describe(`${__dirname.split(path.sep).pop()}`, () => {
|
||||
it('should deploy and pass probe checks', async () => {
|
||||
const info = await deployAndTest(__dirname);
|
||||
Object.assign(ctx, info);
|
||||
});
|
||||
});
|
||||
11
packages/next/test/fixtures/00-app-dir-middleware/middleware.js
vendored
Normal file
11
packages/next/test/fixtures/00-app-dir-middleware/middleware.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export function middleware(request) {
|
||||
request.nextUrl.pathname = `/no-variant${request.nextUrl.pathname}`;
|
||||
return NextResponse.rewrite(request.nextUrl);
|
||||
}
|
||||
|
||||
// See "Matching Paths" below to learn more
|
||||
export const config = {
|
||||
matcher: ['/', '/shop', '/product', '/who-we-are', '/about', '/contact'],
|
||||
};
|
||||
14
packages/next/test/fixtures/00-app-dir-middleware/next.config.js
vendored
Normal file
14
packages/next/test/fixtures/00-app-dir-middleware/next.config.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
experimental: {
|
||||
appDir: true,
|
||||
runtime: 'nodejs',
|
||||
},
|
||||
rewrites: async () => {
|
||||
return [
|
||||
{
|
||||
source: '/rewritten-to-dashboard',
|
||||
destination: '/dashboard',
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
7
packages/next/test/fixtures/00-app-dir-middleware/package.json
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-middleware/package.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "experimental",
|
||||
"react-dom": "experimental"
|
||||
}
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir-middleware/pages/api/hello.js
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-middleware/pages/api/hello.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function handler(req, res) {
|
||||
return res.json({ hello: 'world' });
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user