mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 12:57:46 +00:00
Compare commits
6 Commits
vercel-plu
...
vercel-plu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3abf73f58 | ||
|
|
4873b8b379 | ||
|
|
6248139281 | ||
|
|
507a5de3cd | ||
|
|
be1c78e72f | ||
|
|
c277c649c6 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "2.12.3-canary.17",
|
||||
"version": "2.12.3-canary.18",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from 'fs-extra';
|
||||
import { join, dirname, relative } from 'path';
|
||||
import glob from './fs/glob';
|
||||
import { normalizePath } from './fs/normalize-path';
|
||||
import { FILES_SYMBOL, Lambda } from './lambda';
|
||||
import { FILES_SYMBOL, getLambdaOptionsFromFunction, Lambda } from './lambda';
|
||||
import type FileBlob from './file-blob';
|
||||
import type { BuilderFunctions, BuildOptions, Files } from './types';
|
||||
import minimatch from 'minimatch';
|
||||
@@ -21,8 +21,8 @@ export function convertRuntimeToPlugin(
|
||||
const files = await glob('**', opts);
|
||||
delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
|
||||
const entrypoints = await glob(`api/**/*${ext}`, opts);
|
||||
const functionsManifest: { [key: string]: any } = {};
|
||||
const functions = await readVercelConfigFunctions(workPath);
|
||||
const pages: { [key: string]: any } = {};
|
||||
const { functions = {} } = await readVercelConfig(workPath);
|
||||
const traceDir = join(workPath, '.output', 'runtime-traced-files');
|
||||
await fs.ensureDir(traceDir);
|
||||
|
||||
@@ -44,11 +44,11 @@ export function convertRuntimeToPlugin(
|
||||
},
|
||||
});
|
||||
|
||||
functionsManifest[entrypoint] = {
|
||||
pages[entrypoint] = {
|
||||
handler: output.handler,
|
||||
runtime: output.runtime,
|
||||
memory: config.memory || output.memory,
|
||||
maxDuration: config.maxDuration || output.maxDuration,
|
||||
memory: output.memory,
|
||||
maxDuration: output.maxDuration,
|
||||
environment: output.environment,
|
||||
allowQuery: output.allowQuery,
|
||||
regions: output.regions,
|
||||
@@ -98,10 +98,7 @@ export function convertRuntimeToPlugin(
|
||||
await fs.writeFile(nft, json);
|
||||
}
|
||||
|
||||
await fs.writeFile(
|
||||
join(workPath, '.output', 'functions-manifest.json'),
|
||||
JSON.stringify(functionsManifest)
|
||||
);
|
||||
await updateFunctionsManifest({ workPath, pages });
|
||||
};
|
||||
}
|
||||
|
||||
@@ -115,14 +112,10 @@ async function linkOrCopy(existingPath: string, newPath: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function readVercelConfigFunctions(
|
||||
workPath: string
|
||||
): Promise<BuilderFunctions> {
|
||||
const vercelJsonPath = join(workPath, 'vercel.json');
|
||||
async function readJson(filePath: string): Promise<{ [key: string]: any }> {
|
||||
try {
|
||||
const str = await fs.readFile(vercelJsonPath, 'utf8');
|
||||
const obj = JSON.parse(str);
|
||||
return obj.functions || {};
|
||||
const str = await fs.readFile(filePath, 'utf8');
|
||||
return JSON.parse(str);
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return {};
|
||||
@@ -130,3 +123,49 @@ async function readVercelConfigFunctions(
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function readVercelConfig(
|
||||
workPath: string
|
||||
): Promise<{ functions?: BuilderFunctions; regions?: string[] }> {
|
||||
const vercelJsonPath = join(workPath, 'vercel.json');
|
||||
return readJson(vercelJsonPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* If `.output/functions-manifest.json` exists, append to the pages
|
||||
* property. Otherwise write a new file. This will also read `vercel.json`
|
||||
* and apply relevant `functions` property config.
|
||||
*/
|
||||
export async function updateFunctionsManifest({
|
||||
workPath,
|
||||
pages,
|
||||
}: {
|
||||
workPath: string;
|
||||
pages: { [key: string]: any };
|
||||
}) {
|
||||
const functionsManifestPath = join(
|
||||
workPath,
|
||||
'.output',
|
||||
'functions-manifest.json'
|
||||
);
|
||||
const vercelConfig = await readVercelConfig(workPath);
|
||||
const functionsManifest = await readJson(functionsManifestPath);
|
||||
|
||||
if (!functionsManifest.version) functionsManifest.version = 1;
|
||||
if (!functionsManifest.pages) functionsManifest.pages = {};
|
||||
|
||||
for (const [pageKey, pageConfig] of Object.entries(pages)) {
|
||||
const fnConfig = await getLambdaOptionsFromFunction({
|
||||
sourceFile: pageKey,
|
||||
config: vercelConfig,
|
||||
});
|
||||
functionsManifest.pages[pageKey] = {
|
||||
...pageConfig,
|
||||
memory: fnConfig.memory || pageConfig.memory,
|
||||
maxDuration: fnConfig.maxDuration || pageConfig.maxDuration,
|
||||
regions: vercelConfig.regions || pageConfig.regions,
|
||||
};
|
||||
}
|
||||
|
||||
await fs.writeFile(functionsManifestPath, JSON.stringify(functionsManifest));
|
||||
}
|
||||
|
||||
@@ -82,7 +82,10 @@ export { detectFramework } from './detect-framework';
|
||||
export { DetectorFilesystem } from './detectors/filesystem';
|
||||
export { readConfigFile } from './fs/read-config-file';
|
||||
export { normalizePath } from './fs/normalize-path';
|
||||
export { convertRuntimeToPlugin } from './convert-runtime-to-plugin';
|
||||
export {
|
||||
convertRuntimeToPlugin,
|
||||
updateFunctionsManifest,
|
||||
} from './convert-runtime-to-plugin';
|
||||
|
||||
export * from './schemas';
|
||||
export * from './types';
|
||||
|
||||
@@ -36,7 +36,7 @@ interface CreateLambdaOptions {
|
||||
|
||||
interface GetLambdaOptionsFromFunctionOptions {
|
||||
sourceFile: string;
|
||||
config?: Config;
|
||||
config?: Pick<Config, 'functions'>;
|
||||
}
|
||||
|
||||
export const FILES_SYMBOL = Symbol('files');
|
||||
|
||||
@@ -71,9 +71,12 @@ describe('convert-runtime-to-plugin', () => {
|
||||
|
||||
const funcManifest = JSON.parse(output['functions-manifest.json']);
|
||||
expect(funcManifest).toMatchObject({
|
||||
'api/index.py': lambdaOptions,
|
||||
'api/users/get.py': lambdaOptions,
|
||||
'api/users/post.py': { ...lambdaOptions, memory: 3008 },
|
||||
version: 1,
|
||||
pages: {
|
||||
'api/index.py': lambdaOptions,
|
||||
'api/users/get.py': lambdaOptions,
|
||||
'api/users/post.py': { ...lambdaOptions, memory: 3008 },
|
||||
},
|
||||
});
|
||||
|
||||
const indexJson = JSON.parse(output.server.pages.api['index.py.nft.json']);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "23.1.3-canary.28",
|
||||
"version": "23.1.3-canary.30",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -43,14 +43,14 @@
|
||||
"node": ">= 12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.12.3-canary.17",
|
||||
"@vercel/build-utils": "2.12.3-canary.18",
|
||||
"@vercel/go": "1.2.4-canary.3",
|
||||
"@vercel/node": "1.12.2-canary.6",
|
||||
"@vercel/python": "2.0.6-canary.5",
|
||||
"@vercel/ruby": "1.2.8-canary.4",
|
||||
"update-notifier": "4.1.0",
|
||||
"vercel-plugin-middleware": "0.0.0-canary.6",
|
||||
"vercel-plugin-node": "1.12.2-canary.7"
|
||||
"vercel-plugin-middleware": "0.0.0-canary.7",
|
||||
"vercel-plugin-node": "1.12.2-canary.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/env": "11.1.2",
|
||||
|
||||
@@ -78,6 +78,22 @@ const fields: {
|
||||
];
|
||||
|
||||
export default async function main(client: Client) {
|
||||
if (process.env.__VERCEL_BUILD_RUNNING) {
|
||||
client.output.error(
|
||||
`${cmd(
|
||||
`${getPkgName()} build`
|
||||
)} must not recursively invoke itself. Check the Build Command in the Project Settings or the ${cmd(
|
||||
'build'
|
||||
)} script in ${cmd('package.json')}`
|
||||
);
|
||||
client.output.error(
|
||||
`Learn More: https://vercel.link/recursive-invocation-of-commands`
|
||||
);
|
||||
return 1;
|
||||
} else {
|
||||
process.env.__VERCEL_BUILD_RUNNING = '1';
|
||||
}
|
||||
|
||||
let argv;
|
||||
const buildStamp = stamp();
|
||||
try {
|
||||
|
||||
@@ -48,6 +48,22 @@ const help = () => {
|
||||
};
|
||||
|
||||
export default async function main(client: Client) {
|
||||
if (process.env.__VERCEL_DEV_RUNNING) {
|
||||
client.output.error(
|
||||
`${cmd(
|
||||
`${getPkgName()} dev`
|
||||
)} must not recursively invoke itself. Check the Development Command in the Project Settings or the ${cmd(
|
||||
'dev'
|
||||
)} script in ${cmd('package.json')}`
|
||||
);
|
||||
client.output.error(
|
||||
`Learn More: https://vercel.link/recursive-invocation-of-commands`
|
||||
);
|
||||
return 1;
|
||||
} else {
|
||||
process.env.__VERCEL_DEV_RUNNING = '1';
|
||||
}
|
||||
|
||||
let argv;
|
||||
let args;
|
||||
const { output } = client;
|
||||
@@ -90,22 +106,21 @@ export default async function main(client: Client) {
|
||||
if (pkg) {
|
||||
const { scripts } = pkg as PackageJson;
|
||||
|
||||
if (scripts && scripts.dev && /\bnow\b\W+\bdev\b/.test(scripts.dev)) {
|
||||
output.error(
|
||||
`The ${cmd('dev')} script in ${cmd(
|
||||
'package.json'
|
||||
)} must not contain ${cmd('now dev')}`
|
||||
if (
|
||||
scripts &&
|
||||
scripts.dev &&
|
||||
/\b(now|vercel)\b\W+\bdev\b/.test(scripts.dev)
|
||||
) {
|
||||
client.output.error(
|
||||
`${cmd(
|
||||
`${getPkgName()} dev`
|
||||
)} must not recursively invoke itself. Check the Development Command in the Project Settings or the ${cmd(
|
||||
'dev'
|
||||
)} script in ${cmd('package.json')}`
|
||||
);
|
||||
output.error(`Learn More: http://err.sh/vercel/now-dev-as-dev-script`);
|
||||
return 1;
|
||||
}
|
||||
if (scripts && scripts.dev && /\bvercel\b\W+\bdev\b/.test(scripts.dev)) {
|
||||
output.error(
|
||||
`The ${cmd('dev')} script in ${cmd(
|
||||
'package.json'
|
||||
)} must not contain ${cmd('vercel dev')}`
|
||||
client.output.error(
|
||||
`Learn More: https://vercel.link/recursive-invocation-of-commands`
|
||||
);
|
||||
output.error(`Learn More: http://err.sh/vercel/now-dev-as-dev-script`);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,8 @@ export const isDirectory = (path: string): boolean => {
|
||||
const getGlobalPathConfig = (): string => {
|
||||
let customPath: string | undefined;
|
||||
|
||||
try {
|
||||
const argv = getArgs(process.argv.slice(2), {});
|
||||
customPath = argv['--global-config'];
|
||||
} catch (_error) {
|
||||
// args are optional so consume error
|
||||
}
|
||||
const argv = getArgs(process.argv.slice(2), {}, { permissive: true });
|
||||
customPath = argv['--global-config'];
|
||||
|
||||
const vercelDirectories = XDGAppPaths('com.vercel.cli').dataDirs();
|
||||
|
||||
|
||||
@@ -7,12 +7,8 @@ import getArgs from '../../util/get-args';
|
||||
export default function getLocalPathConfig(prefix: string) {
|
||||
let customPath: string | undefined;
|
||||
|
||||
try {
|
||||
const argv = getArgs(process.argv.slice(2), {});
|
||||
customPath = argv['--local-config'];
|
||||
} catch (_error) {
|
||||
// args are optional so consume error
|
||||
}
|
||||
const argv = getArgs(process.argv.slice(2), {}, { permissive: true });
|
||||
customPath = argv['--local-config'];
|
||||
|
||||
// If `--local-config` flag was specified, then that takes priority
|
||||
if (customPath) {
|
||||
|
||||
@@ -1358,13 +1358,20 @@ export default class DevServer {
|
||||
this.cwd,
|
||||
this.output
|
||||
);
|
||||
for (let plugin of devMiddlewarePlugins) {
|
||||
const result = await plugin.plugin.runDevMiddleware(req, res, this.cwd);
|
||||
if (result.finished) {
|
||||
return result;
|
||||
try {
|
||||
for (let plugin of devMiddlewarePlugins) {
|
||||
const result = await plugin.plugin.runDevMiddleware(req, res, this.cwd);
|
||||
if (result.finished) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return { finished: false };
|
||||
} catch (e) {
|
||||
return {
|
||||
finished: true,
|
||||
error: e,
|
||||
};
|
||||
}
|
||||
return { finished: false };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2154,7 +2161,10 @@ export default class DevServer {
|
||||
process.stdout.write(data.replace(proxyPort, devPort));
|
||||
});
|
||||
|
||||
p.on('exit', () => {
|
||||
p.on('exit', (code: number) => {
|
||||
if (code > 0) {
|
||||
process.exit(code);
|
||||
}
|
||||
this.devProcessPort = undefined;
|
||||
});
|
||||
|
||||
|
||||
3
packages/cli/test/fixtures/unit/edge-middleware-invalid-response/_middleware.js
vendored
Normal file
3
packages/cli/test/fixtures/unit/edge-middleware-invalid-response/_middleware.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function () {
|
||||
return 'freecandy';
|
||||
}
|
||||
@@ -19,7 +19,7 @@ const getRevertAliasConfigFile = () => {
|
||||
],
|
||||
});
|
||||
};
|
||||
module.exports = async function prepare(session) {
|
||||
module.exports = async function prepare(session, binaryPath) {
|
||||
const spec = {
|
||||
'static-single-file': {
|
||||
'first.png': getImageFile(session, { size: 30 }),
|
||||
@@ -114,6 +114,23 @@ module.exports = async function prepare(session) {
|
||||
2
|
||||
),
|
||||
},
|
||||
'dev-fail-on-recursion-command': {
|
||||
'package.json': '{}',
|
||||
},
|
||||
'build-fail-on-recursion-command': {
|
||||
'package.json': '{}',
|
||||
},
|
||||
'build-fail-on-recursion-script': {
|
||||
'package.json': JSON.stringify(
|
||||
{
|
||||
scripts: {
|
||||
build: `${binaryPath} build`,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
},
|
||||
'static-deployment': {
|
||||
'index.txt': 'Hello World',
|
||||
},
|
||||
|
||||
369
packages/cli/test/integration.js
vendored
369
packages/cli/test/integration.js
vendored
@@ -252,10 +252,69 @@ const createUser = async () => {
|
||||
|
||||
const getConfigAuthPath = () => path.join(globalDir, 'auth.json');
|
||||
|
||||
async function setupProject(process, projectName, overrides) {
|
||||
await waitForPrompt(process, chunk => /Set up [^?]+\?/.test(chunk));
|
||||
process.stdin.write('yes\n');
|
||||
|
||||
await waitForPrompt(process, chunk => /Which scope [^?]+\?/.test(chunk));
|
||||
process.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(process, chunk =>
|
||||
chunk.includes('Link to existing project?')
|
||||
);
|
||||
process.stdin.write('no\n');
|
||||
|
||||
await waitForPrompt(process, chunk =>
|
||||
chunk.includes('What’s your project’s name?')
|
||||
);
|
||||
process.stdin.write(`${projectName}\n`);
|
||||
|
||||
await waitForPrompt(process, chunk =>
|
||||
chunk.includes('In which directory is your code located?')
|
||||
);
|
||||
process.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(process, chunk =>
|
||||
chunk.includes('Want to override the settings?')
|
||||
);
|
||||
|
||||
if (overrides) {
|
||||
process.stdin.write('yes\n');
|
||||
|
||||
const { buildCommand, outputDirectory, devCommand } = overrides;
|
||||
|
||||
await waitForPrompt(process, chunk =>
|
||||
chunk.includes(
|
||||
'Which settings would you like to overwrite (select multiple)?'
|
||||
)
|
||||
);
|
||||
process.stdin.write('a\n'); // 'a' means select all
|
||||
|
||||
await waitForPrompt(process, chunk =>
|
||||
chunk.includes(`What's your Build Command?`)
|
||||
);
|
||||
process.stdin.write(`${buildCommand ?? ''}\n`);
|
||||
|
||||
await waitForPrompt(process, chunk =>
|
||||
chunk.includes(`What's your Output Directory?`)
|
||||
);
|
||||
process.stdin.write(`${outputDirectory ?? ''}\n`);
|
||||
|
||||
await waitForPrompt(process, chunk =>
|
||||
chunk.includes(`What's your Development Command?`)
|
||||
);
|
||||
process.stdin.write(`${devCommand ?? ''}\n`);
|
||||
} else {
|
||||
process.stdin.write('no\n');
|
||||
}
|
||||
|
||||
await waitForPrompt(process, chunk => chunk.includes('Linked to'));
|
||||
}
|
||||
|
||||
test.before(async () => {
|
||||
try {
|
||||
await createUser();
|
||||
await prepareFixtures(contextName);
|
||||
await prepareFixtures(contextName, binaryPath);
|
||||
} catch (err) {
|
||||
console.log('Failed `test.before`');
|
||||
console.log(err);
|
||||
@@ -2227,13 +2286,93 @@ test('whoami', async t => {
|
||||
t.is(stdout, contextName, formatOutput({ stdout, stderr }));
|
||||
});
|
||||
|
||||
test('fail `now dev` dev script without now.json', async t => {
|
||||
test('[vercel dev] fails when dev script calls vercel dev recursively', async t => {
|
||||
const deploymentPath = fixture('now-dev-fail-dev-script');
|
||||
const { exitCode, stderr } = await execute(['dev', deploymentPath]);
|
||||
|
||||
t.is(exitCode, 1);
|
||||
t.true(
|
||||
stderr.includes('must not contain `now dev`'),
|
||||
stderr.includes('must not recursively invoke itself'),
|
||||
`Received instead: "${stderr}"`
|
||||
);
|
||||
});
|
||||
|
||||
test('[vercel dev] fails when development commad calls vercel dev recursively', async t => {
|
||||
const dir = fixture('dev-fail-on-recursion-command');
|
||||
const projectName = `dev-fail-on-recursion-command-${
|
||||
Math.random().toString(36).split('.')[1]
|
||||
}`;
|
||||
|
||||
const dev = execa(binaryPath, ['dev', ...defaultArgs], {
|
||||
cwd: dir,
|
||||
reject: false,
|
||||
});
|
||||
|
||||
await setupProject(dev, projectName, {
|
||||
devCommand: `${binaryPath} dev`,
|
||||
});
|
||||
|
||||
const { exitCode, stderr } = await dev;
|
||||
|
||||
t.is(exitCode, 1);
|
||||
t.true(
|
||||
stderr.includes('must not recursively invoke itself'),
|
||||
`Received instead: "${stderr}"`
|
||||
);
|
||||
});
|
||||
|
||||
test('[vercel build] fails when build commad calls vercel build recursively', async t => {
|
||||
const dir = fixture('build-fail-on-recursion-command');
|
||||
const projectName = `build-fail-on-recursion-command-${
|
||||
Math.random().toString(36).split('.')[1]
|
||||
}`;
|
||||
|
||||
const build = execa(binaryPath, ['build', ...defaultArgs], {
|
||||
cwd: dir,
|
||||
reject: false,
|
||||
});
|
||||
|
||||
await waitForPrompt(build, chunk =>
|
||||
chunk.includes('No Project Settings found locally')
|
||||
);
|
||||
build.stdin.write('yes\n');
|
||||
|
||||
await setupProject(build, projectName, {
|
||||
buildCommand: `${binaryPath} build`,
|
||||
});
|
||||
|
||||
const { exitCode, stderr } = await build;
|
||||
|
||||
t.is(exitCode, 1);
|
||||
t.true(
|
||||
stderr.includes('must not recursively invoke itself'),
|
||||
`Received instead: "${stderr}"`
|
||||
);
|
||||
});
|
||||
|
||||
test('[vercel build] fails when build script calls vercel build recursively', async t => {
|
||||
const dir = fixture('build-fail-on-recursion-script');
|
||||
const projectName = `build-fail-on-recursion-script-${
|
||||
Math.random().toString(36).split('.')[1]
|
||||
}`;
|
||||
|
||||
const build = execa(binaryPath, ['build', ...defaultArgs], {
|
||||
cwd: dir,
|
||||
reject: false,
|
||||
});
|
||||
|
||||
await waitForPrompt(build, chunk =>
|
||||
chunk.includes('No Project Settings found locally')
|
||||
);
|
||||
build.stdin.write('yes\n');
|
||||
|
||||
await setupProject(build, projectName);
|
||||
|
||||
const { exitCode, stderr } = await build;
|
||||
|
||||
t.is(exitCode, 1);
|
||||
t.true(
|
||||
stderr.includes('must not recursively invoke itself'),
|
||||
`Received instead: "${stderr}"`
|
||||
);
|
||||
});
|
||||
@@ -2683,59 +2822,10 @@ test('should show prompts to set up project during first deploy', async t => {
|
||||
|
||||
const now = execa(binaryPath, [dir, ...defaultArgs]);
|
||||
|
||||
await waitForPrompt(now, chunk => /Set up and deploy [^?]+\?/.test(chunk));
|
||||
now.stdin.write('yes\n');
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('Which scope do you want to deploy to?')
|
||||
);
|
||||
now.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('Link to existing project?')
|
||||
);
|
||||
now.stdin.write('no\n');
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('What’s your project’s name?')
|
||||
);
|
||||
now.stdin.write(`${projectName}\n`);
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('In which directory is your code located?')
|
||||
);
|
||||
now.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('Want to override the settings?')
|
||||
);
|
||||
now.stdin.write('yes\n');
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes(
|
||||
'Which settings would you like to overwrite (select multiple)?'
|
||||
)
|
||||
);
|
||||
now.stdin.write('a\n'); // 'a' means select all
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes(`What's your Build Command?`)
|
||||
);
|
||||
now.stdin.write(
|
||||
`mkdir -p o && echo '<h1>custom hello</h1>' > o/index.html\n`
|
||||
);
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes(`What's your Output Directory?`)
|
||||
);
|
||||
now.stdin.write(`o\n`);
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes(`What's your Development Command?`)
|
||||
);
|
||||
now.stdin.write(`\n`);
|
||||
|
||||
await waitForPrompt(now, chunk => chunk.includes('Linked to'));
|
||||
await setupProject(now, projectName, {
|
||||
buildCommand: `mkdir -p o && echo '<h1>custom hello</h1>' > o/index.html`,
|
||||
outputDirectory: 'o',
|
||||
});
|
||||
|
||||
const output = await now;
|
||||
|
||||
@@ -3301,55 +3391,10 @@ test('[vc link] should show prompts to set up project', async t => {
|
||||
|
||||
const vc = execa(binaryPath, ['link', ...defaultArgs], { cwd: dir });
|
||||
|
||||
await waitForPrompt(vc, chunk => /Set up [^?]+\?/.test(chunk));
|
||||
vc.stdin.write('yes\n');
|
||||
|
||||
await waitForPrompt(vc, chunk =>
|
||||
chunk.includes('Which scope should contain your project?')
|
||||
);
|
||||
vc.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(vc, chunk => chunk.includes('Link to existing project?'));
|
||||
vc.stdin.write('no\n');
|
||||
|
||||
await waitForPrompt(vc, chunk =>
|
||||
chunk.includes('What’s your project’s name?')
|
||||
);
|
||||
vc.stdin.write(`${projectName}\n`);
|
||||
|
||||
await waitForPrompt(vc, chunk =>
|
||||
chunk.includes('In which directory is your code located?')
|
||||
);
|
||||
vc.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(vc, chunk =>
|
||||
chunk.includes('Want to override the settings?')
|
||||
);
|
||||
vc.stdin.write('yes\n');
|
||||
|
||||
await waitForPrompt(vc, chunk =>
|
||||
chunk.includes(
|
||||
'Which settings would you like to overwrite (select multiple)?'
|
||||
)
|
||||
);
|
||||
vc.stdin.write('a\n'); // 'a' means select all
|
||||
|
||||
await waitForPrompt(vc, chunk =>
|
||||
chunk.includes(`What's your Build Command?`)
|
||||
);
|
||||
vc.stdin.write(`mkdir -p o && echo '<h1>custom hello</h1>' > o/index.html\n`);
|
||||
|
||||
await waitForPrompt(vc, chunk =>
|
||||
chunk.includes(`What's your Output Directory?`)
|
||||
);
|
||||
vc.stdin.write(`o\n`);
|
||||
|
||||
await waitForPrompt(vc, chunk =>
|
||||
chunk.includes(`What's your Development Command?`)
|
||||
);
|
||||
vc.stdin.write(`\n`);
|
||||
|
||||
await waitForPrompt(vc, chunk => chunk.includes('Linked to'));
|
||||
await setupProject(vc, projectName, {
|
||||
buildCommand: `mkdir -p o && echo '<h1>custom hello</h1>' > o/index.html`,
|
||||
outputDirectory: 'o',
|
||||
});
|
||||
|
||||
const output = await vc;
|
||||
|
||||
@@ -3422,59 +3467,10 @@ test('[vc dev] should show prompts to set up project', async t => {
|
||||
cwd: dir,
|
||||
});
|
||||
|
||||
await waitForPrompt(dev, chunk => /Set up and develop [^?]+\?/.test(chunk));
|
||||
dev.stdin.write('yes\n');
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('Which scope should contain your project?')
|
||||
);
|
||||
dev.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('Link to existing project?')
|
||||
);
|
||||
dev.stdin.write('no\n');
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('What’s your project’s name?')
|
||||
);
|
||||
dev.stdin.write(`${projectName}\n`);
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('In which directory is your code located?')
|
||||
);
|
||||
dev.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('Want to override the settings?')
|
||||
);
|
||||
dev.stdin.write('yes\n');
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes(
|
||||
'Which settings would you like to overwrite (select multiple)?'
|
||||
)
|
||||
);
|
||||
dev.stdin.write('a\n'); // 'a' means select all
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes(`What's your Build Command?`)
|
||||
);
|
||||
dev.stdin.write(
|
||||
`mkdir -p o && echo '<h1>custom hello</h1>' > o/index.html\n`
|
||||
);
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes(`What's your Output Directory?`)
|
||||
);
|
||||
dev.stdin.write(`o\n`);
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes(`What's your Development Command?`)
|
||||
);
|
||||
dev.stdin.write(`\n`);
|
||||
|
||||
await waitForPrompt(dev, chunk => chunk.includes('Linked to'));
|
||||
await setupProject(dev, projectName, {
|
||||
buildCommand: `mkdir -p o && echo '<h1>custom hello</h1>' > o/index.html`,
|
||||
outputDirectory: 'o',
|
||||
});
|
||||
|
||||
// Ensure .gitignore is created
|
||||
const gitignore = await readFile(path.join(dir, '.gitignore'), 'utf8');
|
||||
@@ -3574,59 +3570,12 @@ test('[vc dev] should send the platform proxy request headers to frontend dev se
|
||||
cwd: dir,
|
||||
});
|
||||
|
||||
await waitForPrompt(dev, chunk => /Set up and develop [^?]+\?/.test(chunk));
|
||||
dev.stdin.write('yes\n');
|
||||
await setupProject(dev, projectName, {
|
||||
buildCommand: `mkdir -p o && echo '<h1>custom hello</h1>' > o/index.html`,
|
||||
outputDirectory: 'o',
|
||||
devCommand: 'node server.js',
|
||||
});
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('Which scope should contain your project?')
|
||||
);
|
||||
dev.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('Link to existing project?')
|
||||
);
|
||||
dev.stdin.write('no\n');
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('What’s your project’s name?')
|
||||
);
|
||||
dev.stdin.write(`${projectName}\n`);
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('In which directory is your code located?')
|
||||
);
|
||||
dev.stdin.write('\n');
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes('Want to override the settings?')
|
||||
);
|
||||
dev.stdin.write('yes\n');
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes(
|
||||
'Which settings would you like to overwrite (select multiple)?'
|
||||
)
|
||||
);
|
||||
dev.stdin.write('a\n'); // 'a' means select all
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes(`What's your Build Command?`)
|
||||
);
|
||||
dev.stdin.write(
|
||||
`mkdir -p o && echo '<h1>custom hello</h1>' > o/index.html\n`
|
||||
);
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes(`What's your Output Directory?`)
|
||||
);
|
||||
dev.stdin.write(`o\n`);
|
||||
|
||||
await waitForPrompt(dev, chunk =>
|
||||
chunk.includes(`What's your Development Command?`)
|
||||
);
|
||||
dev.stdin.write(`node server.js\n`);
|
||||
|
||||
await waitForPrompt(dev, chunk => chunk.includes('Linked to'));
|
||||
await waitForPrompt(dev, chunk => chunk.includes('Ready! Available at'));
|
||||
|
||||
// Ensure that `vc dev` also works
|
||||
|
||||
@@ -374,4 +374,15 @@ describe('DevServer', () => {
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
it(
|
||||
'should render an error page when the middleware returns not a Response',
|
||||
testFixture('edge-middleware-invalid-response', async server => {
|
||||
const response = await fetch(`${server.address}/index.html`);
|
||||
const body = await response.text();
|
||||
expect(body).toStrictEqual(
|
||||
'A server error has occurred\n\nEDGE_FUNCTION_INVOCATION_FAILED\n'
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "10.2.3-canary.18",
|
||||
"version": "10.2.3-canary.19",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -40,7 +40,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.12.3-canary.17",
|
||||
"@vercel/build-utils": "2.12.3-canary.18",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel-plugin-middleware",
|
||||
"version": "0.0.0-canary.6",
|
||||
"version": "0.0.0-canary.7",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "",
|
||||
|
||||
@@ -3,13 +3,16 @@ _ENTRIES = typeof _ENTRIES === 'undefined' ? {} : _ENTRIES;
|
||||
_ENTRIES['middleware_pages/_middleware'] = {
|
||||
default: async function (ev) {
|
||||
const result = await middleware.default(ev.request, ev);
|
||||
if (result instanceof Response) {
|
||||
return {
|
||||
promise: Promise.resolve(),
|
||||
waitUntil: Promise.resolve(),
|
||||
response: result,
|
||||
};
|
||||
}
|
||||
return result;
|
||||
return {
|
||||
promise: Promise.resolve(),
|
||||
waitUntil: Promise.resolve(),
|
||||
response:
|
||||
result ||
|
||||
new Response(null, {
|
||||
headers: {
|
||||
'x-middleware-next': 1,
|
||||
},
|
||||
}),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
37
packages/middleware/test/build.test.ts
vendored
37
packages/middleware/test/build.test.ts
vendored
@@ -1,8 +1,19 @@
|
||||
import { join } from 'path';
|
||||
import { promises as fsp } from 'fs';
|
||||
import { build } from '../src';
|
||||
import { Response } from 'node-fetch';
|
||||
|
||||
describe('build()', () => {
|
||||
beforeEach(() => {
|
||||
//@ts-ignore
|
||||
global.Response = Response;
|
||||
});
|
||||
afterEach(() => {
|
||||
//@ts-ignore
|
||||
delete global.Response;
|
||||
//@ts-ignore
|
||||
delete global._ENTRIES;
|
||||
});
|
||||
it('should build simple middleware', async () => {
|
||||
const fixture = join(__dirname, 'fixtures/simple');
|
||||
await build({
|
||||
@@ -17,8 +28,30 @@ describe('build()', () => {
|
||||
);
|
||||
expect(middlewareManifest).toMatchSnapshot();
|
||||
|
||||
const outputFile = join(fixture, '.output/server/pages/_middleware.js');
|
||||
expect(await fsp.stat(outputFile)).toBeTruthy();
|
||||
|
||||
require(outputFile);
|
||||
//@ts-ignore
|
||||
const middleware = global._ENTRIES['middleware_pages/_middleware'].default;
|
||||
expect(typeof middleware).toStrictEqual('function');
|
||||
const handledResponse = await middleware({
|
||||
request: {
|
||||
url: 'http://google.com',
|
||||
},
|
||||
});
|
||||
const unhandledResponse = await middleware({
|
||||
request: {
|
||||
url: 'literallyanythingelse',
|
||||
},
|
||||
});
|
||||
expect(String(handledResponse.response.body)).toEqual('Hi from the edge!');
|
||||
expect(
|
||||
await fsp.stat(join(fixture, '.output/server/pages/_middleware.js'))
|
||||
).toBeTruthy();
|
||||
(handledResponse.response as Response).headers.get('x-middleware-next')
|
||||
).toEqual(null);
|
||||
expect(unhandledResponse.response.body).toEqual(null);
|
||||
expect(
|
||||
(unhandledResponse.response as Response).headers.get('x-middleware-next')
|
||||
).toEqual('1');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
export default () => new Response('Hi from the edge!');
|
||||
export default req => {
|
||||
if (req.url === 'http://google.com') {
|
||||
return new Response('Hi from the edge!');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": false,
|
||||
"name": "vercel-plugin-go",
|
||||
"version": "1.0.0-canary.1",
|
||||
"version": "1.0.0-canary.2",
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
@@ -17,7 +17,7 @@
|
||||
"prepublishOnly": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.12.3-canary.17",
|
||||
"@vercel/build-utils": "2.12.3-canary.18",
|
||||
"@vercel/go": "1.2.4-canary.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel-plugin-node",
|
||||
"version": "1.12.2-canary.7",
|
||||
"version": "1.12.2-canary.8",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||
@@ -33,6 +33,7 @@
|
||||
"@types/jest": "27.0.2",
|
||||
"@types/node-fetch": "2",
|
||||
"@types/test-listen": "1.1.0",
|
||||
"@vercel/build-utils": "2.12.3-canary.18",
|
||||
"@vercel/fun": "1.0.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/nft": "0.14.0",
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
debug,
|
||||
isSymbolicLink,
|
||||
runNpmInstall,
|
||||
updateFunctionsManifest,
|
||||
walkParentDirs,
|
||||
} from '@vercel/build-utils';
|
||||
import { FromSchema } from 'json-schema-to-ts';
|
||||
@@ -482,27 +483,13 @@ export async function buildEntrypoint({
|
||||
await finishPromise;
|
||||
}
|
||||
|
||||
// Update the `functions-mainifest.json` file with this entrypoint
|
||||
// TODO NATE: turn this into a `@vercel/plugin-utils` helper function?
|
||||
const functionsManifestPath = join(outputDirPath, 'functions-manifest.json');
|
||||
let functionsManifest: any = {};
|
||||
try {
|
||||
functionsManifest = JSON.parse(
|
||||
await fsp.readFile(functionsManifestPath, 'utf8')
|
||||
);
|
||||
} catch (_err) {
|
||||
// ignore...
|
||||
}
|
||||
if (!functionsManifest.version) functionsManifest.version = 1;
|
||||
if (!functionsManifest.pages) functionsManifest.pages = {};
|
||||
functionsManifest.pages[entrypointWithoutExtIndex] = {
|
||||
handler: `${getFileName(LAUNCHER_FILENAME).slice(0, -3)}.launcher`,
|
||||
runtime: nodeVersion.runtime,
|
||||
const pages = {
|
||||
[entrypointWithoutExtIndex]: {
|
||||
handler: `${getFileName(LAUNCHER_FILENAME).slice(0, -3)}.launcher`,
|
||||
runtime: nodeVersion.runtime,
|
||||
},
|
||||
};
|
||||
await fsp.writeFile(
|
||||
functionsManifestPath,
|
||||
JSON.stringify(functionsManifest, null, 2)
|
||||
);
|
||||
await updateFunctionsManifest({ workPath, pages });
|
||||
|
||||
// Update the `routes-mainifest.json` file with the wildcard route
|
||||
// when the entrypoint is dynamic (i.e. `/api/[id].ts`).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": false,
|
||||
"name": "vercel-plugin-python",
|
||||
"version": "1.0.0-canary.1",
|
||||
"version": "1.0.0-canary.2",
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
@@ -17,7 +17,7 @@
|
||||
"prepublishOnly": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.12.3-canary.17",
|
||||
"@vercel/build-utils": "2.12.3-canary.18",
|
||||
"@vercel/python": "2.0.6-canary.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": false,
|
||||
"name": "vercel-plugin-ruby",
|
||||
"version": "1.0.0-canary.1",
|
||||
"version": "1.0.0-canary.2",
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
@@ -17,7 +17,7 @@
|
||||
"prepublishOnly": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.12.3-canary.17",
|
||||
"@vercel/build-utils": "2.12.3-canary.18",
|
||||
"@vercel/ruby": "1.2.8-canary.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Reference in New Issue
Block a user