mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-06 04:22:01 +00:00
[static-build] Support subset of Build Output API v2 (#7808)
* Revert "Revert "[static-build] Support subset of Build Output API v2" (#7803)"
This reverts commit dfb6ef949b.
* more specific v2 detection
* use nuxt@3.0.0-rc.3 to make sure the incident is resolved
* set test timeout to see if this works in CI
* update CI node version to 14
* add node_modules because it was taking too long to install in CI
* remove timeout
* remove node modules
* remove the nuxt@3 dependency
* finish update to node 14
* blank yarn.lock
* revert node version update
* fix revert
* remove newline
This commit is contained in:
1
examples/solidstart/.gitignore
vendored
1
examples/solidstart/.gitignore
vendored
@@ -2,6 +2,7 @@ dist
|
||||
worker
|
||||
.solid
|
||||
.vercel
|
||||
.output
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"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,6 +32,7 @@ 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';
|
||||
@@ -261,6 +262,37 @@ 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,
|
||||
@@ -629,48 +661,36 @@ 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 buildOutputPath = await BuildOutputV3.getBuildOutputDirectory(
|
||||
const buildOutputPathV3 = await BuildOutputV3.getBuildOutputDirectory(
|
||||
outputDirPrefix
|
||||
);
|
||||
|
||||
if (buildOutputPath) {
|
||||
if (buildOutputPathV3) {
|
||||
// Ensure that `vercel build` is being used for this Deployment
|
||||
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,
|
||||
};
|
||||
return BuildOutputV3.createBuildOutput(
|
||||
meta,
|
||||
buildCommand,
|
||||
buildOutputPathV3,
|
||||
framework
|
||||
);
|
||||
}
|
||||
|
||||
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 buildOutputPathV2 = await BuildOutputV2.getBuildOutputDirectory(
|
||||
outputDirPrefix
|
||||
);
|
||||
if (buildOutputPathV2) {
|
||||
return await BuildOutputV2.createBuildOutput(workPath);
|
||||
}
|
||||
|
||||
const extraOutputs = await BuildOutputV1.readBuildOutputDirectory({
|
||||
|
||||
184
packages/static-build/src/utils/build-output-v2.ts
Normal file
184
packages/static-build/src/utils/build-output-v2.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
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;
|
||||
}
|
||||
`;
|
||||
|
||||
const CONFIG_FILES = [
|
||||
'build-manifest.json',
|
||||
'functions-manifest.json',
|
||||
'images-manifest.json',
|
||||
'prerender-manifest.json',
|
||||
'routes-manifest.json',
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns the path to the Build Output API v2 directory when any
|
||||
* relevant config file was created by the framework / build script,
|
||||
* or `undefined` if the framework did not create the v2 output.
|
||||
*/
|
||||
export async function getBuildOutputDirectory(
|
||||
workingDir: string
|
||||
): Promise<string | undefined> {
|
||||
const outputDir = path.join(workingDir, BUILD_OUTPUT_DIR);
|
||||
|
||||
// check for one of several config files
|
||||
const finderPromises = CONFIG_FILES.map(configFile => {
|
||||
return pathExists(path.join(outputDir, configFile));
|
||||
});
|
||||
|
||||
const finders = await Promise.all(finderPromises);
|
||||
if (finders.some(found => found)) {
|
||||
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,10 +1,12 @@
|
||||
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 v3 directory when the
|
||||
* Returns the path to the Build Output API 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.
|
||||
*/
|
||||
@@ -34,3 +36,27 @@ 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
packages/static-build/test/build-fixtures/09-build-output-v3/.gitignore
vendored
Normal file
1
packages/static-build/test/build-fixtures/09-build-output-v3/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
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</h1>'
|
||||
'<h1>Build Output API v3</h1>'
|
||||
);
|
||||
|
||||
1
packages/static-build/test/build-fixtures/10-build-output-v2/.gitignore
vendored
Normal file
1
packages/static-build/test/build-fixtures/10-build-output-v2/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
yarn.lock
|
||||
60
packages/static-build/test/build-fixtures/10-build-output-v2/build.js
Executable file
60
packages/static-build/test/build-fixtures/10-build-output-v2/build.js
Executable file
@@ -0,0 +1,60 @@
|
||||
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', {});
|
||||
|
||||
},
|
||||
};
|
||||
`
|
||||
);
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "10-build-output-v2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "node build.js"
|
||||
}
|
||||
}
|
||||
1
packages/static-build/test/build-fixtures/11-build-output-v1/.gitignore
vendored
Normal file
1
packages/static-build/test/build-fixtures/11-build-output-v1/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
yarn.lock
|
||||
32
packages/static-build/test/build-fixtures/11-build-output-v1/build.js
Executable file
32
packages/static-build/test/build-fixtures/11-build-output-v1/build.js
Executable file
@@ -0,0 +1,32 @@
|
||||
const fs = require('fs');
|
||||
|
||||
fs.mkdirSync('.vercel_build_output/static', { recursive: true });
|
||||
fs.mkdirSync('.vercel_build_output/config', { recursive: true });
|
||||
|
||||
fs.writeFileSync(
|
||||
'.vercel_build_output/config/functions.json',
|
||||
JSON.stringify(
|
||||
{
|
||||
about: {
|
||||
memory: 3008,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
'.vercel_build_output/static/index.html',
|
||||
'<h1>Build Output API v1</h1>'
|
||||
);
|
||||
|
||||
fs.mkdirSync('.vercel_build_output/functions/node/about', { recursive: true });
|
||||
fs.writeFileSync(
|
||||
'.vercel_build_output/functions/node/about/index.js',
|
||||
`export default function handler(request, response) {
|
||||
response.status(200).json({
|
||||
body: 'some user info'
|
||||
});
|
||||
}`
|
||||
);
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "11-build-output-v1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "node build.js"
|
||||
}
|
||||
}
|
||||
94
packages/static-build/test/build-fixtures/12-build-output-v1-conflict/.gitignore
vendored
Normal file
94
packages/static-build/test/build-fixtures/12-build-output-v1-conflict/.gitignore
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Node template
|
||||
# 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 (https://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
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.build
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# Nuxt generate
|
||||
dist
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# IDE / Editor
|
||||
.idea
|
||||
|
||||
# Service worker
|
||||
sw.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Vim swap files
|
||||
*.swp
|
||||
|
||||
# Vercel
|
||||
.vercel
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"date": "2022-05-18T17:39:45.094Z",
|
||||
"preset": "nitro-prerender",
|
||||
"commands": {
|
||||
"preview": "npx serve -s ./public"
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"node_modules/nuxt/dist/app/entry.mjs": {
|
||||
"file": "entry-51e0e8ac.mjs",
|
||||
"src": "node_modules/nuxt/dist/app/entry.mjs",
|
||||
"isEntry": true,
|
||||
"css": ["entry.fec640a4.css"]
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"node_modules/nuxt/dist/app/entry.mjs": {
|
||||
"file": "entry-51e0e8ac.mjs",
|
||||
"src": "node_modules/nuxt/dist/app/entry.mjs",
|
||||
"isEntry": true,
|
||||
"css": ["entry.fec640a4.css"]
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
|
||||
README.md
|
||||
.nuxt
|
||||
.output
|
||||
node_modules
|
||||
*.log
|
||||
@@ -0,0 +1,10 @@
|
||||
# 12-build-output-v1-conflict
|
||||
|
||||
This fixture was built with the latest (at this time) nuxt 3 release candidate. To produce a potential Build Output API version detection conflict, the following was executed in the fixture directory and committed:
|
||||
|
||||
- `yarn nuxi build`: produced the `.output`
|
||||
- `NOW_BUILDER=1 yarn nuxi build`: produced the `.vercel_build_output`
|
||||
|
||||
The `NOW_BUILDER` env var is being detected by the nuxt build to know to produce the Build Output API v1 format.
|
||||
|
||||
After creating this fixutre, `"nuxt": "3.0.0-rc.3"` was removed from the `package.json` dependencies so that it would not be installed during every test run. It's not necessary to run a test on this fixture and it was causing CI timeouts.
|
||||
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<NuxtWelcome />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,50 @@
|
||||
const fs = require('fs');
|
||||
|
||||
fs.mkdirSync('.vercel_build_output/static', { recursive: true });
|
||||
fs.mkdirSync('.vercel_build_output/config', { recursive: true });
|
||||
|
||||
fs.writeFileSync(
|
||||
'.vercel_build_output/config/functions.json',
|
||||
JSON.stringify(
|
||||
{
|
||||
about: {
|
||||
memory: 3008,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
'.vercel_build_output/static/index.html',
|
||||
'<h1>Build Output API v1</h1>'
|
||||
);
|
||||
|
||||
fs.mkdirSync('.vercel_build_output/functions/node/about', { recursive: true });
|
||||
fs.writeFileSync(
|
||||
'.vercel_build_output/functions/node/about/index.js',
|
||||
`export default function handler(request, response) {
|
||||
response.status(200).json({
|
||||
body: 'some user info'
|
||||
});
|
||||
}`
|
||||
);
|
||||
|
||||
// .output looks like a Build Output API v2 build, but some frameworks (like Nuxt) use it
|
||||
// for their own purposes
|
||||
fs.mkdirSync('.output', { recursive: true });
|
||||
fs.writeFileSync(
|
||||
'.output/nitro.json',
|
||||
JSON.stringify(
|
||||
{
|
||||
date: '2022-05-16T16:18:26.958Z',
|
||||
preset: 'server',
|
||||
commands: {
|
||||
preview: 'node ./server/index.mjs',
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,4 @@
|
||||
import { defineNuxtConfig } from 'nuxt';
|
||||
|
||||
// https://v3.nuxtjs.org/docs/directory-structure/nuxt.config
|
||||
export default defineNuxtConfig({});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "12-build-output-v1-conflict",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxi dev",
|
||||
"build": "echo 'using already built `nuxi generate` for nuxt3'",
|
||||
"start": "node .output/server/index.mjs"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://v3.nuxtjs.org/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
171
packages/static-build/test/build.test.ts
vendored
171
packages/static-build/test/build.test.ts
vendored
@@ -1,56 +1,149 @@
|
||||
import path from 'path';
|
||||
import { remove } from 'fs-extra';
|
||||
import { build } from '../src';
|
||||
|
||||
describe('build()', () => {
|
||||
jest.setTimeout(60 * 1000);
|
||||
jest.setTimeout(60 * 1000);
|
||||
|
||||
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',
|
||||
},
|
||||
describe('build()', () => {
|
||||
describe('Build Output API v1', () => {
|
||||
it('should detect the output format', async () => {
|
||||
const workPath = path.join(
|
||||
__dirname,
|
||||
'build-fixtures',
|
||||
'11-build-output-v1'
|
||||
);
|
||||
|
||||
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();
|
||||
} finally {
|
||||
remove(path.join(workPath, '.vercel_build_output'));
|
||||
}
|
||||
});
|
||||
|
||||
it('should detect the v1 output format when .output exists', async () => {
|
||||
const workPath = path.join(
|
||||
__dirname,
|
||||
'build-fixtures',
|
||||
'12-build-output-v1-conflict'
|
||||
);
|
||||
|
||||
try {
|
||||
process.env.NOW_BUILDER = '1';
|
||||
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();
|
||||
} finally {
|
||||
delete process.env.NOW_BUILDER;
|
||||
}
|
||||
});
|
||||
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 with Builder Output v3 without `vercel build`', async () => {
|
||||
let err;
|
||||
const workPath = path.join(
|
||||
__dirname,
|
||||
'build-fixtures',
|
||||
'09-build-output-v3'
|
||||
);
|
||||
try {
|
||||
await 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'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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({
|
||||
files: {},
|
||||
entrypoint: 'package.json',
|
||||
workPath,
|
||||
config: {},
|
||||
meta: {
|
||||
skipDownload: true,
|
||||
cliVersion: '0.0.0',
|
||||
},
|
||||
});
|
||||
} 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.`
|
||||
);
|
||||
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.`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user