Compare commits

..

10 Commits

Author SHA1 Message Date
Steven
6792edf32a Publish Canary
- @vercel/build-utils@2.12.3-canary.38
 - vercel@23.1.3-canary.61
 - @vercel/client@10.2.3-canary.39
 - @vercel/frameworks@0.5.1-canary.17
 - vercel-plugin-middleware@0.0.0-canary.14
 - vercel-plugin-go@1.0.0-canary.26
 - vercel-plugin-node@1.12.2-canary.30
 - vercel-plugin-python@1.0.0-canary.27
 - vercel-plugin-ruby@1.0.0-canary.26
2021-12-06 14:36:06 -05:00
Steven
67de167a7e [frameworks][cli] Remove duplicate getFsOutputDir() definitions (#7124) 2021-12-06 14:34:30 -05:00
Leo Lamprecht
0c5c05d90b Prevent CLI Plugins from overwriting files (#7140)
* Prevent CLI Plugins from overwriting files

* Revert "Temporarily remove CLI Plugin linking (#7138)"

This reverts commit d6a5aa4f6d.
2021-12-06 17:22:55 +01:00
Leo Lamprecht
fe43c9c4b2 Publish Canary
- @vercel/build-utils@2.12.3-canary.37
 - vercel@23.1.3-canary.60
 - @vercel/client@10.2.3-canary.38
 - vercel-plugin-middleware@0.0.0-canary.13
 - vercel-plugin-go@1.0.0-canary.25
 - vercel-plugin-node@1.12.2-canary.29
 - vercel-plugin-python@1.0.0-canary.26
 - vercel-plugin-ruby@1.0.0-canary.25
2021-12-06 14:28:12 +01:00
Leo Lamprecht
d6a5aa4f6d Temporarily remove CLI Plugin linking (#7138) 2021-12-06 14:25:22 +01:00
Leo Lamprecht
1c3701628d Publish Canary
- @vercel/build-utils@2.12.3-canary.36
 - vercel@23.1.3-canary.59
 - @vercel/client@10.2.3-canary.37
 - vercel-plugin-middleware@0.0.0-canary.12
 - vercel-plugin-go@1.0.0-canary.24
 - vercel-plugin-node@1.12.2-canary.28
 - vercel-plugin-python@1.0.0-canary.25
 - vercel-plugin-ruby@1.0.0-canary.24
2021-12-04 17:01:20 +01:00
Leo Lamprecht
45689f22ab Correctly position dependencies for CLI Plugins (#7133)
Previously, CLI Plugins would try to mount the user-provided request handler (e.g. `api/test.rb`) at the same position inside the Lambda at which the launcher was located (e.g. `api/test.rb`), which would cause the launcher to be overwritten.

With this change, all the destination mounting points for NFT input files are becoming relative to the `.output/server/pages/api` directory instead of `.output/server/pages`, so they should no longer overwrite the launcher, and instead be loaded from the launcher, like normal.

This PR might have two problems:

- If imports in Ruby/Python/etc are relative to `cwd` and not the file from which the import is executed (which I doubt), this would fail.
- We might have to replace `api` with the exact sub folder of the API Route within `.output/server/pages/api` if the current change doesn't yet work for nested paths. Although that also means repeating all of the other dependencies (not just the user-provided request handler) in a different location for every single API Route.

The two above will be tested after this PR was merged, as there currently isn't a way to test `vercel-plugin-go`, `vercel-plugin-python`, and `vercel-plugin-ruby` without publishing a canary, because they don't bundle `@vercel/build-utils`, which was the package that was just updated.

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [x] This PR has a concise title and thorough description useful to a reviewer
- [x] Issue from task tracker has a link to this PR
2021-12-04 16:00:15 +00:00
Leo Lamprecht
2c3ddffaac Publish Canary
- @vercel/build-utils@2.12.3-canary.35
 - vercel@23.1.3-canary.58
 - @vercel/client@10.2.3-canary.36
 - vercel-plugin-middleware@0.0.0-canary.11
 - vercel-plugin-go@1.0.0-canary.23
 - vercel-plugin-node@1.12.2-canary.27
 - vercel-plugin-python@1.0.0-canary.24
 - vercel-plugin-ruby@1.0.0-canary.23
 - @vercel/ruby@1.2.10-canary.0
2021-12-04 01:30:37 +01:00
Leo Lamprecht
c3ea0195c2 Fixed Lambda handler for compiled languages (#7129)
* Use correct Lambda handler for compiled languages

* Use the correct entrypoint

* Fixed the logic

* Perfected it

* Simpler code

* Update packages/build-utils/src/convert-runtime-to-plugin.ts

Co-authored-by: Andy <AndyBitz@users.noreply.github.com>

* Handle edge cases and simplify logic

* Fixed the logic yet again to work perfectly

* Normalize Page path

* Simplified everything

* Fixed the tests

Co-authored-by: Andy <AndyBitz@users.noreply.github.com>
2021-12-04 01:29:46 +01:00
Gary Borton
5f5e50cff0 [middleware] Make edge functions be in "strict mode" (#7118)
Co-authored-by: Leo Lamprecht <leo@vercel.com>
Co-authored-by: Steven <steven@ceriously.com>
Co-authored-by: Nathan Rajlich <n@n8.io>
2021-12-03 15:22:21 -08:00
22 changed files with 182 additions and 186 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "2.12.3-canary.34",
"version": "2.12.3-canary.38",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
@@ -30,7 +30,7 @@
"@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0",
"@types/yazl": "^2.4.1",
"@vercel/frameworks": "0.5.1-canary.16",
"@vercel/frameworks": "0.5.1-canary.17",
"@vercel/ncc": "0.24.0",
"aggregate-error": "3.0.1",
"async-retry": "1.2.3",

View File

@@ -1,5 +1,5 @@
import fs from 'fs-extra';
import { join, dirname, parse, relative } from 'path';
import { join, parse, relative, dirname, basename, extname } from 'path';
import glob from './fs/glob';
import { normalizePath } from './fs/normalize-path';
import { FILES_SYMBOL, Lambda } from './lambda';
@@ -104,6 +104,9 @@ export function convertRuntimeToPlugin(
let newPathsRuntime: Set<string> = new Set();
let linkersRuntime: Array<Promise<void>> = [];
const entryDir = join('.output', 'server', 'pages');
const entryRoot = join(workPath, entryDir);
for (const entrypoint of Object.keys(entrypoints)) {
const { output } = await buildRuntime({
files: sourceFilesPreBuild,
@@ -114,6 +117,7 @@ export function convertRuntimeToPlugin(
},
meta: {
avoidTopLevelInstall: true,
skipDownload: true,
},
});
@@ -128,15 +132,6 @@ export function convertRuntimeToPlugin(
ignoreFilter
);
// Further down, we will need the filename of the Lambda handler
// for placing it inside `server/pages/api`, but because Legacy Runtimes
// don't expose the filename directly, we have to construct it
// from the handler name, and then find the matching file further below,
// because we don't yet know its extension here.
const handler = output.handler;
const handlerMethod = handler.split('.').reverse()[0];
const handlerFileName = handler.replace(`.${handlerMethod}`, '');
// @ts-ignore This symbol is a private API
const lambdaFiles: Files = output[FILES_SYMBOL];
@@ -150,26 +145,41 @@ export function convertRuntimeToPlugin(
}
}
const handlerFilePath = Object.keys(lambdaFiles).find(item => {
return parse(item).name === handlerFileName;
});
let handlerFileBase = output.handler;
let handlerFile = lambdaFiles[handlerFileBase];
const handlerFileOrigin = lambdaFiles[handlerFilePath || ''].fsPath;
const { handler } = output;
const handlerMethod = handler.split('.').pop();
const handlerFileName = handler.replace(`.${handlerMethod}`, '');
if (!handlerFileOrigin) {
// For compiled languages, the launcher file for the Lambda generated
// by the Legacy Runtime matches the `handler` defined for it, but for
// interpreted languages, the `handler` consists of the launcher file name
// without an extension, plus the name of the method inside of that file
// that should be invoked, so we have to construct the file path explicitly.
if (!handlerFile) {
handlerFileBase = handlerFileName + ext;
handlerFile = lambdaFiles[handlerFileBase];
}
if (!handlerFile || !handlerFile.fsPath) {
throw new Error(
`Could not find a handler file. Please ensure that the list of \`files\` defined for the returned \`Lambda\` contains a file with the name ${handlerFileName} (+ any extension).`
`Could not find a handler file. Please ensure that \`files\` for the returned \`Lambda\` contains an \`FileFsRef\` named "${handlerFileBase}" with a valid \`fsPath\`.`
);
}
const entry = join(workPath, '.output', 'server', 'pages', entrypoint);
const handlerExtName = extname(handlerFile.fsPath);
const entryBase = basename(entrypoint).replace(ext, handlerExtName);
const entryPath = join(dirname(entrypoint), entryBase);
const entry = join(entryRoot, entryPath);
// We never want to link here, only copy, because the launcher
// file often has the same name for every entrypoint, which means that
// every build for every entrypoint overwrites the launcher of the previous
// one, so linking would end with a broken reference.
await fs.ensureDir(dirname(entry));
await fs.copy(handlerFileOrigin, entry);
await fs.copy(handlerFile.fsPath, entry);
const newFilesEntrypoint: Array<string> = [];
const newDirectoriesEntrypoint: Array<string> = [];
@@ -233,7 +243,7 @@ export function convertRuntimeToPlugin(
const newPath = join(traceDir, relPath);
// The handler was already moved into position above.
if (relPath === handlerFilePath) {
if (relPath === handlerFileBase) {
return;
}
@@ -277,19 +287,15 @@ export function convertRuntimeToPlugin(
linkersRuntime = linkersRuntime.concat(linkers);
const nft = join(
workPath,
'.output',
'server',
'pages',
`${entrypoint}.nft.json`
);
const nft = `${entry}.nft.json`;
const json = JSON.stringify({
version: 1,
files: tracedFiles.map(file => ({
input: normalizePath(relative(dirname(nft), file.absolutePath)),
output: normalizePath(file.relativePath),
// We'd like to place all the dependency files right next
// to the final launcher file inside of the Lambda.
output: normalizePath(join(entryDir, 'api', file.relativePath)),
})),
});
@@ -305,12 +311,14 @@ export function convertRuntimeToPlugin(
...newDirectoriesEntrypoint,
]);
const apiRouteHandler = `${parse(entry).name}.${handlerMethod}`;
// Add an entry that will later on be added to the `functions-manifest.json`
// file that is placed inside of the `.output` directory.
pages[entrypoint] = {
handler: apiRouteHandler,
pages[normalizePath(entryPath)] = {
// Because the underlying file used as a handler was placed
// inside `.output/server/pages/api`, it no longer has the name it originally
// had and is now named after the API Route that it's responsible for,
// so we have to adjust the name of the Lambda handler accordingly.
handler: handler.replace(handlerFileName, parse(entry).name),
runtime: output.runtime,
memory: output.memory,
maxDuration: output.maxDuration,

View File

@@ -114,35 +114,35 @@ describe('convert-runtime-to-plugin', () => {
files: [
{
input: `../../../inputs/api-routes-python/api/db/[id].py`,
output: 'api/db/[id].py',
output: '.output/server/pages/api/api/db/[id].py',
},
{
input: `../../../inputs/api-routes-python/api/index.py`,
output: 'api/index.py',
output: '.output/server/pages/api/api/index.py',
},
{
input: `../../../inputs/api-routes-python/api/project/[aid]/[bid]/index.py`,
output: 'api/project/[aid]/[bid]/index.py',
output: '.output/server/pages/api/api/project/[aid]/[bid]/index.py',
},
{
input: `../../../inputs/api-routes-python/api/users/get.py`,
output: 'api/users/get.py',
output: '.output/server/pages/api/api/users/get.py',
},
{
input: `../../../inputs/api-routes-python/api/users/post.py`,
output: 'api/users/post.py',
output: '.output/server/pages/api/api/users/post.py',
},
{
input: `../../../inputs/api-routes-python/file.txt`,
output: 'file.txt',
output: '.output/server/pages/api/file.txt',
},
{
input: `../../../inputs/api-routes-python/util/date.py`,
output: 'util/date.py',
output: '.output/server/pages/api/util/date.py',
},
{
input: `../../../inputs/api-routes-python/util/math.py`,
output: 'util/math.py',
output: '.output/server/pages/api/util/math.py',
},
],
});
@@ -155,35 +155,35 @@ describe('convert-runtime-to-plugin', () => {
files: [
{
input: `../../../../inputs/api-routes-python/api/db/[id].py`,
output: 'api/db/[id].py',
output: '.output/server/pages/api/api/db/[id].py',
},
{
input: `../../../../inputs/api-routes-python/api/index.py`,
output: 'api/index.py',
output: '.output/server/pages/api/api/index.py',
},
{
input: `../../../../inputs/api-routes-python/api/project/[aid]/[bid]/index.py`,
output: 'api/project/[aid]/[bid]/index.py',
output: '.output/server/pages/api/api/project/[aid]/[bid]/index.py',
},
{
input: `../../../../inputs/api-routes-python/api/users/get.py`,
output: 'api/users/get.py',
output: '.output/server/pages/api/api/users/get.py',
},
{
input: `../../../../inputs/api-routes-python/api/users/post.py`,
output: 'api/users/post.py',
output: '.output/server/pages/api/api/users/post.py',
},
{
input: `../../../../inputs/api-routes-python/file.txt`,
output: 'file.txt',
output: '.output/server/pages/api/file.txt',
},
{
input: `../../../../inputs/api-routes-python/util/date.py`,
output: 'util/date.py',
output: '.output/server/pages/api/util/date.py',
},
{
input: `../../../../inputs/api-routes-python/util/math.py`,
output: 'util/math.py',
output: '.output/server/pages/api/util/math.py',
},
],
});
@@ -196,35 +196,35 @@ describe('convert-runtime-to-plugin', () => {
files: [
{
input: `../../../../inputs/api-routes-python/api/db/[id].py`,
output: 'api/db/[id].py',
output: '.output/server/pages/api/api/db/[id].py',
},
{
input: `../../../../inputs/api-routes-python/api/index.py`,
output: 'api/index.py',
output: '.output/server/pages/api/api/index.py',
},
{
input: `../../../../inputs/api-routes-python/api/project/[aid]/[bid]/index.py`,
output: 'api/project/[aid]/[bid]/index.py',
output: '.output/server/pages/api/api/project/[aid]/[bid]/index.py',
},
{
input: `../../../../inputs/api-routes-python/api/users/get.py`,
output: 'api/users/get.py',
output: '.output/server/pages/api/api/users/get.py',
},
{
input: `../../../../inputs/api-routes-python/api/users/post.py`,
output: 'api/users/post.py',
output: '.output/server/pages/api/api/users/post.py',
},
{
input: `../../../../inputs/api-routes-python/file.txt`,
output: 'file.txt',
output: '.output/server/pages/api/file.txt',
},
{
input: `../../../../inputs/api-routes-python/util/date.py`,
output: 'util/date.py',
output: '.output/server/pages/api/util/date.py',
},
{
input: `../../../../inputs/api-routes-python/util/math.py`,
output: 'util/math.py',
output: '.output/server/pages/api/util/math.py',
},
],
});

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "23.1.3-canary.57",
"version": "23.1.3-canary.61",
"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.34",
"@vercel/build-utils": "2.12.3-canary.38",
"@vercel/go": "1.2.4-canary.4",
"@vercel/node": "1.12.2-canary.7",
"@vercel/python": "2.1.2-canary.1",
"@vercel/ruby": "1.2.9",
"@vercel/ruby": "1.2.10-canary.0",
"update-notifier": "4.1.0",
"vercel-plugin-middleware": "0.0.0-canary.10",
"vercel-plugin-node": "1.12.2-canary.26"
"vercel-plugin-middleware": "0.0.0-canary.14",
"vercel-plugin-node": "1.12.2-canary.30"
},
"devDependencies": {
"@next/env": "11.1.2",
@@ -90,7 +90,7 @@
"@types/update-notifier": "5.1.0",
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@vercel/frameworks": "0.5.1-canary.16",
"@vercel/frameworks": "0.5.1-canary.17",
"@vercel/ncc": "0.24.0",
"@vercel/nft": "0.17.0",
"@zeit/fun": "0.11.2",

View File

@@ -354,18 +354,19 @@ export default async function main(client: Client) {
}
// We cannot rely on the `framework` alone, as it might be a static export,
// and the current build might use a differnt project that's not in the settings.
// and the current build might use a different project that's not in the settings.
const isNextOutput = Boolean(dotNextDir);
const nextExport = await getNextExportStatus(dotNextDir);
const outputDir =
isNextOutput && !nextExport ? OUTPUT_DIR : join(OUTPUT_DIR, 'static');
const getDistDir = framework.getFsOutputDir || framework.getOutputDirName;
const distDir =
(nextExport?.exportDetail.outDirectory
? relative(cwd, nextExport.exportDetail.outDirectory)
: false) ||
dotNextDir ||
userOutputDirectory ||
(await framework.getFsOutputDir(cwd));
(await getDistDir(cwd));
await fs.ensureDir(join(cwd, outputDir));

View File

@@ -0,0 +1,6 @@
export default function (req) {
const isStrict = (function () {
return !this;
})();
return new Response('is strict mode? ' + (isStrict ? 'yes' : 'no'));
}

View File

@@ -385,4 +385,13 @@ describe('DevServer', () => {
);
})
);
it(
'should run middleware in strict mode',
testFixture('edge-middleware-strict', async server => {
const response = await fetch(`${server.address}/index.html`);
const body = await response.text();
expect(body).toStrictEqual('is strict mode? yes');
})
);
});

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "10.2.3-canary.35",
"version": "10.2.3-canary.39",
"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.34",
"@vercel/build-utils": "2.12.3-canary.38",
"@zeit/fetch": "5.2.0",
"async-retry": "1.2.3",
"async-sema": "3.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/frameworks",
"version": "0.5.1-canary.16",
"version": "0.5.1-canary.17",
"main": "./dist/frameworks.js",
"types": "./dist/frameworks.d.ts",
"files": [

View File

@@ -141,7 +141,6 @@ export const frameworks = [
},
dependency: 'gatsby',
getOutputDirName: async () => 'public',
getFsOutputDir: async () => 'public',
defaultRoutes: async (dirPrefix: string) => {
// This file could be generated by gatsby-plugin-now or gatsby-plugin-zeit-now
try {
@@ -226,7 +225,6 @@ export const frameworks = [
},
},
dependency: 'remix',
getFsOutputDir: async () => 'public',
getOutputDirName: async () => 'public',
defaultRoutes: [
{
@@ -254,10 +252,13 @@ export const frameworks = [
source: '/build/(.*)',
regex: '/build/(.*)',
headers: [
{ key: 'cache-control', value: 'public, max-age=31536000, immutable' },
{
key: 'cache-control',
value: 'public, max-age=31536000, immutable',
},
],
},
]
],
},
{
name: 'Hexo',
@@ -294,7 +295,6 @@ export const frameworks = [
},
},
dependency: 'hexo',
getFsOutputDir: async () => 'public',
getOutputDirName: async () => 'public',
},
{
@@ -332,7 +332,6 @@ export const frameworks = [
},
},
dependency: '@11ty/eleventy',
getFsOutputDir: async () => '_site',
getOutputDirName: async () => '_site',
cachePattern: '.cache/**',
},
@@ -372,22 +371,6 @@ export const frameworks = [
},
},
dependency: '@docusaurus/core',
getFsOutputDir: async (dirPrefix: string) => {
const base = 'build';
try {
const location = join(dirPrefix, base);
const content = await readdir(location, { withFileTypes: true });
// If there is only one file in it that is a dir we'll use it as dist dir
if (content.length === 1 && content[0].isDirectory()) {
return join(base, content[0].name);
}
} catch (error) {
console.error(`Error detecting output directory: `, error);
}
return base;
},
getOutputDirName: async (dirPrefix: string) => {
const base = 'build';
try {
@@ -527,21 +510,6 @@ export const frameworks = [
},
},
dependency: 'docusaurus',
getFsOutputDir: async (dirPrefix: string) => {
const base = 'build';
try {
const location = join(dirPrefix, base);
const content = await readdir(location, { withFileTypes: true });
// If there is only one file in it that is a dir we'll use it as dist dir
if (content.length === 1 && content[0].isDirectory()) {
return join(base, content[0].name);
}
} catch (error) {
console.error(`Error detecting output directory: `, error);
}
return base;
},
getOutputDirName: async (dirPrefix: string) => {
const base = 'build';
try {
@@ -593,7 +561,6 @@ export const frameworks = [
},
},
dependency: 'preact-cli',
getFsOutputDir: async () => 'build',
getOutputDirName: async () => 'build',
defaultRoutes: [
{
@@ -650,7 +617,6 @@ export const frameworks = [
},
},
dependency: '@dojo/cli',
getFsOutputDir: async () => 'output/dist',
getOutputDirName: async () => join('output', 'dist'),
defaultRoutes: [
{
@@ -717,7 +683,6 @@ export const frameworks = [
},
},
dependency: 'ember-cli',
getFsOutputDir: async () => 'dist',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{
@@ -772,7 +737,6 @@ export const frameworks = [
},
},
dependency: '@vue/cli-service',
getFsOutputDir: async () => 'dist',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{
@@ -849,7 +813,6 @@ export const frameworks = [
},
},
dependency: '@scullyio/init',
getFsOutputDir: async () => 'dist',
getOutputDirName: async () => 'dist/static',
},
{
@@ -886,7 +849,6 @@ export const frameworks = [
},
},
dependency: '@ionic/angular',
getFsOutputDir: async () => 'www',
getOutputDirName: async () => 'www',
defaultRoutes: [
{
@@ -940,7 +902,6 @@ export const frameworks = [
},
},
dependency: '@angular/cli',
getFsOutputDir: async () => 'dist',
getOutputDirName: async (dirPrefix: string) => {
const base = 'dist';
try {
@@ -1008,7 +969,6 @@ export const frameworks = [
},
},
dependency: 'polymer-cli',
getFsOutputDir: async () => 'build',
getOutputDirName: async (dirPrefix: string) => {
const base = 'build';
try {
@@ -1078,7 +1038,6 @@ export const frameworks = [
},
},
dependency: 'sirv-cli',
getFsOutputDir: async () => 'public',
getOutputDirName: async () => 'public',
defaultRoutes: [
{
@@ -1128,10 +1087,9 @@ export const frameworks = [
placeholder: 'svelte-kit dev',
},
outputDirectory: {
placeholder: 'public',
value: 'public',
},
},
getFsOutputDir: async () => '.output',
getOutputDirName: async () => 'public',
},
{
@@ -1168,7 +1126,6 @@ export const frameworks = [
},
},
dependency: '@ionic/react',
getFsOutputDir: async () => 'build',
getOutputDirName: async () => 'build',
defaultRoutes: [
{
@@ -1276,7 +1233,6 @@ export const frameworks = [
},
},
dependency: 'react-scripts',
getFsOutputDir: async () => 'build',
getOutputDirName: async () => 'build',
defaultRoutes: [
{
@@ -1378,7 +1334,6 @@ export const frameworks = [
},
},
dependency: 'gridsome',
getFsOutputDir: async () => 'dist',
getOutputDirName: async () => 'dist',
},
{
@@ -1416,7 +1371,6 @@ export const frameworks = [
},
},
dependency: 'umi',
getFsOutputDir: async () => 'dist',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{
@@ -1470,7 +1424,6 @@ export const frameworks = [
},
},
dependency: 'sapper',
getFsOutputDir: async () => '__sapper__/export',
getOutputDirName: async () => '__sapper__/export',
},
{
@@ -1508,7 +1461,6 @@ export const frameworks = [
},
},
dependency: 'saber',
getFsOutputDir: async () => 'public',
getOutputDirName: async () => 'public',
defaultRoutes: [
{
@@ -1577,7 +1529,6 @@ export const frameworks = [
},
},
dependency: '@stencil/core',
getFsOutputDir: async () => 'www',
getOutputDirName: async () => 'www',
defaultRoutes: [
{
@@ -1666,7 +1617,6 @@ export const frameworks = [
},
},
dependency: 'nuxt',
getFsOutputDir: async () => '.output',
getOutputDirName: async () => 'dist',
cachePattern: '.nuxt/**',
defaultRoutes: [
@@ -1724,7 +1674,6 @@ export const frameworks = [
placeholder: 'RedwoodJS default',
},
},
getFsOutputDir: async () => 'public',
getOutputDirName: async () => 'public',
},
{
@@ -1768,16 +1717,6 @@ export const frameworks = [
placeholder: '`public` or `publishDir` from the `config` file',
},
},
getFsOutputDir: async (dirPrefix: string): Promise<string> => {
type HugoConfig = { publishDir?: string };
const config = await readConfigFile<HugoConfig>(
['config.json', 'config.yaml', 'config.toml'].map(fileName => {
return join(dirPrefix, fileName);
})
);
return (config && config.publishDir) || 'public';
},
getOutputDirName: async (dirPrefix: string): Promise<string> => {
type HugoConfig = { publishDir?: string };
const config = await readConfigFile<HugoConfig>(
@@ -1822,13 +1761,6 @@ export const frameworks = [
placeholder: '`_site` or `destination` from `_config.yml`',
},
},
getFsOutputDir: async (dirPrefix: string): Promise<string> => {
type JekyllConfig = { destination?: string };
const config = await readConfigFile<JekyllConfig>(
join(dirPrefix, '_config.yml')
);
return (config && config.destination) || '_site';
},
getOutputDirName: async (dirPrefix: string): Promise<string> => {
type JekyllConfig = { destination?: string };
const config = await readConfigFile<JekyllConfig>(
@@ -1870,7 +1802,6 @@ export const frameworks = [
value: 'public',
},
},
getFsOutputDir: async () => 'public',
getOutputDirName: async () => 'public',
},
{
@@ -1905,7 +1836,6 @@ export const frameworks = [
value: 'build',
},
},
getFsOutputDir: async () => 'build',
getOutputDirName: async () => 'build',
cachePattern: '{vendor/bin,vendor/cache,vendor/bundle}/**',
},
@@ -1940,7 +1870,6 @@ export const frameworks = [
value: 'public',
},
},
getFsOutputDir: async () => 'public',
getOutputDirName: async () => 'public',
defaultVersion: '0.13.0',
},
@@ -1980,7 +1909,6 @@ export const frameworks = [
},
},
dependency: 'vite',
getFsOutputDir: async () => 'dist',
getOutputDirName: async () => 'dist',
},
{
@@ -2018,7 +1946,6 @@ export const frameworks = [
},
},
dependency: 'parcel',
getFsOutputDir: async () => 'dist',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{

View File

@@ -162,9 +162,9 @@ export interface Framework {
dependency?: string;
/**
* Function that returns the name of the directory that the framework outputs
* its build results to. In some cases this is read from a configuration file.
* its File System API build results to, usually called `.output`.
*/
getFsOutputDir: (dirPrefix: string) => Promise<string>;
getFsOutputDir?: (dirPrefix: string) => Promise<string>;
/**
* Function that returns the name of the directory that the framework outputs
* its STATIC build results to. In some cases this is read from a configuration file.

View File

@@ -1,6 +1,6 @@
{
"name": "vercel-plugin-middleware",
"version": "0.0.0-canary.10",
"version": "0.0.0-canary.14",
"license": "MIT",
"main": "./dist/index",
"homepage": "",
@@ -30,7 +30,7 @@
"@types/node-fetch": "^2",
"@types/ua-parser-js": "0.7.36",
"@types/uuid": "8.3.1",
"@vercel/build-utils": "2.12.3-canary.34",
"@vercel/build-utils": "2.12.3-canary.38",
"@vercel/ncc": "0.24.0",
"cookie": "0.4.1",
"formdata-node": "4.3.1",

View File

@@ -1,4 +1,4 @@
import * as middleware from './_middleware';
import * as middleware from './_temp_middleware';
_ENTRIES = typeof _ENTRIES === 'undefined' ? {} : _ENTRIES;
_ENTRIES['middleware_pages/_middleware'] = {
default: async function (ev) {

View File

@@ -23,7 +23,8 @@ const SUPPORTED_EXTENSIONS = ['.js', '.ts'];
// File name of the `entries.js` file that gets copied into the
// project directory. Use a name that is unlikely to conflict.
const ENTRIES_NAME = '___vc_entries.js';
const TMP_ENTRIES_NAME = '.output/inputs/middleware/___vc_entries.js';
const TMP_MIDDLEWARE_BUNDLE = '.output/inputs/middleware/_temp_middleware.js';
async function getMiddlewareFile(workingDirectory: string) {
// Only the root-level `_middleware.*` files are considered.
@@ -53,17 +54,36 @@ async function getMiddlewareFile(workingDirectory: string) {
}
export async function build({ workPath }: { workPath: string }) {
const entriesPath = join(workPath, ENTRIES_NAME);
const entriesPath = join(workPath, TMP_ENTRIES_NAME);
const transientFilePath = join(workPath, TMP_MIDDLEWARE_BUNDLE);
const middlewareFile = await getMiddlewareFile(workPath);
if (!middlewareFile) return;
console.log('Compiling middleware file: %j', middlewareFile);
// Create `_ENTRIES` wrapper
await fsp.copyFile(join(__dirname, 'entries.js'), entriesPath);
// Build
/**
* Two builds happen here, because esbuild doesn't offer a way to add a banner
* to individual input files, and the entries wrapper relies on running in
* non-strict mode to access the ENTRIES global.
*
* To work around this, we bundle the middleware directly and add
* 'use strict'; to make the entire bundle run in strict mode. We then bundle
* a second time, adding the global ENTRIES wrapper and preserving the
* 'use strict' for the entire scope of the original bundle.
*/
try {
await esbuild.build({
entryPoints: [middlewareFile],
bundle: true,
absWorkingDir: workPath,
outfile: transientFilePath,
banner: {
js: '"use strict";',
},
format: 'cjs',
});
// Create `_ENTRIES` wrapper
await fsp.copyFile(join(__dirname, 'entries.js'), entriesPath);
await esbuild.build({
entryPoints: [entriesPath],
bundle: true,
@@ -71,6 +91,7 @@ export async function build({ workPath }: { workPath: string }) {
outfile: join(workPath, '.output/server/pages/_middleware.js'),
});
} finally {
await fsp.unlink(transientFilePath);
await fsp.unlink(entriesPath);
}

View File

@@ -114,6 +114,7 @@ export async function run(params: {
const content = readFileSync(params.path, 'utf-8');
const esBuildResult = esbuild.transformSync(content, {
format: 'cjs',
banner: '"use strict";',
});
const x = vm.runInNewContext(m.wrap(esBuildResult.code), cache.sandbox, {
filename: params.path,
@@ -163,6 +164,7 @@ function sandboxRequire(referrer: string, specifier: string) {
const transformOptions: esbuild.TransformOptions = {
format: 'cjs',
banner: '"use strict";',
};
if (extname(resolved) === '.json') {
transformOptions.loader = 'json';

View File

@@ -3,6 +3,30 @@ import { promises as fsp } from 'fs';
import { build } from '../src';
import { Response } from 'node-fetch';
const setupFixture = async (fixture: string) => {
const fixturePath = join(__dirname, `fixtures/${fixture}`);
await build({
workPath: fixturePath,
});
const functionsManifest = JSON.parse(
await fsp.readFile(
join(fixturePath, '.output/functions-manifest.json'),
'utf8'
)
);
const outputFile = join(fixturePath, '.output/server/pages/_middleware.js');
expect(await fsp.stat(outputFile)).toBeTruthy();
require(outputFile);
//@ts-ignore
const middleware = global._ENTRIES['middleware_pages/_middleware'].default;
return {
middleware,
functionsManifest,
};
};
describe('build()', () => {
beforeEach(() => {
//@ts-ignore
@@ -15,25 +39,9 @@ describe('build()', () => {
delete global._ENTRIES;
});
it('should build simple middleware', async () => {
const fixture = join(__dirname, 'fixtures/simple');
await build({
workPath: fixture,
});
const { functionsManifest, middleware } = await setupFixture('simple');
const middlewareManifest = JSON.parse(
await fsp.readFile(
join(fixture, '.output/functions-manifest.json'),
'utf8'
)
);
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(functionsManifest).toMatchSnapshot();
expect(typeof middleware).toStrictEqual('function');
const handledResponse = await middleware({
request: {
@@ -54,4 +62,12 @@ describe('build()', () => {
(unhandledResponse.response as Response).headers.get('x-middleware-next')
).toEqual('1');
});
it('should create a middleware that runs in strict mode', async () => {
const { middleware } = await setupFixture('use-strict');
const response = await middleware({
request: {},
});
expect(String(response.response.body)).toEqual('is strict mode? yes');
});
});

View File

@@ -0,0 +1,6 @@
export default function (req) {
const isStrict = (function () {
return !this;
})();
return new Response('is strict mode? ' + (isStrict ? 'yes' : 'no'));
}

View File

@@ -1,7 +1,7 @@
{
"private": false,
"name": "vercel-plugin-go",
"version": "1.0.0-canary.22",
"version": "1.0.0-canary.26",
"main": "dist/index.js",
"license": "MIT",
"files": [
@@ -17,7 +17,7 @@
"prepublishOnly": "tsc"
},
"dependencies": {
"@vercel/build-utils": "2.12.3-canary.34",
"@vercel/build-utils": "2.12.3-canary.38",
"@vercel/go": "1.2.4-canary.4"
},
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "vercel-plugin-node",
"version": "1.12.2-canary.26",
"version": "1.12.2-canary.30",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -34,7 +34,7 @@
"@types/node-fetch": "2",
"@types/test-listen": "1.1.0",
"@types/yazl": "2.4.2",
"@vercel/build-utils": "2.12.3-canary.34",
"@vercel/build-utils": "2.12.3-canary.38",
"@vercel/fun": "1.0.3",
"@vercel/ncc": "0.24.0",
"@vercel/nft": "0.14.0",

View File

@@ -1,7 +1,7 @@
{
"private": false,
"name": "vercel-plugin-python",
"version": "1.0.0-canary.23",
"version": "1.0.0-canary.27",
"main": "dist/index.js",
"license": "MIT",
"files": [
@@ -17,7 +17,7 @@
"prepublishOnly": "tsc"
},
"dependencies": {
"@vercel/build-utils": "2.12.3-canary.34",
"@vercel/build-utils": "2.12.3-canary.38",
"@vercel/python": "2.1.2-canary.1"
},
"devDependencies": {

View File

@@ -1,7 +1,7 @@
{
"private": false,
"name": "vercel-plugin-ruby",
"version": "1.0.0-canary.22",
"version": "1.0.0-canary.26",
"main": "dist/index.js",
"license": "MIT",
"files": [
@@ -17,8 +17,8 @@
"prepublishOnly": "tsc"
},
"dependencies": {
"@vercel/build-utils": "2.12.3-canary.34",
"@vercel/ruby": "1.2.9"
"@vercel/build-utils": "2.12.3-canary.38",
"@vercel/ruby": "1.2.10-canary.0"
},
"devDependencies": {
"@types/node": "*",

View File

@@ -1,7 +1,7 @@
{
"name": "@vercel/ruby",
"author": "Nathan Cahill <nathan@nathancahill.com>",
"version": "1.2.9",
"version": "1.2.10-canary.0",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",