Compare commits

..

5 Commits

Author SHA1 Message Date
Steven
0c7b54edad Publish Stable
- @vercel/build-utils@4.1.0
 - vercel@25.1.0
 - @vercel/client@12.0.1
 - @vercel/go@2.0.1
 - @vercel/next@3.0.1
 - @vercel/node@2.1.0
 - @vercel/python@3.0.1
 - @vercel/redwood@1.0.1
 - @vercel/remix@1.0.1
 - @vercel/ruby@1.3.9
 - @vercel/static-build@1.0.1
 - @vercel/static-config@2.0.1
2022-06-08 10:44:17 -04:00
Steven
6d42816395 Publish Canary
- vercel@25.0.2-canary.1
 - @vercel/next@3.0.1-canary.1
 - @vercel/static-build@1.0.1-canary.1
2022-06-08 08:48:04 -04:00
Seiya Nuta
6fe6d05a42 Increase the maximum size of an edge function to 1MiB (#7903) 2022-06-08 16:30:49 +09:00
Steven
50a201f145 [cli][static-build] Fix case when vc dev is throwing the wrong error w/ BOAv3 (#7927)
Fixes an issue brought up in https://github.com/vercel/og-image/issues/207

The problem is that we allow a corner case with `vc dev` to run the build script, but this can break if the user ran `vc build` first due to the BOA V3 detection.

The workaround is to delete the BOA V3 directory when there is no Development Command provided since that will run the Build Command during development.

We also add a nicer error in the case when someone actually intended to emit BOA V3.
2022-06-07 21:31:43 +00:00
Gal Schlezinger
701a02ae9d [next] Support Edge API Endpoints (#7905)
* Add regression test for nested middleware

* [next] Allow edge api endpoints in Next.js

This reverts commit d4cef69cc9 (#7898)

* delete `functions`, not `middleware`

* Add an assertion

Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-06-07 23:36:46 +03:00
19 changed files with 172 additions and 82 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "4.0.1-canary.0",
"version": "4.1.0",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "25.0.2-canary.0",
"version": "25.1.0",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -42,15 +42,15 @@
"node": ">= 14"
},
"dependencies": {
"@vercel/build-utils": "4.0.1-canary.0",
"@vercel/go": "2.0.1-canary.0",
"@vercel/next": "3.0.1-canary.0",
"@vercel/node": "2.0.2-canary.0",
"@vercel/python": "3.0.1-canary.0",
"@vercel/redwood": "1.0.1-canary.0",
"@vercel/remix": "1.0.1-canary.0",
"@vercel/ruby": "1.3.9-canary.0",
"@vercel/static-build": "1.0.1-canary.0",
"@vercel/build-utils": "4.1.0",
"@vercel/go": "2.0.1",
"@vercel/next": "3.0.1",
"@vercel/node": "2.1.0",
"@vercel/python": "3.0.1",
"@vercel/redwood": "1.0.1",
"@vercel/remix": "1.0.1",
"@vercel/ruby": "1.3.9",
"@vercel/static-build": "1.0.1",
"update-notifier": "5.1.0"
},
"devDependencies": {
@@ -94,7 +94,7 @@
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@types/yauzl-promise": "2.1.0",
"@vercel/client": "12.0.1-canary.0",
"@vercel/client": "12.0.1",
"@vercel/frameworks": "1.0.1",
"@vercel/ncc": "0.24.0",
"@zeit/fun": "0.11.2",

View File

@@ -1,4 +1,5 @@
import { resolve, join } from 'path';
import fs from 'fs-extra';
import DevServer from '../../util/dev/server';
import parseListen from '../../util/dev/parse-listen';
@@ -12,6 +13,7 @@ import setupAndLink from '../../util/link/setup-and-link';
import getSystemEnvValues from '../../util/env/get-system-env-values';
import { getCommandName } from '../../util/pkg-name';
import param from '../../util/output/param';
import { OUTPUT_DIR } from '../../util/build/write-build-result';
type Options = {
'--listen': string;
@@ -104,6 +106,15 @@ export default async function dev(
devCommand = process.env.VERCEL_DEV_COMMAND;
}
// If there is no Development Command, we must delete the
// v3 Build Output because it will incorrectly be detected by
// @vercel/static-build in BuildOutputV3.getBuildOutputDirectory()
if (!devCommand) {
output.log(`Removing ${OUTPUT_DIR}`);
const outputDir = join(cwd, OUTPUT_DIR);
await fs.remove(outputDir);
}
const devServer = new DevServer(cwd, {
output,
devCommand,

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "12.0.1-canary.0",
"version": "12.0.1",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",
@@ -42,7 +42,7 @@
]
},
"dependencies": {
"@vercel/build-utils": "4.0.1-canary.0",
"@vercel/build-utils": "4.1.0",
"@zeit/fetch": "5.2.0",
"async-retry": "1.2.3",
"async-sema": "3.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/go",
"version": "2.0.1-canary.0",
"version": "2.0.1",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
@@ -25,7 +25,7 @@
"@types/fs-extra": "^5.0.5",
"@types/node-fetch": "^2.3.0",
"@types/tar": "^4.0.0",
"@vercel/build-utils": "4.0.1-canary.0",
"@vercel/build-utils": "4.1.0",
"@vercel/ncc": "0.24.0",
"async-retry": "1.3.1",
"execa": "^1.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/next",
"version": "3.0.1-canary.0",
"version": "3.0.1",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
@@ -45,7 +45,7 @@
"@types/semver": "6.0.0",
"@types/text-table": "0.2.1",
"@types/webpack-sources": "3.2.0",
"@vercel/build-utils": "4.0.1-canary.0",
"@vercel/build-utils": "4.1.0",
"@vercel/nft": "0.19.1",
"@vercel/routing-utils": "1.13.4",
"async-sema": "3.0.1",

View File

@@ -2,23 +2,6 @@ const KIB = 1024;
const MIB = 1024 * KIB;
/**
* The limit after compression. it has to be kibibyte instead of kilobyte
* See https://github.com/cloudflare/wrangler/blob/8907b12add3d70ee21ac597b69cd66f6807571f4/src/wranglerjs/output.rs#L44
* The maximum size of a *compressed* edge function.
*/
const EDGE_FUNCTION_SCRIPT_SIZE_LIMIT = MIB;
/**
* This safety buffer must cover the size of our whole runtime layer compressed
* plus some extra space to allow it to grow in the future. At the time of
* writing this comment the compressed size size is ~7KiB so 20KiB should
* be more than enough.
*/
const EDGE_FUNCTION_SCRIPT_SIZE_BUFFER = 20 * KIB;
/**
* The max size we allow for compressed user code is the compressed script
* limit minus the compressed safety buffer. We must check this limit after
* compressing the user code.
*/
export const EDGE_FUNCTION_USER_SCRIPT_SIZE_LIMIT =
EDGE_FUNCTION_SCRIPT_SIZE_LIMIT - EDGE_FUNCTION_SCRIPT_SIZE_BUFFER;
export const EDGE_FUNCTION_SIZE_LIMIT = MIB;

View File

@@ -3,7 +3,7 @@ import { readFile } from 'fs-extra';
import { ConcatSource, Source } from 'webpack-sources';
import { fileToSource, raw, sourcemapped } from '../sourcemapped';
import { join } from 'path';
import { EDGE_FUNCTION_USER_SCRIPT_SIZE_LIMIT } from './constants';
import { EDGE_FUNCTION_SIZE_LIMIT } from './constants';
import zlib from 'zlib';
import { promisify } from 'util';
import bytes from 'pretty-bytes';
@@ -74,11 +74,11 @@ function getWasmImportStatements(wasm: { name: string }[] = []) {
async function validateScript(content: string) {
const gzipped = await gzip(content);
if (gzipped.length > EDGE_FUNCTION_USER_SCRIPT_SIZE_LIMIT) {
if (gzipped.length > EDGE_FUNCTION_SIZE_LIMIT) {
throw new Error(
`Exceeds maximum edge function script size: ${bytes(
gzipped.length
)} / ${bytes(EDGE_FUNCTION_USER_SCRIPT_SIZE_LIMIT)}`
)} / ${bytes(EDGE_FUNCTION_SIZE_LIMIT)}`
);
}
}

View File

@@ -56,6 +56,7 @@ import {
getExportStatus,
getFilesMapFromReasons,
getImagesManifest,
getMiddlewareManifest,
getNextConfig,
getPageLambdaGroups,
getPrerenderManifest,
@@ -77,6 +78,7 @@ import {
updateRouteSrc,
validateEntrypoint,
} from './utils';
import assert from 'assert';
export const version = 2;
export const htmlContentType = 'text/html; charset=utf-8';
@@ -1001,7 +1003,11 @@ export const build: BuildV2 = async ({
buildId,
'pages'
);
const pages = await glob('**/!(_middleware).js', pagesDir);
const pages = await getServerlessPages({
pagesDir,
entryPath,
outputDirectory,
});
const launcherPath = path.join(__dirname, 'legacy-launcher.js');
const launcherData = await readFile(launcherPath, 'utf8');
@@ -1074,7 +1080,11 @@ export const build: BuildV2 = async ({
'pages'
);
const pages = await glob('**/!(_middleware).js', pagesDir);
const pages = await getServerlessPages({
pagesDir,
entryPath,
outputDirectory,
});
const isApiPage = (page: string) =>
page
.replace(/\\/g, '/')
@@ -2575,3 +2585,32 @@ export const prepareCache: PrepareCache = async ({
debug('Cache file manifest produced');
return cache;
};
async function getServerlessPages(params: {
pagesDir: string;
entryPath: string;
outputDirectory: string;
}) {
const [pages, middlewareManifest] = await Promise.all([
glob('**/!(_middleware).js', params.pagesDir),
getMiddlewareManifest(params.entryPath, params.outputDirectory),
]);
// Edge Functions do not consider as Serverless Functions
for (const edgeFunctionFile of Object.keys(
middlewareManifest?.functions ?? {}
)) {
// `getStaticProps` are expecting `Prerender` output which is a Serverless function
// and not an Edge Function. Therefore we only remove API endpoints for now, as they
// don't have `getStaticProps`.
//
// Context: https://github.com/vercel/vercel/pull/7905#discussion_r890213165
assert(
edgeFunctionFile.startsWith('/api/'),
`Only API endpoints are currently supported for Edge endpoints.`
);
delete pages[edgeFunctionFile.slice(1) + '.js'];
}
return pages;
}

View File

@@ -2124,12 +2124,11 @@ export {
interface MiddlewareManifest {
version: 1;
sortedMiddleware: string[];
middleware: {
[page: string]: MiddlewareInfo;
};
middleware: { [page: string]: EdgeFunctionInfo };
functions?: { [page: string]: EdgeFunctionInfo };
}
interface MiddlewareInfo {
interface EdgeFunctionInfo {
env: string[];
files: string[];
name: string;
@@ -2153,16 +2152,34 @@ export async function getMiddlewareBundle({
entryPath,
outputDirectory
);
const sortedFunctions = [
...(!middlewareManifest
? []
: middlewareManifest.sortedMiddleware.map(key => ({
key,
edgeFunction: middlewareManifest?.middleware[key],
type: 'middleware' as const,
}))),
if (middlewareManifest && middlewareManifest?.sortedMiddleware.length > 0) {
...Object.entries(middlewareManifest?.functions ?? {}).map(
([key, edgeFunction]) => {
return {
key,
edgeFunction,
type: 'function' as const,
};
}
),
];
if (middlewareManifest && sortedFunctions.length > 0) {
const workerConfigs = await Promise.all(
middlewareManifest.sortedMiddleware.map(async key => {
const middleware = middlewareManifest.middleware[key];
sortedFunctions.map(async ({ key, edgeFunction, type }) => {
try {
const wrappedModuleSource = await getNextjsEdgeFunctionSource(
middleware.files,
edgeFunction.files,
{
name: middleware.name,
name: edgeFunction.name,
staticRoutes: routesManifest.staticRoutes,
dynamicRoutes: routesManifest.dynamicRoutes.filter(
r => !('isMiddleware' in r)
@@ -2173,18 +2190,19 @@ export async function getMiddlewareBundle({
},
},
path.resolve(entryPath, outputDirectory),
middleware.wasm
edgeFunction.wasm
);
return {
page: middlewareManifest.middleware[key].page,
type,
page: edgeFunction.page,
edgeFunction: (() => {
const { source, map } = wrappedModuleSource.sourceAndMap();
const transformedMap = stringifySourceMap(
transformSourceMap(map)
);
const wasmFiles = (middleware.wasm ?? []).reduce(
const wasmFiles = (edgeFunction.wasm ?? []).reduce(
(acc: Files, { filePath, name }) => {
const fullFilePath = path.join(
entryPath,
@@ -2203,7 +2221,7 @@ export async function getMiddlewareBundle({
return new EdgeFunction({
deploymentTarget: 'v8-worker',
name: middleware.name,
name: edgeFunction.name,
files: {
'index.js': new FileBlob({
data: source,
@@ -2220,13 +2238,10 @@ export async function getMiddlewareBundle({
...wasmFiles,
},
entrypoint: 'index.js',
envVarsInUse: middleware.env,
envVarsInUse: edgeFunction.env,
});
})(),
routeSrc: getRouteSrc(
middlewareManifest.middleware[key],
routesManifest
),
routeSrc: getRouteSrc(edgeFunction, routesManifest),
};
} catch (e: any) {
e.message = `Can't build edge function ${key}: ${e.message}`;
@@ -2247,16 +2262,21 @@ export async function getMiddlewareBundle({
for (const worker of workerConfigs.values()) {
const edgeFile = worker.edgeFunction.name;
worker.edgeFunction.name = edgeFile.replace(/^pages\//, '');
source.edgeFunctions[edgeFile] = worker.edgeFunction;
const route: Source = {
const shortPath = edgeFile.replace(/^pages\//, '');
worker.edgeFunction.name = shortPath;
source.edgeFunctions[shortPath] = worker.edgeFunction;
const route: Route = {
continue: true,
middlewarePath: edgeFile,
src: worker.routeSrc,
};
if (isCorrectMiddlewareOrder) {
route.override = true;
if (worker.type === 'function') {
route.dest = shortPath;
} else {
route.middlewarePath = shortPath;
if (isCorrectMiddlewareOrder) {
route.override = true;
}
}
if (routesManifest.version > 3 && isDynamicRoute(worker.page)) {
@@ -2281,7 +2301,7 @@ export async function getMiddlewareBundle({
* location. If the manifest can't be found it will resolve to
* undefined.
*/
async function getMiddlewareManifest(
export async function getMiddlewareManifest(
entryPath: string,
outputDirectory: string
): Promise<MiddlewareManifest | undefined> {
@@ -2313,7 +2333,7 @@ async function getMiddlewareManifest(
* @returns A regexp string for the middleware route.
*/
function getRouteSrc(
{ regexp, page }: MiddlewareInfo,
{ regexp, page }: EdgeFunctionInfo,
{ basePath = '', i18n }: RoutesManifest
): string {
if (page === '/') {

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node",
"version": "2.0.2-canary.0",
"version": "2.1.0",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -45,10 +45,10 @@
"@types/etag": "1.8.0",
"@types/jest": "27.4.1",
"@types/test-listen": "1.1.0",
"@vercel/build-utils": "4.0.1-canary.0",
"@vercel/build-utils": "4.1.0",
"@vercel/ncc": "0.24.0",
"@vercel/nft": "0.19.1",
"@vercel/static-config": "2.0.1-canary.0",
"@vercel/static-config": "2.0.1",
"content-type": "1.0.4",
"cookie": "0.4.0",
"etag": "1.8.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/python",
"version": "3.0.1-canary.0",
"version": "3.0.1",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
@@ -23,7 +23,7 @@
"devDependencies": {
"@types/execa": "^0.9.0",
"@types/jest": "27.4.1",
"@vercel/build-utils": "4.0.1-canary.0",
"@vercel/build-utils": "4.1.0",
"@vercel/ncc": "0.24.0",
"execa": "^1.0.0",
"typescript": "4.3.4"

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/redwood",
"version": "1.0.1-canary.0",
"version": "1.0.1",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs",
@@ -28,6 +28,6 @@
"@types/aws-lambda": "8.10.19",
"@types/node": "*",
"@types/semver": "6.0.0",
"@vercel/build-utils": "4.0.1-canary.0"
"@vercel/build-utils": "4.1.0"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/remix",
"version": "1.0.1-canary.0",
"version": "1.0.1",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://vercel.com/docs",
@@ -27,7 +27,7 @@
"devDependencies": {
"@types/jest": "27.5.1",
"@types/node": "*",
"@vercel/build-utils": "4.0.1-canary.0",
"@vercel/build-utils": "4.1.0",
"typescript": "4.6.4"
}
}

View File

@@ -1,7 +1,7 @@
{
"name": "@vercel/ruby",
"author": "Nathan Cahill <nathan@nathancahill.com>",
"version": "1.3.9-canary.0",
"version": "1.3.9",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
@@ -23,7 +23,7 @@
"devDependencies": {
"@types/fs-extra": "8.0.0",
"@types/semver": "6.0.0",
"@vercel/build-utils": "4.0.1-canary.0",
"@vercel/build-utils": "4.1.0",
"@vercel/ncc": "0.24.0",
"execa": "2.0.4",
"fs-extra": "^7.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/static-build",
"version": "1.0.1-canary.0",
"version": "1.0.1",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/build-step",
@@ -37,7 +37,7 @@
"@types/ms": "0.7.31",
"@types/node-fetch": "2.5.4",
"@types/promise-timeout": "1.3.0",
"@vercel/build-utils": "4.0.1-canary.0",
"@vercel/build-utils": "4.1.0",
"@vercel/frameworks": "1.0.1",
"@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "1.13.4",

View File

@@ -50,6 +50,11 @@ export function createBuildOutput(
else if (framework) buildCommandName = framework.name;
else buildCommandName = 'the "build" script';
if (meta.isDev) {
throw new Error(
`Detected Build Output v3 from ${buildCommandName}, but it is not supported for \`vercel dev\`. Please set the Development Command in your Project Settings.`
);
}
throw new Error(
`Detected Build Output v3 from ${buildCommandName}, but this Deployment is not using \`vercel build\`.\nPlease set the \`ENABLE_VC_BUILD=1\` environment variable.`
);

View File

@@ -17,6 +17,7 @@ describe('build()', () => {
const buildResult = await build({
files: {},
entrypoint: 'package.json',
repoRootPath: workPath,
workPath,
config: {},
meta: {
@@ -46,6 +47,7 @@ describe('build()', () => {
const buildResult = await build({
files: {},
entrypoint: 'package.json',
repoRootPath: workPath,
workPath,
config: {},
meta: {
@@ -76,6 +78,7 @@ describe('build()', () => {
const buildResult = await build({
files: {},
entrypoint: 'package.json',
repoRootPath: workPath,
workPath,
config: {},
meta: {
@@ -105,6 +108,7 @@ describe('build()', () => {
const buildResult = await build({
files: {},
entrypoint: 'package.json',
repoRootPath: workPath,
workPath,
config: {},
meta: {
@@ -132,6 +136,7 @@ describe('build()', () => {
await build({
files: {},
entrypoint: 'package.json',
repoRootPath: workPath,
workPath,
config: {},
meta: {
@@ -145,5 +150,32 @@ describe('build()', () => {
`Detected Build Output v3 from the "build" script, but this Deployment is not using \`vercel build\`.\nPlease set the \`ENABLE_VC_BUILD=1\` environment variable.`
);
});
it('should throw an Error when `vercel dev` is used with `@vercel/static-build`', async () => {
let err;
const workPath = path.join(
__dirname,
'build-fixtures',
'09-build-output-v3'
);
try {
await build({
files: {},
entrypoint: 'package.json',
repoRootPath: workPath,
workPath,
config: {},
meta: {
skipDownload: true,
isDev: true,
},
});
} catch (_err: any) {
err = _err;
}
expect(err.message).toEqual(
`Detected Build Output v3 from the "build" script, but it is not supported for \`vercel dev\`. Please set the Development Command in your Project Settings.`
);
});
});
});

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/static-config",
"version": "2.0.1-canary.0",
"version": "2.0.1",
"license": "MIT",
"main": "./dist/index",
"repository": {