@vercel/build-utils 2.13.1-canary.0 → 2.14.1-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -7
- package/dist/debug.js +2 -2
- package/dist/fs/run-user-scripts.d.ts +16 -0
- package/dist/fs/run-user-scripts.js +55 -22
- package/dist/get-platform-env.d.ts +5 -0
- package/dist/get-platform-env.js +26 -0
- package/dist/index.d.ts +4 -8
- package/dist/index.js +210 -402
- package/dist/lambda.d.ts +16 -15
- package/dist/lambda.js +46 -43
- package/dist/nodejs-lambda.d.ts +14 -0
- package/dist/nodejs-lambda.js +14 -0
- package/dist/types.d.ts +38 -0
- package/package.json +3 -3
- package/dist/convert-runtime-to-plugin.d.ts +0 -65
- package/dist/convert-runtime-to-plugin.js +0 -298
package/dist/lambda.d.ts
CHANGED
@@ -3,17 +3,7 @@ import { Files, Config } from './types';
|
|
3
3
|
interface Environment {
|
4
4
|
[key: string]: string;
|
5
5
|
}
|
6
|
-
interface LambdaOptions {
|
7
|
-
zipBuffer: Buffer;
|
8
|
-
handler: string;
|
9
|
-
runtime: string;
|
10
|
-
memory?: number;
|
11
|
-
maxDuration?: number;
|
12
|
-
environment: Environment;
|
13
|
-
allowQuery?: string[];
|
14
|
-
regions?: string[];
|
15
|
-
}
|
16
|
-
interface CreateLambdaOptions {
|
6
|
+
export interface LambdaOptions {
|
17
7
|
files: Files;
|
18
8
|
handler: string;
|
19
9
|
runtime: string;
|
@@ -22,15 +12,18 @@ interface CreateLambdaOptions {
|
|
22
12
|
environment?: Environment;
|
23
13
|
allowQuery?: string[];
|
24
14
|
regions?: string[];
|
15
|
+
/**
|
16
|
+
* @deprecated Use `files` property instead.
|
17
|
+
*/
|
18
|
+
zipBuffer?: Buffer;
|
25
19
|
}
|
26
20
|
interface GetLambdaOptionsFromFunctionOptions {
|
27
21
|
sourceFile: string;
|
28
22
|
config?: Pick<Config, 'functions'>;
|
29
23
|
}
|
30
|
-
export declare const FILES_SYMBOL: unique symbol;
|
31
24
|
export declare class Lambda {
|
32
25
|
type: 'Lambda';
|
33
|
-
|
26
|
+
files: Files;
|
34
27
|
handler: string;
|
35
28
|
runtime: string;
|
36
29
|
memory?: number;
|
@@ -38,9 +31,17 @@ export declare class Lambda {
|
|
38
31
|
environment: Environment;
|
39
32
|
allowQuery?: string[];
|
40
33
|
regions?: string[];
|
41
|
-
|
34
|
+
/**
|
35
|
+
* @deprecated Use `await lambda.createZip()` instead.
|
36
|
+
*/
|
37
|
+
zipBuffer?: Buffer;
|
38
|
+
constructor({ files, handler, runtime, maxDuration, memory, environment, allowQuery, regions, zipBuffer, }: LambdaOptions);
|
39
|
+
createZip(): Promise<Buffer>;
|
42
40
|
}
|
43
|
-
|
41
|
+
/**
|
42
|
+
* @deprecated Use `new Lambda()` instead.
|
43
|
+
*/
|
44
|
+
export declare function createLambda(opts: LambdaOptions): Promise<Lambda>;
|
44
45
|
export declare function createZip(files: Files): Promise<Buffer>;
|
45
46
|
export declare function getLambdaOptionsFromFunction({ sourceFile, config, }: GetLambdaOptionsFromFunctionOptions): Promise<Pick<LambdaOptions, 'memory' | 'maxDuration'>>;
|
46
47
|
export {};
|
package/dist/lambda.js
CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.getLambdaOptionsFromFunction = exports.createZip = exports.createLambda = exports.Lambda =
|
6
|
+
exports.getLambdaOptionsFromFunction = exports.createZip = exports.createLambda = exports.Lambda = void 0;
|
7
7
|
const assert_1 = __importDefault(require("assert"));
|
8
8
|
const async_sema_1 = __importDefault(require("async-sema"));
|
9
9
|
const yazl_1 = require("yazl");
|
@@ -11,11 +11,30 @@ const minimatch_1 = __importDefault(require("minimatch"));
|
|
11
11
|
const fs_extra_1 = require("fs-extra");
|
12
12
|
const download_1 = require("./fs/download");
|
13
13
|
const stream_to_buffer_1 = __importDefault(require("./fs/stream-to-buffer"));
|
14
|
-
exports.FILES_SYMBOL = Symbol('files');
|
15
14
|
class Lambda {
|
16
|
-
constructor({
|
15
|
+
constructor({ files, handler, runtime, maxDuration, memory, environment = {}, allowQuery, regions, zipBuffer, }) {
|
16
|
+
if (!zipBuffer) {
|
17
|
+
assert_1.default(typeof files === 'object', '"files" must be an object');
|
18
|
+
}
|
19
|
+
assert_1.default(typeof handler === 'string', '"handler" is not a string');
|
20
|
+
assert_1.default(typeof runtime === 'string', '"runtime" is not a string');
|
21
|
+
assert_1.default(typeof environment === 'object', '"environment" is not an object');
|
22
|
+
if (memory !== undefined) {
|
23
|
+
assert_1.default(typeof memory === 'number', '"memory" is not a number');
|
24
|
+
}
|
25
|
+
if (maxDuration !== undefined) {
|
26
|
+
assert_1.default(typeof maxDuration === 'number', '"maxDuration" is not a number');
|
27
|
+
}
|
28
|
+
if (allowQuery !== undefined) {
|
29
|
+
assert_1.default(Array.isArray(allowQuery), '"allowQuery" is not an Array');
|
30
|
+
assert_1.default(allowQuery.every(q => typeof q === 'string'), '"allowQuery" is not a string Array');
|
31
|
+
}
|
32
|
+
if (regions !== undefined) {
|
33
|
+
assert_1.default(Array.isArray(regions), '"regions" is not an Array');
|
34
|
+
assert_1.default(regions.every(r => typeof r === 'string'), '"regions" is not a string Array');
|
35
|
+
}
|
17
36
|
this.type = 'Lambda';
|
18
|
-
this.
|
37
|
+
this.files = files;
|
19
38
|
this.handler = handler;
|
20
39
|
this.runtime = runtime;
|
21
40
|
this.memory = memory;
|
@@ -23,49 +42,33 @@ class Lambda {
|
|
23
42
|
this.environment = environment;
|
24
43
|
this.allowQuery = allowQuery;
|
25
44
|
this.regions = regions;
|
45
|
+
this.zipBuffer = zipBuffer;
|
46
|
+
}
|
47
|
+
async createZip() {
|
48
|
+
let { zipBuffer } = this;
|
49
|
+
if (!zipBuffer) {
|
50
|
+
await sema.acquire();
|
51
|
+
try {
|
52
|
+
zipBuffer = await createZip(this.files);
|
53
|
+
}
|
54
|
+
finally {
|
55
|
+
sema.release();
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return zipBuffer;
|
26
59
|
}
|
27
60
|
}
|
28
61
|
exports.Lambda = Lambda;
|
29
62
|
const sema = new async_sema_1.default(10);
|
30
63
|
const mtime = new Date(1540000000000);
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
if (maxDuration !== undefined) {
|
40
|
-
assert_1.default(typeof maxDuration === 'number', '"maxDuration" is not a number');
|
41
|
-
}
|
42
|
-
if (allowQuery !== undefined) {
|
43
|
-
assert_1.default(Array.isArray(allowQuery), '"allowQuery" is not an Array');
|
44
|
-
assert_1.default(allowQuery.every(q => typeof q === 'string'), '"allowQuery" is not a string Array');
|
45
|
-
}
|
46
|
-
if (regions !== undefined) {
|
47
|
-
assert_1.default(Array.isArray(regions), '"regions" is not an Array');
|
48
|
-
assert_1.default(regions.every(r => typeof r === 'string'), '"regions" is not a string Array');
|
49
|
-
}
|
50
|
-
await sema.acquire();
|
51
|
-
try {
|
52
|
-
const zipBuffer = await createZip(files);
|
53
|
-
const lambda = new Lambda({
|
54
|
-
zipBuffer,
|
55
|
-
handler,
|
56
|
-
runtime,
|
57
|
-
memory,
|
58
|
-
maxDuration,
|
59
|
-
environment,
|
60
|
-
regions,
|
61
|
-
});
|
62
|
-
// @ts-ignore This symbol is a private API
|
63
|
-
lambda[exports.FILES_SYMBOL] = files;
|
64
|
-
return lambda;
|
65
|
-
}
|
66
|
-
finally {
|
67
|
-
sema.release();
|
68
|
-
}
|
64
|
+
/**
|
65
|
+
* @deprecated Use `new Lambda()` instead.
|
66
|
+
*/
|
67
|
+
async function createLambda(opts) {
|
68
|
+
const lambda = new Lambda(opts);
|
69
|
+
// backwards compat
|
70
|
+
lambda.zipBuffer = await lambda.createZip();
|
71
|
+
return lambda;
|
69
72
|
}
|
70
73
|
exports.createLambda = createLambda;
|
71
74
|
async function createZip(files) {
|
@@ -100,7 +103,7 @@ async function createZip(files) {
|
|
100
103
|
}
|
101
104
|
exports.createZip = createZip;
|
102
105
|
async function getLambdaOptionsFromFunction({ sourceFile, config, }) {
|
103
|
-
if (config
|
106
|
+
if (config === null || config === void 0 ? void 0 : config.functions) {
|
104
107
|
for (const [pattern, fn] of Object.entries(config.functions)) {
|
105
108
|
if (sourceFile === pattern || minimatch_1.default(sourceFile, pattern)) {
|
106
109
|
return {
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { Lambda, LambdaOptions } from './lambda';
|
2
|
+
interface NodejsLambdaOptions extends LambdaOptions {
|
3
|
+
shouldAddHelpers: boolean;
|
4
|
+
shouldAddSourcemapSupport: boolean;
|
5
|
+
awsLambdaHandler?: string;
|
6
|
+
}
|
7
|
+
export declare class NodejsLambda extends Lambda {
|
8
|
+
launcherType: 'Nodejs';
|
9
|
+
shouldAddHelpers: boolean;
|
10
|
+
shouldAddSourcemapSupport: boolean;
|
11
|
+
awsLambdaHandler?: string;
|
12
|
+
constructor({ shouldAddHelpers, shouldAddSourcemapSupport, awsLambdaHandler, ...opts }: NodejsLambdaOptions);
|
13
|
+
}
|
14
|
+
export {};
|
@@ -0,0 +1,14 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.NodejsLambda = void 0;
|
4
|
+
const lambda_1 = require("./lambda");
|
5
|
+
class NodejsLambda extends lambda_1.Lambda {
|
6
|
+
constructor({ shouldAddHelpers, shouldAddSourcemapSupport, awsLambdaHandler, ...opts }) {
|
7
|
+
super(opts);
|
8
|
+
this.launcherType = 'Nodejs';
|
9
|
+
this.shouldAddHelpers = shouldAddHelpers;
|
10
|
+
this.shouldAddSourcemapSupport = shouldAddSourcemapSupport;
|
11
|
+
this.awsLambdaHandler = awsLambdaHandler;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
exports.NodejsLambda = NodejsLambda;
|
package/dist/types.d.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
/// <reference types="node" />
|
2
2
|
import FileRef from './file-ref';
|
3
3
|
import FileFsRef from './file-fs-ref';
|
4
|
+
import { Lambda } from './lambda';
|
4
5
|
export interface Env {
|
5
6
|
[name: string]: string | undefined;
|
6
7
|
}
|
@@ -319,3 +320,40 @@ export interface ProjectSettings {
|
|
319
320
|
directoryListing?: boolean;
|
320
321
|
gitForkProtection?: boolean;
|
321
322
|
}
|
323
|
+
export interface BuilderV2 {
|
324
|
+
version: 2;
|
325
|
+
build: BuildV2;
|
326
|
+
prepareCache?: PrepareCache;
|
327
|
+
}
|
328
|
+
export interface BuilderV3 {
|
329
|
+
version: 3;
|
330
|
+
build: BuildV3;
|
331
|
+
prepareCache?: PrepareCache;
|
332
|
+
startDevServer?: StartDevServer;
|
333
|
+
}
|
334
|
+
declare type ImageFormat = 'image/avif' | 'image/webp';
|
335
|
+
export interface Images {
|
336
|
+
domains: string[];
|
337
|
+
sizes: number[];
|
338
|
+
minimumCacheTTL?: number;
|
339
|
+
formats?: ImageFormat[];
|
340
|
+
}
|
341
|
+
export interface BuildResultV2 {
|
342
|
+
routes: any[];
|
343
|
+
images?: Images;
|
344
|
+
output: {
|
345
|
+
[key: string]: File | Lambda;
|
346
|
+
};
|
347
|
+
wildcard?: Array<{
|
348
|
+
domain: string;
|
349
|
+
value: string;
|
350
|
+
}>;
|
351
|
+
}
|
352
|
+
export interface BuildResultV3 {
|
353
|
+
output: Lambda;
|
354
|
+
}
|
355
|
+
export declare type BuildV2 = (options: BuildOptions) => Promise<BuildResultV2>;
|
356
|
+
export declare type BuildV3 = (options: BuildOptions) => Promise<BuildResultV3>;
|
357
|
+
export declare type PrepareCache = (options: PrepareCacheOptions) => Promise<Files>;
|
358
|
+
export declare type StartDevServer = (options: StartDevServerOptions) => Promise<StartDevServerResult>;
|
359
|
+
export {};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vercel/build-utils",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.14.1-canary.0",
|
4
4
|
"license": "MIT",
|
5
5
|
"main": "./dist/index.js",
|
6
6
|
"types": "./dist/index.d.js",
|
@@ -30,7 +30,7 @@
|
|
30
30
|
"@types/node-fetch": "^2.1.6",
|
31
31
|
"@types/semver": "6.0.0",
|
32
32
|
"@types/yazl": "^2.4.1",
|
33
|
-
"@vercel/frameworks": "0.
|
33
|
+
"@vercel/frameworks": "0.6.1-canary.0",
|
34
34
|
"@vercel/ncc": "0.24.0",
|
35
35
|
"aggregate-error": "3.0.1",
|
36
36
|
"async-retry": "1.2.3",
|
@@ -49,5 +49,5 @@
|
|
49
49
|
"typescript": "4.3.4",
|
50
50
|
"yazl": "2.4.3"
|
51
51
|
},
|
52
|
-
"gitHead": "
|
52
|
+
"gitHead": "04029013a60ed96c86ed369990cef6dd284d1724"
|
53
53
|
}
|
@@ -1,65 +0,0 @@
|
|
1
|
-
import { Lambda } from './lambda';
|
2
|
-
import type { BuildOptions } from './types';
|
3
|
-
/**
|
4
|
-
* Convert legacy Runtime to a Plugin.
|
5
|
-
* @param buildRuntime - a legacy build() function from a Runtime
|
6
|
-
* @param packageName - the name of the package, for example `vercel-plugin-python`
|
7
|
-
* @param ext - the file extension, for example `.py`
|
8
|
-
*/
|
9
|
-
export declare function _experimental_convertRuntimeToPlugin(buildRuntime: (options: BuildOptions) => Promise<{
|
10
|
-
output: Lambda;
|
11
|
-
}>, packageName: string, ext: string): ({ workPath }: {
|
12
|
-
workPath: string;
|
13
|
-
}) => Promise<void>;
|
14
|
-
/**
|
15
|
-
* If `.output/functions-manifest.json` exists, append to the pages
|
16
|
-
* property. Otherwise write a new file.
|
17
|
-
*/
|
18
|
-
export declare function _experimental_updateFunctionsManifest({ workPath, pages, }: {
|
19
|
-
workPath: string;
|
20
|
-
pages: {
|
21
|
-
[key: string]: any;
|
22
|
-
};
|
23
|
-
}): Promise<void>;
|
24
|
-
/**
|
25
|
-
* Append routes to the `routes-manifest.json` file.
|
26
|
-
* If the file does not exist, it will be created.
|
27
|
-
*/
|
28
|
-
export declare function _experimental_updateRoutesManifest({ workPath, redirects, rewrites, headers, dynamicRoutes, staticRoutes, }: {
|
29
|
-
workPath: string;
|
30
|
-
redirects?: {
|
31
|
-
source: string;
|
32
|
-
destination: string;
|
33
|
-
statusCode: number;
|
34
|
-
regex: string;
|
35
|
-
}[];
|
36
|
-
rewrites?: {
|
37
|
-
source: string;
|
38
|
-
destination: string;
|
39
|
-
regex: string;
|
40
|
-
}[];
|
41
|
-
headers?: {
|
42
|
-
source: string;
|
43
|
-
headers: {
|
44
|
-
key: string;
|
45
|
-
value: string;
|
46
|
-
}[];
|
47
|
-
regex: string;
|
48
|
-
}[];
|
49
|
-
dynamicRoutes?: {
|
50
|
-
page: string;
|
51
|
-
regex: string;
|
52
|
-
namedRegex?: string;
|
53
|
-
routeKeys?: {
|
54
|
-
[named: string]: string;
|
55
|
-
};
|
56
|
-
}[];
|
57
|
-
staticRoutes?: {
|
58
|
-
page: string;
|
59
|
-
regex: string;
|
60
|
-
namedRegex?: string;
|
61
|
-
routeKeys?: {
|
62
|
-
[named: string]: string;
|
63
|
-
};
|
64
|
-
}[];
|
65
|
-
}): Promise<void>;
|
@@ -1,298 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
-
};
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports._experimental_updateRoutesManifest = exports._experimental_updateFunctionsManifest = exports._experimental_convertRuntimeToPlugin = void 0;
|
7
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
8
|
-
const path_1 = require("path");
|
9
|
-
const glob_1 = __importDefault(require("./fs/glob"));
|
10
|
-
const normalize_path_1 = require("./fs/normalize-path");
|
11
|
-
const lambda_1 = require("./lambda");
|
12
|
-
const _1 = require(".");
|
13
|
-
// `.output` was already created by the Build Command, so we have
|
14
|
-
// to ensure its contents don't get bundled into the Lambda. Similarily,
|
15
|
-
// we don't want to bundle anything from `.vercel` either. Lastly,
|
16
|
-
// Builders/Runtimes didn't have `vercel.json` or `now.json`.
|
17
|
-
const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
|
18
|
-
const shouldIgnorePath = (file, ignoreFilter, ignoreFile) => {
|
19
|
-
const isNative = ignoredPaths.some(item => {
|
20
|
-
return file.startsWith(item);
|
21
|
-
});
|
22
|
-
if (!ignoreFile) {
|
23
|
-
return isNative;
|
24
|
-
}
|
25
|
-
return isNative || ignoreFilter(file);
|
26
|
-
};
|
27
|
-
const getSourceFiles = async (workPath, ignoreFilter) => {
|
28
|
-
const list = await glob_1.default('**', {
|
29
|
-
cwd: workPath,
|
30
|
-
});
|
31
|
-
// We're not passing this as an `ignore` filter to the `glob` function above,
|
32
|
-
// so that we can re-use exactly the same `getIgnoreFilter` method that the
|
33
|
-
// Build Step uses (literally the same code). Note that this exclusion only applies
|
34
|
-
// when deploying. Locally, another exclusion is needed, which is handled
|
35
|
-
// further below in the `convertRuntimeToPlugin` function.
|
36
|
-
for (const file in list) {
|
37
|
-
if (shouldIgnorePath(file, ignoreFilter, true)) {
|
38
|
-
delete list[file];
|
39
|
-
}
|
40
|
-
}
|
41
|
-
return list;
|
42
|
-
};
|
43
|
-
/**
|
44
|
-
* Convert legacy Runtime to a Plugin.
|
45
|
-
* @param buildRuntime - a legacy build() function from a Runtime
|
46
|
-
* @param packageName - the name of the package, for example `vercel-plugin-python`
|
47
|
-
* @param ext - the file extension, for example `.py`
|
48
|
-
*/
|
49
|
-
function _experimental_convertRuntimeToPlugin(buildRuntime, packageName, ext) {
|
50
|
-
// This `build()` signature should match `plugin.build()` signature in `vercel build`.
|
51
|
-
return async function build({ workPath }) {
|
52
|
-
// We also don't want to provide any files to Runtimes that were ignored
|
53
|
-
// through `.vercelignore` or `.nowignore`, because the Build Step does the same.
|
54
|
-
const ignoreFilter = await _1.getIgnoreFilter(workPath);
|
55
|
-
// Retrieve the files that are currently available on the File System,
|
56
|
-
// before the Legacy Runtime has even started to build.
|
57
|
-
const sourceFilesPreBuild = await getSourceFiles(workPath, ignoreFilter);
|
58
|
-
// Instead of doing another `glob` to get all the matching source files,
|
59
|
-
// we'll filter the list of existing files down to only the ones
|
60
|
-
// that are matching the entrypoint pattern, so we're first creating
|
61
|
-
// a clean new list to begin.
|
62
|
-
const entrypoints = Object.assign({}, sourceFilesPreBuild);
|
63
|
-
const entrypointMatch = new RegExp(`^api/.*${ext}$`);
|
64
|
-
// Up next, we'll strip out the files from the list of entrypoints
|
65
|
-
// that aren't actually considered entrypoints.
|
66
|
-
for (const file in entrypoints) {
|
67
|
-
if (!entrypointMatch.test(file)) {
|
68
|
-
delete entrypoints[file];
|
69
|
-
}
|
70
|
-
}
|
71
|
-
const pages = {};
|
72
|
-
const pluginName = packageName.replace('vercel-plugin-', '');
|
73
|
-
const outputPath = path_1.join(workPath, '.output');
|
74
|
-
const traceDir = path_1.join(outputPath, `inputs`,
|
75
|
-
// Legacy Runtimes can only provide API Routes, so that's
|
76
|
-
// why we can use this prefix for all of them. Here, we have to
|
77
|
-
// make sure to not use a cryptic hash name, because people
|
78
|
-
// need to be able to easily inspect the output.
|
79
|
-
`api-routes-${pluginName}`);
|
80
|
-
await fs_extra_1.default.ensureDir(traceDir);
|
81
|
-
const entryRoot = path_1.join(outputPath, 'server', 'pages');
|
82
|
-
for (const entrypoint of Object.keys(entrypoints)) {
|
83
|
-
const { output } = await buildRuntime({
|
84
|
-
files: sourceFilesPreBuild,
|
85
|
-
entrypoint,
|
86
|
-
workPath,
|
87
|
-
config: {
|
88
|
-
zeroConfig: true,
|
89
|
-
},
|
90
|
-
meta: {
|
91
|
-
avoidTopLevelInstall: true,
|
92
|
-
skipDownload: true,
|
93
|
-
},
|
94
|
-
});
|
95
|
-
// @ts-ignore This symbol is a private API
|
96
|
-
const lambdaFiles = output[lambda_1.FILES_SYMBOL];
|
97
|
-
// When deploying, the `files` that are passed to the Legacy Runtimes already
|
98
|
-
// have certain files that are ignored stripped, but locally, that list of
|
99
|
-
// files isn't used by the Legacy Runtimes, so we need to apply the filters
|
100
|
-
// to the outputs that they are returning instead.
|
101
|
-
for (const file in lambdaFiles) {
|
102
|
-
if (shouldIgnorePath(file, ignoreFilter, false)) {
|
103
|
-
delete lambdaFiles[file];
|
104
|
-
}
|
105
|
-
}
|
106
|
-
let handlerFileBase = output.handler;
|
107
|
-
let handlerFile = lambdaFiles[handlerFileBase];
|
108
|
-
let handlerHasImport = false;
|
109
|
-
const { handler } = output;
|
110
|
-
const handlerMethod = handler.split('.').pop();
|
111
|
-
const handlerFileName = handler.replace(`.${handlerMethod}`, '');
|
112
|
-
// For compiled languages, the launcher file for the Lambda generated
|
113
|
-
// by the Legacy Runtime matches the `handler` defined for it, but for
|
114
|
-
// interpreted languages, the `handler` consists of the launcher file name
|
115
|
-
// without an extension, plus the name of the method inside of that file
|
116
|
-
// that should be invoked, so we have to construct the file path explicitly.
|
117
|
-
if (!handlerFile) {
|
118
|
-
handlerFileBase = handlerFileName + ext;
|
119
|
-
handlerFile = lambdaFiles[handlerFileBase];
|
120
|
-
handlerHasImport = true;
|
121
|
-
}
|
122
|
-
if (!handlerFile || !handlerFile.fsPath) {
|
123
|
-
throw new Error(`Could not find a handler file. Please ensure that \`files\` for the returned \`Lambda\` contains an \`FileFsRef\` named "${handlerFileBase}" with a valid \`fsPath\`.`);
|
124
|
-
}
|
125
|
-
const handlerExtName = path_1.extname(handlerFile.fsPath);
|
126
|
-
const entryBase = path_1.basename(entrypoint).replace(ext, handlerExtName);
|
127
|
-
const entryPath = path_1.join(path_1.dirname(entrypoint), entryBase);
|
128
|
-
const entry = path_1.join(entryRoot, entryPath);
|
129
|
-
// Create the parent directory of the API Route that will be created
|
130
|
-
// for the current entrypoint inside of `.output/server/pages/api`.
|
131
|
-
await fs_extra_1.default.ensureDir(path_1.dirname(entry));
|
132
|
-
// For compiled languages, the launcher file will be binary and therefore
|
133
|
-
// won't try to import a user-provided request handler (instead, it will
|
134
|
-
// contain it). But for interpreted languages, the launcher might try to
|
135
|
-
// load a user-provided request handler from the source file instead of bundling
|
136
|
-
// it, so we have to adjust the import statement inside the launcher to point
|
137
|
-
// to the respective source file. Previously, Legacy Runtimes simply expected
|
138
|
-
// the user-provided request-handler to be copied right next to the launcher,
|
139
|
-
// but with the new File System API, files won't be moved around unnecessarily.
|
140
|
-
if (handlerHasImport) {
|
141
|
-
const { fsPath } = handlerFile;
|
142
|
-
const encoding = 'utf-8';
|
143
|
-
// This is the true directory of the user-provided request handler in the
|
144
|
-
// source files, so that's what we will use as an import path in the launcher.
|
145
|
-
const locationPrefix = path_1.relative(entry, outputPath);
|
146
|
-
let handlerContent = await fs_extra_1.default.readFile(fsPath, encoding);
|
147
|
-
const importPaths = [
|
148
|
-
// This is the full entrypoint path, like `./api/test.py`. In our tests
|
149
|
-
// Python didn't support importing from a parent directory without using different
|
150
|
-
// code in the launcher that registers it as a location for modules and then changing
|
151
|
-
// the importing syntax, but continuing to import it like before seems to work. If
|
152
|
-
// other languages need this, we should consider excluding Python explicitly.
|
153
|
-
// `./${entrypoint}`,
|
154
|
-
// This is the entrypoint path without extension, like `api/test`
|
155
|
-
entrypoint.slice(0, -ext.length),
|
156
|
-
];
|
157
|
-
// Generate a list of regular expressions that we can use for
|
158
|
-
// finding matches, but only allow matches if the import path is
|
159
|
-
// wrapped inside single (') or double quotes (").
|
160
|
-
const patterns = importPaths.map(path => {
|
161
|
-
// eslint-disable-next-line no-useless-escape
|
162
|
-
return new RegExp(`('|")(${path.replace(/\./g, '\\.')})('|")`, 'g');
|
163
|
-
});
|
164
|
-
let replacedMatch = null;
|
165
|
-
for (const pattern of patterns) {
|
166
|
-
const newContent = handlerContent.replace(pattern, (_, p1, p2, p3) => {
|
167
|
-
return `${p1}${path_1.join(locationPrefix, p2)}${p3}`;
|
168
|
-
});
|
169
|
-
if (newContent !== handlerContent) {
|
170
|
-
_1.debug(`Replaced "${pattern}" inside "${entry}" to ensure correct import of user-provided request handler`);
|
171
|
-
handlerContent = newContent;
|
172
|
-
replacedMatch = true;
|
173
|
-
}
|
174
|
-
}
|
175
|
-
if (!replacedMatch) {
|
176
|
-
new Error(`No replacable matches for "${importPaths[0]}" or "${importPaths[1]}" found in "${fsPath}"`);
|
177
|
-
}
|
178
|
-
await fs_extra_1.default.writeFile(entry, handlerContent, encoding);
|
179
|
-
}
|
180
|
-
else {
|
181
|
-
await fs_extra_1.default.copy(handlerFile.fsPath, entry);
|
182
|
-
}
|
183
|
-
// Legacy Runtimes based on interpreted languages will create a new launcher file
|
184
|
-
// for every entrypoint, but they will create each one inside `workPath`, which means that
|
185
|
-
// the launcher for one entrypoint will overwrite the launcher provided for the previous
|
186
|
-
// entrypoint. That's why, above, we copy the file contents into the new destination (and
|
187
|
-
// optionally transform them along the way), instead of linking. We then also want to remove
|
188
|
-
// the copy origin right here, so that the `workPath` doesn't contain a useless launcher file
|
189
|
-
// once the build has finished running.
|
190
|
-
await fs_extra_1.default.remove(handlerFile.fsPath);
|
191
|
-
_1.debug(`Removed temporary file "${handlerFile.fsPath}"`);
|
192
|
-
const nft = `${entry}.nft.json`;
|
193
|
-
const json = JSON.stringify({
|
194
|
-
version: 2,
|
195
|
-
files: Object.keys(lambdaFiles)
|
196
|
-
.map(file => {
|
197
|
-
const { fsPath } = lambdaFiles[file];
|
198
|
-
if (!fsPath) {
|
199
|
-
throw new Error(`File "${file}" is missing valid \`fsPath\` property`);
|
200
|
-
}
|
201
|
-
// The handler was already moved into position above.
|
202
|
-
if (file === handlerFileBase) {
|
203
|
-
return;
|
204
|
-
}
|
205
|
-
return normalize_path_1.normalizePath(path_1.relative(path_1.dirname(nft), fsPath));
|
206
|
-
})
|
207
|
-
.filter(Boolean),
|
208
|
-
});
|
209
|
-
await fs_extra_1.default.writeFile(nft, json);
|
210
|
-
// Add an entry that will later on be added to the `functions-manifest.json`
|
211
|
-
// file that is placed inside of the `.output` directory.
|
212
|
-
pages[normalize_path_1.normalizePath(entryPath)] = {
|
213
|
-
// Because the underlying file used as a handler was placed
|
214
|
-
// inside `.output/server/pages/api`, it no longer has the name it originally
|
215
|
-
// had and is now named after the API Route that it's responsible for,
|
216
|
-
// so we have to adjust the name of the Lambda handler accordingly.
|
217
|
-
handler: handler.replace(handlerFileName, path_1.parse(entry).name),
|
218
|
-
runtime: output.runtime,
|
219
|
-
memory: output.memory,
|
220
|
-
maxDuration: output.maxDuration,
|
221
|
-
environment: output.environment,
|
222
|
-
allowQuery: output.allowQuery,
|
223
|
-
};
|
224
|
-
}
|
225
|
-
// Add any Serverless Functions that were exposed by the Legacy Runtime
|
226
|
-
// to the `functions-manifest.json` file provided in `.output`.
|
227
|
-
await _experimental_updateFunctionsManifest({ workPath, pages });
|
228
|
-
};
|
229
|
-
}
|
230
|
-
exports._experimental_convertRuntimeToPlugin = _experimental_convertRuntimeToPlugin;
|
231
|
-
async function readJson(filePath) {
|
232
|
-
try {
|
233
|
-
const str = await fs_extra_1.default.readFile(filePath, 'utf8');
|
234
|
-
return JSON.parse(str);
|
235
|
-
}
|
236
|
-
catch (err) {
|
237
|
-
if (err.code === 'ENOENT') {
|
238
|
-
return {};
|
239
|
-
}
|
240
|
-
throw err;
|
241
|
-
}
|
242
|
-
}
|
243
|
-
/**
|
244
|
-
* If `.output/functions-manifest.json` exists, append to the pages
|
245
|
-
* property. Otherwise write a new file.
|
246
|
-
*/
|
247
|
-
async function _experimental_updateFunctionsManifest({ workPath, pages, }) {
|
248
|
-
const functionsManifestPath = path_1.join(workPath, '.output', 'functions-manifest.json');
|
249
|
-
const functionsManifest = await readJson(functionsManifestPath);
|
250
|
-
if (!functionsManifest.version)
|
251
|
-
functionsManifest.version = 2;
|
252
|
-
if (!functionsManifest.pages)
|
253
|
-
functionsManifest.pages = {};
|
254
|
-
for (const [pageKey, pageConfig] of Object.entries(pages)) {
|
255
|
-
functionsManifest.pages[pageKey] = { ...pageConfig };
|
256
|
-
}
|
257
|
-
await fs_extra_1.default.writeFile(functionsManifestPath, JSON.stringify(functionsManifest));
|
258
|
-
}
|
259
|
-
exports._experimental_updateFunctionsManifest = _experimental_updateFunctionsManifest;
|
260
|
-
/**
|
261
|
-
* Append routes to the `routes-manifest.json` file.
|
262
|
-
* If the file does not exist, it will be created.
|
263
|
-
*/
|
264
|
-
async function _experimental_updateRoutesManifest({ workPath, redirects, rewrites, headers, dynamicRoutes, staticRoutes, }) {
|
265
|
-
const routesManifestPath = path_1.join(workPath, '.output', 'routes-manifest.json');
|
266
|
-
const routesManifest = await readJson(routesManifestPath);
|
267
|
-
if (!routesManifest.version)
|
268
|
-
routesManifest.version = 3;
|
269
|
-
if (routesManifest.pages404 === undefined)
|
270
|
-
routesManifest.pages404 = true;
|
271
|
-
if (redirects) {
|
272
|
-
if (!routesManifest.redirects)
|
273
|
-
routesManifest.redirects = [];
|
274
|
-
routesManifest.redirects.push(...redirects);
|
275
|
-
}
|
276
|
-
if (rewrites) {
|
277
|
-
if (!routesManifest.rewrites)
|
278
|
-
routesManifest.rewrites = [];
|
279
|
-
routesManifest.rewrites.push(...rewrites);
|
280
|
-
}
|
281
|
-
if (headers) {
|
282
|
-
if (!routesManifest.headers)
|
283
|
-
routesManifest.headers = [];
|
284
|
-
routesManifest.headers.push(...headers);
|
285
|
-
}
|
286
|
-
if (dynamicRoutes) {
|
287
|
-
if (!routesManifest.dynamicRoutes)
|
288
|
-
routesManifest.dynamicRoutes = [];
|
289
|
-
routesManifest.dynamicRoutes.push(...dynamicRoutes);
|
290
|
-
}
|
291
|
-
if (staticRoutes) {
|
292
|
-
if (!routesManifest.staticRoutes)
|
293
|
-
routesManifest.staticRoutes = [];
|
294
|
-
routesManifest.staticRoutes.push(...staticRoutes);
|
295
|
-
}
|
296
|
-
await fs_extra_1.default.writeFile(routesManifestPath, JSON.stringify(routesManifest));
|
297
|
-
}
|
298
|
-
exports._experimental_updateRoutesManifest = _experimental_updateRoutesManifest;
|