mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-10 04:22:12 +00:00
Revert "[static-build] Support subset of Build Output API v2" (#7803)
Revert "[static-build] Support subset of Build Output API v2 (#7690)"
This reverts commit 05243fb6e9.
This commit is contained in:
1
examples/solidstart/.gitignore
vendored
1
examples/solidstart/.gitignore
vendored
@@ -2,7 +2,6 @@ dist
|
||||
worker
|
||||
.solid
|
||||
.vercel
|
||||
.output
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
"devDependencies": {
|
||||
"@types/aws-lambda": "8.10.64",
|
||||
"@types/cross-spawn": "6.0.0",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/ms": "0.7.31",
|
||||
"@types/node-fetch": "2.5.4",
|
||||
|
||||
@@ -32,7 +32,6 @@ import {
|
||||
} from '@vercel/build-utils';
|
||||
import type { Route, Source } from '@vercel/routing-utils';
|
||||
import * as BuildOutputV1 from './utils/build-output-v1';
|
||||
import * as BuildOutputV2 from './utils/build-output-v2';
|
||||
import * as BuildOutputV3 from './utils/build-output-v3';
|
||||
import * as GatsbyUtils from './utils/gatsby';
|
||||
import * as NuxtUtils from './utils/nuxt';
|
||||
@@ -262,37 +261,6 @@ async function fetchBinary(url: string, framework: string, version: string) {
|
||||
});
|
||||
}
|
||||
|
||||
async function getUpdatedDistPath(
|
||||
framework: Framework | undefined,
|
||||
outputDirPrefix: string,
|
||||
entrypointDir: string,
|
||||
distPath: string,
|
||||
config: Config
|
||||
): Promise<string | undefined> {
|
||||
if (framework) {
|
||||
const outputDirName = config.outputDirectory
|
||||
? config.outputDirectory
|
||||
: await framework.getOutputDirName(outputDirPrefix);
|
||||
|
||||
return path.join(outputDirPrefix, outputDirName);
|
||||
}
|
||||
|
||||
if (!config || !config.distDir) {
|
||||
// Select either `dist` or `public` as directory
|
||||
const publicPath = path.join(entrypointDir, 'public');
|
||||
|
||||
if (
|
||||
!existsSync(distPath) &&
|
||||
existsSync(publicPath) &&
|
||||
statSync(publicPath).isDirectory()
|
||||
) {
|
||||
return publicPath;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export const build: BuildV2 = async ({
|
||||
files,
|
||||
entrypoint,
|
||||
@@ -661,36 +629,48 @@ export const build: BuildV2 = async ({
|
||||
}
|
||||
|
||||
const outputDirPrefix = path.join(workPath, path.dirname(entrypoint));
|
||||
distPath =
|
||||
(await getUpdatedDistPath(
|
||||
framework,
|
||||
outputDirPrefix,
|
||||
entrypointDir,
|
||||
distPath,
|
||||
config
|
||||
)) || distPath;
|
||||
|
||||
// If the Build Command or Framework output files according to the
|
||||
// Build Output v3 API, then stop processing here in `static-build`
|
||||
// since the output is already in its final form.
|
||||
const buildOutputPathV3 = await BuildOutputV3.getBuildOutputDirectory(
|
||||
const buildOutputPath = await BuildOutputV3.getBuildOutputDirectory(
|
||||
outputDirPrefix
|
||||
);
|
||||
if (buildOutputPathV3) {
|
||||
|
||||
if (buildOutputPath) {
|
||||
// Ensure that `vercel build` is being used for this Deployment
|
||||
return BuildOutputV3.createBuildOutput(
|
||||
meta,
|
||||
buildCommand,
|
||||
buildOutputPathV3,
|
||||
framework
|
||||
);
|
||||
if (!meta.cliVersion) {
|
||||
let buildCommandName: string;
|
||||
if (buildCommand) buildCommandName = `"${buildCommand}"`;
|
||||
else if (framework) buildCommandName = framework.name;
|
||||
else buildCommandName = 'the "build" script';
|
||||
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.`
|
||||
);
|
||||
}
|
||||
return {
|
||||
buildOutputVersion: 3,
|
||||
buildOutputPath,
|
||||
};
|
||||
}
|
||||
|
||||
const buildOutputPathV2 = await BuildOutputV2.getBuildOutputDirectory(
|
||||
outputDirPrefix
|
||||
);
|
||||
if (buildOutputPathV2) {
|
||||
return await BuildOutputV2.createBuildOutput(workPath);
|
||||
if (framework) {
|
||||
const outputDirName = config.outputDirectory
|
||||
? config.outputDirectory
|
||||
: await framework.getOutputDirName(outputDirPrefix);
|
||||
|
||||
distPath = path.join(outputDirPrefix, outputDirName);
|
||||
} else if (!config || !config.distDir) {
|
||||
// Select either `dist` or `public` as directory
|
||||
const publicPath = path.join(entrypointDir, 'public');
|
||||
|
||||
if (
|
||||
!existsSync(distPath) &&
|
||||
existsSync(publicPath) &&
|
||||
statSync(publicPath).isDirectory()
|
||||
) {
|
||||
distPath = publicPath;
|
||||
}
|
||||
}
|
||||
|
||||
const extraOutputs = await BuildOutputV1.readBuildOutputDirectory({
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
import path from 'path';
|
||||
import { pathExists, readJson, appendFile } from 'fs-extra';
|
||||
import { Route } from '@vercel/routing-utils';
|
||||
import {
|
||||
Files,
|
||||
FileFsRef,
|
||||
debug,
|
||||
glob,
|
||||
EdgeFunction,
|
||||
BuildResultV2,
|
||||
} from '@vercel/build-utils';
|
||||
import { isObjectEmpty } from './_shared';
|
||||
|
||||
const BUILD_OUTPUT_DIR = '.output';
|
||||
const BRIDGE_MIDDLEWARE_V2_TO_V3 = `
|
||||
|
||||
|
||||
// appended to convert v2 middleware to v3 middleware
|
||||
export default async (request) => {
|
||||
const { response } = await _ENTRIES['middleware_pages/_middleware'].default({ request });
|
||||
return response;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Returns the path to the Build Output API v2 directory when the
|
||||
* `config.json` file was created by the framework / build script,
|
||||
* or `undefined` if the framework did not create the v3 output.
|
||||
*/
|
||||
export async function getBuildOutputDirectory(
|
||||
workingDir: string
|
||||
): Promise<string | undefined> {
|
||||
const outputDir = path.join(workingDir, BUILD_OUTPUT_DIR);
|
||||
const outputPathExists = await pathExists(outputDir);
|
||||
if (outputPathExists) {
|
||||
return outputDir;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the BUILD_OUTPUT_DIR directory and returns and object
|
||||
* that should be merged with the build outputs.
|
||||
*/
|
||||
export async function readBuildOutputDirectory({
|
||||
workPath,
|
||||
}: {
|
||||
workPath: string;
|
||||
}) {
|
||||
// Functions are not supported, but are used to support Middleware
|
||||
const functions: Record<string, EdgeFunction> = {};
|
||||
|
||||
// Routes are not supported, but are used to support Middleware
|
||||
const routes: Array<Route> = [];
|
||||
|
||||
const middleware = await getMiddleware(workPath);
|
||||
if (middleware) {
|
||||
routes.push(middleware.route);
|
||||
|
||||
functions['middleware'] = new EdgeFunction({
|
||||
deploymentTarget: 'v8-worker',
|
||||
entrypoint: '_middleware.js',
|
||||
files: {
|
||||
'_middleware.js': middleware.file,
|
||||
},
|
||||
name: 'middleware',
|
||||
});
|
||||
}
|
||||
|
||||
const staticFiles = await readStaticFiles({ workPath });
|
||||
|
||||
const outputs = {
|
||||
staticFiles: isObjectEmpty(staticFiles) ? null : staticFiles,
|
||||
functions: isObjectEmpty(functions) ? null : functions,
|
||||
routes: routes.length ? routes : null,
|
||||
};
|
||||
|
||||
if (outputs.functions) {
|
||||
debug(`Detected Serverless Functions in "${BUILD_OUTPUT_DIR}"`);
|
||||
}
|
||||
|
||||
if (outputs.staticFiles) {
|
||||
debug(`Detected Static Assets in "${BUILD_OUTPUT_DIR}"`);
|
||||
}
|
||||
|
||||
if (outputs.routes) {
|
||||
debug(`Detected Routes Configuration in "${BUILD_OUTPUT_DIR}"`);
|
||||
}
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
async function getMiddleware(
|
||||
workPath: string
|
||||
): Promise<{ route: Route; file: FileFsRef } | undefined> {
|
||||
const manifestPath = path.join(
|
||||
workPath,
|
||||
BUILD_OUTPUT_DIR,
|
||||
'functions-manifest.json'
|
||||
);
|
||||
|
||||
try {
|
||||
const manifest = await readJson(manifestPath);
|
||||
if (manifest.pages['_middleware.js'].runtime !== 'web') {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') throw error;
|
||||
return;
|
||||
}
|
||||
|
||||
const middlewareRelativePath = path.join(
|
||||
BUILD_OUTPUT_DIR,
|
||||
'server/pages/_middleware.js'
|
||||
);
|
||||
|
||||
const middlewareAbsoluatePath = path.join(workPath, middlewareRelativePath);
|
||||
await appendFile(middlewareAbsoluatePath, BRIDGE_MIDDLEWARE_V2_TO_V3);
|
||||
|
||||
const route = {
|
||||
src: '/(.*)',
|
||||
middlewarePath: 'middleware',
|
||||
continue: true,
|
||||
};
|
||||
|
||||
return {
|
||||
route,
|
||||
file: new FileFsRef({
|
||||
fsPath: middlewareRelativePath,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
async function readStaticFiles({
|
||||
workPath,
|
||||
}: {
|
||||
workPath: string;
|
||||
}): Promise<Files> {
|
||||
const staticFilePath = path.join(workPath, BUILD_OUTPUT_DIR, 'static');
|
||||
const staticFiles = await glob('**', {
|
||||
cwd: staticFilePath,
|
||||
});
|
||||
|
||||
return staticFiles;
|
||||
}
|
||||
|
||||
export async function createBuildOutput(
|
||||
workPath: string
|
||||
): Promise<BuildResultV2> {
|
||||
let output: Files = {};
|
||||
const routes: Route[] = [];
|
||||
|
||||
const extraOutputs = await readBuildOutputDirectory({
|
||||
workPath,
|
||||
});
|
||||
|
||||
if (extraOutputs.routes) {
|
||||
routes.push(...extraOutputs.routes);
|
||||
}
|
||||
|
||||
if (extraOutputs.staticFiles) {
|
||||
output = Object.assign(
|
||||
{},
|
||||
extraOutputs.staticFiles,
|
||||
extraOutputs.functions
|
||||
);
|
||||
}
|
||||
|
||||
return { routes, output };
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
import { join } from 'path';
|
||||
import { promises as fs } from 'fs';
|
||||
import { BuildResultV2, Meta } from '../../../build-utils/dist';
|
||||
import { Framework } from '../../../frameworks/dist/types';
|
||||
|
||||
const BUILD_OUTPUT_DIR = '.vercel/output';
|
||||
|
||||
/**
|
||||
* Returns the path to the Build Output API v3 directory when the
|
||||
* Returns the path to the Build Output v3 directory when the
|
||||
* `config.json` file was created by the framework / build script,
|
||||
* or `undefined` if the framework did not create the v3 output.
|
||||
*/
|
||||
@@ -36,27 +34,3 @@ export async function readConfig(
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function createBuildOutput(
|
||||
meta: Meta,
|
||||
buildCommand: string | null,
|
||||
buildOutputPath: string,
|
||||
framework?: Framework
|
||||
): BuildResultV2 {
|
||||
if (!meta.cliVersion) {
|
||||
let buildCommandName: string;
|
||||
|
||||
if (buildCommand) buildCommandName = `"${buildCommand}"`;
|
||||
else if (framework) buildCommandName = framework.name;
|
||||
else buildCommandName = 'the "build" script';
|
||||
|
||||
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.`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
buildOutputVersion: 3,
|
||||
buildOutputPath,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
yarn.lock
|
||||
@@ -3,5 +3,5 @@ fs.mkdirSync('.vercel/output/static', { recursive: true });
|
||||
fs.writeFileSync('.vercel/output/config.json', '{}');
|
||||
fs.writeFileSync(
|
||||
'.vercel/output/static/index.html',
|
||||
'<h1>Build Output API v3</h1>'
|
||||
'<h1>Build Output API</h1>'
|
||||
);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
yarn.lock
|
||||
@@ -1,60 +0,0 @@
|
||||
const fs = require('fs');
|
||||
|
||||
fs.mkdirSync('.output/static', { recursive: true });
|
||||
fs.mkdirSync('.output/server/pages/api', { recursive: true });
|
||||
|
||||
fs.writeFileSync(
|
||||
'.output/functions-manifest.json',
|
||||
JSON.stringify(
|
||||
{
|
||||
version: 1,
|
||||
pages: {
|
||||
'_middleware.js': {
|
||||
runtime: 'web',
|
||||
env: [],
|
||||
files: ['server/pages/_middleware.js'],
|
||||
name: 'pages/_middleware',
|
||||
page: '/',
|
||||
regexp: '^/.*$',
|
||||
sortingIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
fs.writeFileSync('.output/static/index.html', '<h1>Build Output API v2</h1>');
|
||||
|
||||
fs.writeFileSync('.output/server/pages/about.html', '<h1>Some Site</h1>');
|
||||
|
||||
fs.writeFileSync(
|
||||
'.output/server/pages/api/user.js',
|
||||
`export default function handler(request, response) {
|
||||
response.status(200).json({
|
||||
body: 'some user info'
|
||||
});
|
||||
}`
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
'.output/server/pages/_middleware.js',
|
||||
`
|
||||
const getResult = (body, options) => ({
|
||||
promise: Promise.resolve(),
|
||||
waitUntil: Promise.resolve(),
|
||||
response: new Response(body, options),
|
||||
});
|
||||
|
||||
_ENTRIES = typeof _ENTRIES === 'undefined' ? {} : _ENTRIES;
|
||||
|
||||
_ENTRIES['middleware_pages/_middleware'] = {
|
||||
default: async function ({ request }) {
|
||||
|
||||
return getResult('hi from the edge', {});
|
||||
|
||||
},
|
||||
};
|
||||
`
|
||||
);
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "10-build-output-v2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "node build.js"
|
||||
}
|
||||
}
|
||||
108
packages/static-build/test/build.test.ts
vendored
108
packages/static-build/test/build.test.ts
vendored
@@ -1,88 +1,54 @@
|
||||
import path from 'path';
|
||||
import { remove } from 'fs-extra';
|
||||
import { build } from '../src';
|
||||
|
||||
describe('build()', () => {
|
||||
describe('Build Output API v2', () => {
|
||||
it('should detect the output format', async () => {
|
||||
const workPath = path.join(
|
||||
__dirname,
|
||||
'build-fixtures',
|
||||
'10-build-output-v2'
|
||||
);
|
||||
|
||||
try {
|
||||
const buildResult = await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
skipDownload: true,
|
||||
cliVersion: '0.0.0',
|
||||
},
|
||||
});
|
||||
if ('buildOutputVersion' in buildResult) {
|
||||
throw new Error('Unexpected `buildOutputVersion` in build result');
|
||||
}
|
||||
|
||||
expect(buildResult.output['index.html']).toBeTruthy();
|
||||
expect(buildResult.output['middleware']).toBeTruthy();
|
||||
} finally {
|
||||
remove(path.join(workPath, '.output'));
|
||||
}
|
||||
it('should detect Builder Output v3', async () => {
|
||||
const workPath = path.join(
|
||||
__dirname,
|
||||
'build-fixtures',
|
||||
'09-build-output-v3'
|
||||
);
|
||||
const buildResult = await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
skipDownload: true,
|
||||
cliVersion: '0.0.0',
|
||||
},
|
||||
});
|
||||
if ('output' in buildResult) {
|
||||
throw new Error('Unexpected `output` in build result');
|
||||
}
|
||||
expect(buildResult.buildOutputVersion).toEqual(3);
|
||||
expect(buildResult.buildOutputPath).toEqual(
|
||||
path.join(workPath, '.vercel/output')
|
||||
);
|
||||
});
|
||||
|
||||
describe('Build Output API v3', () => {
|
||||
it('should detect the output format', async () => {
|
||||
const workPath = path.join(
|
||||
__dirname,
|
||||
'build-fixtures',
|
||||
'09-build-output-v3'
|
||||
);
|
||||
const buildResult = await build({
|
||||
it('should throw an Error with Builder Output v3 without `vercel build`', async () => {
|
||||
let err;
|
||||
const workPath = path.join(
|
||||
__dirname,
|
||||
'build-fixtures',
|
||||
'09-build-output-v3'
|
||||
);
|
||||
try {
|
||||
await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
skipDownload: true,
|
||||
cliVersion: '0.0.0',
|
||||
},
|
||||
});
|
||||
if ('output' in buildResult) {
|
||||
throw new Error('Unexpected `output` in build result');
|
||||
}
|
||||
expect(buildResult.buildOutputVersion).toEqual(3);
|
||||
expect(buildResult.buildOutputPath).toEqual(
|
||||
path.join(workPath, '.vercel/output')
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw an Error without `vercel build`', async () => {
|
||||
let err;
|
||||
const workPath = path.join(
|
||||
__dirname,
|
||||
'build-fixtures',
|
||||
'09-build-output-v3'
|
||||
);
|
||||
try {
|
||||
await build({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
skipDownload: true,
|
||||
},
|
||||
});
|
||||
} catch (_err: any) {
|
||||
err = _err;
|
||||
}
|
||||
expect(err.message).toEqual(
|
||||
`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.`
|
||||
);
|
||||
});
|
||||
} catch (_err: any) {
|
||||
err = _err;
|
||||
}
|
||||
expect(err.message).toEqual(
|
||||
`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.`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user