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:
Steven
2022-05-13 18:19:38 -04:00
committed by GitHub
parent cd4799b5d5
commit dfb6ef949b
11 changed files with 72 additions and 393 deletions

View File

@@ -2,7 +2,6 @@ dist
worker worker
.solid .solid
.vercel .vercel
.output
# dependencies # dependencies
/node_modules /node_modules

View File

@@ -31,7 +31,6 @@
"devDependencies": { "devDependencies": {
"@types/aws-lambda": "8.10.64", "@types/aws-lambda": "8.10.64",
"@types/cross-spawn": "6.0.0", "@types/cross-spawn": "6.0.0",
"@types/fs-extra": "9.0.13",
"@types/jest": "27.4.1", "@types/jest": "27.4.1",
"@types/ms": "0.7.31", "@types/ms": "0.7.31",
"@types/node-fetch": "2.5.4", "@types/node-fetch": "2.5.4",

View File

@@ -32,7 +32,6 @@ import {
} from '@vercel/build-utils'; } from '@vercel/build-utils';
import type { Route, Source } from '@vercel/routing-utils'; import type { Route, Source } from '@vercel/routing-utils';
import * as BuildOutputV1 from './utils/build-output-v1'; 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 BuildOutputV3 from './utils/build-output-v3';
import * as GatsbyUtils from './utils/gatsby'; import * as GatsbyUtils from './utils/gatsby';
import * as NuxtUtils from './utils/nuxt'; 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 ({ export const build: BuildV2 = async ({
files, files,
entrypoint, entrypoint,
@@ -661,36 +629,48 @@ export const build: BuildV2 = async ({
} }
const outputDirPrefix = path.join(workPath, path.dirname(entrypoint)); 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 // If the Build Command or Framework output files according to the
// Build Output v3 API, then stop processing here in `static-build` // Build Output v3 API, then stop processing here in `static-build`
// since the output is already in its final form. // since the output is already in its final form.
const buildOutputPathV3 = await BuildOutputV3.getBuildOutputDirectory( const buildOutputPath = await BuildOutputV3.getBuildOutputDirectory(
outputDirPrefix outputDirPrefix
); );
if (buildOutputPathV3) {
if (buildOutputPath) {
// Ensure that `vercel build` is being used for this Deployment // Ensure that `vercel build` is being used for this Deployment
return BuildOutputV3.createBuildOutput( if (!meta.cliVersion) {
meta, let buildCommandName: string;
buildCommand, if (buildCommand) buildCommandName = `"${buildCommand}"`;
buildOutputPathV3, else if (framework) buildCommandName = framework.name;
framework 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( if (framework) {
outputDirPrefix const outputDirName = config.outputDirectory
); ? config.outputDirectory
if (buildOutputPathV2) { : await framework.getOutputDirName(outputDirPrefix);
return await BuildOutputV2.createBuildOutput(workPath);
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({ const extraOutputs = await BuildOutputV1.readBuildOutputDirectory({

View File

@@ -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 };
}

View File

@@ -1,12 +1,10 @@
import { join } from 'path'; import { join } from 'path';
import { promises as fs } from 'fs'; 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'; 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, * `config.json` file was created by the framework / build script,
* or `undefined` if the framework did not create the v3 output. * or `undefined` if the framework did not create the v3 output.
*/ */
@@ -36,27 +34,3 @@ export async function readConfig(
} }
return undefined; 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,
};
}

View File

@@ -1 +0,0 @@
yarn.lock

View File

@@ -3,5 +3,5 @@ fs.mkdirSync('.vercel/output/static', { recursive: true });
fs.writeFileSync('.vercel/output/config.json', '{}'); fs.writeFileSync('.vercel/output/config.json', '{}');
fs.writeFileSync( fs.writeFileSync(
'.vercel/output/static/index.html', '.vercel/output/static/index.html',
'<h1>Build Output API v3</h1>' '<h1>Build Output API</h1>'
); );

View File

@@ -1 +0,0 @@
yarn.lock

View File

@@ -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', {});
},
};
`
);

View File

@@ -1,7 +0,0 @@
{
"name": "10-build-output-v2",
"private": true,
"scripts": {
"build": "node build.js"
}
}

View File

@@ -1,88 +1,54 @@
import path from 'path'; import path from 'path';
import { remove } from 'fs-extra';
import { build } from '../src'; import { build } from '../src';
describe('build()', () => { describe('build()', () => {
describe('Build Output API v2', () => { it('should detect Builder Output v3', async () => {
it('should detect the output format', async () => { const workPath = path.join(
const workPath = path.join( __dirname,
__dirname, 'build-fixtures',
'build-fixtures', '09-build-output-v3'
'10-build-output-v2' );
); const buildResult = await build({
files: {},
try { entrypoint: 'package.json',
const buildResult = await build({ workPath,
files: {}, config: {},
entrypoint: 'package.json', meta: {
workPath, skipDownload: true,
config: {}, cliVersion: '0.0.0',
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'));
}
}); });
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 throw an Error with Builder Output v3 without `vercel build`', async () => {
it('should detect the output format', async () => { let err;
const workPath = path.join( const workPath = path.join(
__dirname, __dirname,
'build-fixtures', 'build-fixtures',
'09-build-output-v3' '09-build-output-v3'
); );
const buildResult = await build({ try {
await build({
files: {}, files: {},
entrypoint: 'package.json', entrypoint: 'package.json',
workPath, workPath,
config: {}, config: {},
meta: { meta: {
skipDownload: true, skipDownload: true,
cliVersion: '0.0.0',
}, },
}); });
if ('output' in buildResult) { } catch (_err: any) {
throw new Error('Unexpected `output` in build result'); err = _err;
} }
expect(buildResult.buildOutputVersion).toEqual(3); expect(err.message).toEqual(
expect(buildResult.buildOutputPath).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.`
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.`
);
});
}); });
}); });