@vercel/static-build 0.18.1-canary.1 → 0.22.2-canary.2

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.
@@ -14,7 +14,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
14
14
  var __importStar = (this && this.__importStar) || function (mod) {
15
15
  if (mod && mod.__esModule) return mod;
16
16
  var result = {};
17
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
18
  __setModuleDefault(result, mod);
19
19
  return result;
20
20
  };
@@ -38,11 +38,13 @@ async function injectVercelAnalyticsPlugin(dir) {
38
38
  const gatsbyConfigName = 'gatsby-config.js';
39
39
  const gatsbyPluginPackageName = 'gatsby-plugin-vercel';
40
40
  const gatsbyConfigPath = path.join(dir, gatsbyConfigName);
41
+ console.log(`Injecting Gatsby.js analytics plugin "${gatsbyPluginPackageName}" to \`${gatsbyConfigPath}\``);
41
42
  const pkgJson = (await _shared_1.readPackageJson(dir));
42
43
  if (!pkgJson.dependencies) {
43
44
  pkgJson.dependencies = {};
44
45
  }
45
46
  if (!pkgJson.dependencies[gatsbyPluginPackageName]) {
47
+ console.log(`Adding "${gatsbyPluginPackageName}" to \`package.json\` "dependencies"`);
46
48
  pkgJson.dependencies[gatsbyPluginPackageName] = 'latest';
47
49
  await _shared_1.writePackageJson(dir, pkgJson);
48
50
  }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.injectVercelAnalyticsPlugin = void 0;
4
+ const path_1 = require("path");
5
+ const rc9_1 = require("rc9");
6
+ const _shared_1 = require("./_shared");
7
+ // https://github.com/nuxt-community/web-vitals-module
8
+ const ANALYTICS_PLUGIN_PACKAGE = '@nuxtjs/web-vitals';
9
+ async function injectVercelAnalyticsPlugin(dir) {
10
+ // First update the `.nuxtrc` file to inject the analytics plugin.
11
+ // See: https://gist.github.com/pi0/23b5253ac19b4ed5a70add3b971545c9
12
+ const nuxtrcPath = path_1.join(dir, '.nuxtrc');
13
+ console.log(`Injecting Nuxt.js analytics plugin "${ANALYTICS_PLUGIN_PACKAGE}" to \`${nuxtrcPath}\``);
14
+ rc9_1.update({
15
+ 'modules[]': ANALYTICS_PLUGIN_PACKAGE,
16
+ }, {
17
+ name: nuxtrcPath,
18
+ });
19
+ // The dependency needs to be listed in `package.json` as well so
20
+ // that `npm i` installs the package.
21
+ const pkgJson = (await _shared_1.readPackageJson(dir));
22
+ if (!pkgJson.dependencies) {
23
+ pkgJson.dependencies = {};
24
+ }
25
+ if (!pkgJson.dependencies[ANALYTICS_PLUGIN_PACKAGE]) {
26
+ pkgJson.dependencies[ANALYTICS_PLUGIN_PACKAGE] = 'latest';
27
+ console.log(`Adding "${ANALYTICS_PLUGIN_PACKAGE}" to \`package.json\` "dependencies"`);
28
+ await _shared_1.writePackageJson(dir, pkgJson);
29
+ }
30
+ }
31
+ exports.injectVercelAnalyticsPlugin = injectVercelAnalyticsPlugin;
@@ -3,102 +3,192 @@ 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.readBuildOutputDirectory = void 0;
6
+ exports.readBuildOutputConfig = exports.readBuildOutputDirectory = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = require("fs");
7
9
  const build_utils_1 = require("@vercel/build-utils");
8
10
  const _shared_1 = require("./_shared");
9
- const launcher_1 = require("../launcher");
10
- const fs_1 = require("fs");
11
- const build_utils_2 = __importDefault(require("../build-utils"));
12
- const path_1 = __importDefault(require("path"));
13
- const { createLambda, debug, getLatestNodeVersion, glob } = build_utils_2.default;
11
+ const VERCEL_BUILD_OUTPUT = '.vercel_build_output';
14
12
  /**
15
13
  * Reads the .vercel_build_output directory and returns and object
16
14
  * that should be merged with the build outputs.
17
- *
18
- * At the moment only `functions/node` is supported for functions.
19
15
  */
20
- async function readBuildOutputDirectory({ workPath, }) {
21
- const functions = {};
22
- const functionsMountPath = path_1.default.join('.vercel', 'functions');
23
- Object.assign(functions, await readNodeFunctions({ workPath, functionsMountPath }));
16
+ async function readBuildOutputDirectory({ workPath, nodeVersion, }) {
17
+ const functions = await readFunctions({
18
+ workPath,
19
+ functionsMountPath: path_1.default.join('.vercel', 'functions'),
20
+ nodeVersion,
21
+ });
24
22
  const staticFiles = await readStaticFiles({ workPath });
25
- const routes = await readRoutesConfig({ workPath });
23
+ const routes = (await readBuildOutputConfig({
24
+ workPath,
25
+ configFileName: 'routes.json',
26
+ })) || [];
27
+ const images = await readBuildOutputConfig({
28
+ workPath,
29
+ configFileName: 'images.json',
30
+ });
31
+ const build = await readBuildOutputConfig({
32
+ workPath,
33
+ configFileName: 'build.json',
34
+ });
26
35
  const outputs = {
27
36
  staticFiles: _shared_1.isObjectEmpty(staticFiles) ? null : staticFiles,
28
37
  functions: _shared_1.isObjectEmpty(functions) ? null : functions,
29
38
  routes: routes.length ? routes : null,
39
+ images,
40
+ build,
30
41
  };
31
42
  if (outputs.functions) {
32
- console.log(`Detected Serverless Functions in ".vercel_build_output/functions"`);
43
+ console.log(`Detected Serverless Functions in "${VERCEL_BUILD_OUTPUT}"`);
33
44
  }
34
45
  if (outputs.staticFiles) {
35
- console.log(`Detected Static Assets in ".vercel_build_output/static"`);
46
+ console.log(`Detected Static Assets in "${VERCEL_BUILD_OUTPUT}"`);
36
47
  }
37
48
  if (outputs.routes) {
38
- console.log(`Detected Configuration in ".vercel_build_output/config"`);
49
+ console.log(`Detected Routes Configuration in "${VERCEL_BUILD_OUTPUT}"`);
50
+ }
51
+ if (outputs.images) {
52
+ console.log(`Detected Images Configuration in "${VERCEL_BUILD_OUTPUT}"`);
53
+ }
54
+ if (outputs.build) {
55
+ console.log(`Detected Build Configuration in "${VERCEL_BUILD_OUTPUT}"`);
39
56
  }
40
57
  return outputs;
41
58
  }
42
59
  exports.readBuildOutputDirectory = readBuildOutputDirectory;
43
60
  async function readStaticFiles({ workPath, }) {
44
- const staticFilePath = path_1.default.join(workPath, '.vercel_build_output', 'static');
45
- const staticFiles = await glob('**', {
61
+ const staticFilePath = path_1.default.join(workPath, VERCEL_BUILD_OUTPUT, 'static');
62
+ const staticFiles = await build_utils_1.glob('**', {
46
63
  cwd: staticFilePath,
47
64
  });
48
65
  return staticFiles;
49
66
  }
50
- async function readNodeFunctions({ workPath, functionsMountPath, }) {
67
+ async function readFunctions({ workPath, functionsMountPath, nodeVersion, }) {
51
68
  const output = {};
52
- const nodeFunctionPath = path_1.default.join(workPath, '.vercel_build_output', 'functions', 'node');
53
- const nodeFunctionFiles = await glob('*/index.js', {
54
- cwd: nodeFunctionPath,
55
- });
56
- const nodeBridgeData = await fs_1.promises.readFile(path_1.default.join(__dirname, 'bridge.js'));
57
- for (const fileName of Object.keys(nodeFunctionFiles)) {
58
- const launcherFileName = '___now_launcher';
59
- const bridgeFileName = '___now_bridge';
60
- const launcherFiles = {
61
- [`${launcherFileName}.js`]: new build_utils_1.FileBlob({
62
- data: launcher_1.makeNowLauncher({
63
- entrypointPath: `./index.js`,
64
- bridgePath: `./${bridgeFileName}`,
65
- helpersPath: '',
66
- sourcemapSupportPath: '',
67
- shouldAddHelpers: false,
68
- shouldAddSourcemapSupport: false,
69
- }),
70
- }),
71
- [`${bridgeFileName}.js`]: new build_utils_1.FileBlob({
72
- data: nodeBridgeData,
73
- }),
74
- };
75
- const requiredFiles = await glob('**', {
76
- cwd: path_1.default.join(nodeFunctionPath, path_1.default.dirname(fileName)),
69
+ const functionsConfig = await readFunctionsConfig({ workPath });
70
+ // Find all entrypoints and create a Lambda for each of them.
71
+ let functionsPath = path_1.default.join(workPath, VERCEL_BUILD_OUTPUT, 'functions');
72
+ let functionEntrypoints = await build_utils_1.glob('*/index{,.*}', { cwd: functionsPath });
73
+ let isLegacyFunctions = false;
74
+ // To not break existing projects, we have to keep supporting the `functions/node` folder.
75
+ if (!Object.keys(functionEntrypoints).length) {
76
+ functionsPath = path_1.default.join(functionsPath, 'node');
77
+ functionEntrypoints = await build_utils_1.glob('*/index.{js,mjs}', {
78
+ cwd: functionsPath,
77
79
  });
78
- const lambda = await createLambda({
79
- files: {
80
- ...requiredFiles,
81
- ...launcherFiles,
82
- },
83
- handler: `${launcherFileName}.launcher`,
84
- runtime: getLatestNodeVersion().runtime,
80
+ isLegacyFunctions = true;
81
+ }
82
+ for (const entrypointFile of Object.keys(functionEntrypoints)) {
83
+ let lambda;
84
+ const functionName = path_1.default.dirname(entrypointFile);
85
+ const lambdaConfig = functionsConfig.get(functionName) || {};
86
+ const { runtime, handler, ...config } = lambdaConfig;
87
+ const lambdaFiles = await build_utils_1.glob('**', {
88
+ cwd: path_1.default.join(functionsPath, functionName),
85
89
  });
86
- const parsed = path_1.default.parse(fileName);
87
- const newPath = path_1.default.join(functionsMountPath, parsed.dir, parsed.name);
90
+ if (!lambdaConfig.runtime && isLegacyFunctions) {
91
+ // The bridge and launcher is only added for legacy functions.
92
+ lambda = new build_utils_1.NodejsLambda({
93
+ files: lambdaFiles,
94
+ handler: path_1.default.basename(entrypointFile),
95
+ runtime: nodeVersion.runtime,
96
+ ...config,
97
+ shouldAddHelpers: false,
98
+ shouldAddSourcemapSupport: false,
99
+ });
100
+ }
101
+ else {
102
+ if (!runtime) {
103
+ throw new Error(`Missing the \`runtime\` property for the function \`${functionName}\`.`);
104
+ }
105
+ if (!handler) {
106
+ throw new Error(`Missing the \`handler\` property for the function \`${functionName}\`.`);
107
+ }
108
+ lambda = new build_utils_1.Lambda({
109
+ files: lambdaFiles,
110
+ ...config,
111
+ handler,
112
+ runtime,
113
+ });
114
+ }
115
+ /**
116
+ * For legacy functions we have to keep the `<name>/index` structure,
117
+ * for new functions we'll just use `<name>`, as there is no need to
118
+ * further nest it.
119
+ */
120
+ const parsed = path_1.default.parse(entrypointFile);
121
+ const newPath = isLegacyFunctions
122
+ ? path_1.default.join(functionsMountPath, parsed.dir, parsed.name)
123
+ : path_1.default.join(functionsMountPath, functionName);
88
124
  output[newPath] = lambda;
89
- debug(`Created Lambda "${newPath}" from "${path_1.default.join(nodeFunctionPath, fileName)}".`);
125
+ build_utils_1.debug(`Created Lambda "${newPath}" from "${path_1.default.join(functionsPath, entrypointFile)}".`);
90
126
  }
91
127
  return output;
92
128
  }
93
- async function readRoutesConfig({ workPath, }) {
94
- const routesConfigPath = path_1.default.join(workPath, '.vercel_build_output', 'config', 'routes.json');
129
+ /**
130
+ * Reads the global configuration file for functions and checks its types.
131
+ */
132
+ async function readFunctionsConfig({ workPath }) {
133
+ const data = await fs_1.promises
134
+ .readFile(path_1.default.join(workPath, VERCEL_BUILD_OUTPUT, 'config', 'functions.json'), 'utf8')
135
+ .then(raw => {
136
+ try {
137
+ return JSON.parse(raw);
138
+ }
139
+ catch (_error) {
140
+ return null;
141
+ }
142
+ })
143
+ .catch(error => {
144
+ if (error.code === 'ENOENT') {
145
+ return null;
146
+ }
147
+ throw error;
148
+ });
149
+ const config = new Map();
150
+ if (!data) {
151
+ return config;
152
+ }
153
+ Object.keys(data).forEach(key => {
154
+ const fnConf = parseFunctionConfig(data[key]);
155
+ if (fnConf)
156
+ config.set(key, fnConf);
157
+ });
158
+ return config;
159
+ }
160
+ function parseFunctionConfig(data) {
161
+ if (!data) {
162
+ return null;
163
+ }
164
+ const config = {};
165
+ if (typeof data.memory === 'number') {
166
+ config.memory = data.memory;
167
+ }
168
+ if (typeof data.maxDuration === 'number') {
169
+ config.maxDuration = data.maxDuration;
170
+ }
171
+ // In case of a custom runtime, a custom handler has to be provided.
172
+ if (typeof data.runtime === 'string' && typeof data.handler === 'string') {
173
+ config.runtime = data.runtime;
174
+ config.handler = data.handler;
175
+ }
176
+ if (Array.isArray(data.regions) &&
177
+ data.regions.every(r => typeof r === 'string')) {
178
+ config.regions = data.regions;
179
+ }
180
+ return config;
181
+ }
182
+ async function readBuildOutputConfig({ workPath, configFileName, }) {
183
+ const configPath = path_1.default.join(workPath, VERCEL_BUILD_OUTPUT, 'config', configFileName);
95
184
  try {
96
- return JSON.parse(await fs_1.promises.readFile(routesConfigPath, 'utf8')) || [];
185
+ return JSON.parse(await fs_1.promises.readFile(configPath, 'utf8'));
97
186
  }
98
187
  catch (error) {
99
188
  if (error.code === 'ENOENT') {
100
- return [];
189
+ return undefined;
101
190
  }
102
191
  throw error;
103
192
  }
104
193
  }
194
+ exports.readBuildOutputConfig = readBuildOutputConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/static-build",
3
- "version": "0.18.1-canary.1",
3
+ "version": "0.22.2-canary.2",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index",
6
6
  "homepage": "https://vercel.com/docs/build-step",
@@ -10,13 +10,13 @@
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "https://github.com/vercel/vercel.git",
13
- "directory": "packages/now-static-build"
13
+ "directory": "packages/static-build"
14
14
  },
15
15
  "scripts": {
16
- "build": "./build.sh",
16
+ "build": "node build",
17
17
  "test-unit": "jest --env node --verbose --runInBand --bail test/unit.test.js",
18
18
  "test-integration-once": "jest --env node --verbose --runInBand --bail test/integration.test.js",
19
- "prepublishOnly": "./build.sh"
19
+ "prepublishOnly": "node build"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/aws-lambda": "8.10.64",
@@ -24,12 +24,15 @@
24
24
  "@types/ms": "0.7.31",
25
25
  "@types/node-fetch": "2.5.4",
26
26
  "@types/promise-timeout": "1.3.0",
27
+ "@vercel/build-utils": "2.14.1-canary.5",
28
+ "@vercel/frameworks": "0.6.1-canary.4",
27
29
  "@vercel/ncc": "0.24.0",
30
+ "@vercel/routing-utils": "1.12.1-canary.0",
28
31
  "get-port": "5.0.0",
29
32
  "is-port-reachable": "2.0.1",
30
33
  "ms": "2.1.2",
31
34
  "node-fetch": "2.6.1",
32
- "typescript": "3.9.3"
35
+ "rc9": "1.2.0"
33
36
  },
34
- "gitHead": "a6ec53d9d38edddbbd4dd4753464d08997d6d598"
37
+ "gitHead": "b3ccb5f3ef354da577eeff6ce63d8ee51cfb3e17"
35
38
  }
package/dist/bridge.js DELETED
@@ -1,178 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Bridge = void 0;
4
- const http_1 = require("http");
5
- /**
6
- * If the `http.Server` handler function throws an error asynchronously,
7
- * then it ends up being an unhandled rejection which doesn't kill the node
8
- * process which causes the HTTP request to hang indefinitely. So print the
9
- * error here and force the process to exit so that the lambda invocation
10
- * returns an Unhandled error quickly.
11
- */
12
- process.on('unhandledRejection', err => {
13
- console.error('Unhandled rejection:', err);
14
- process.exit(1);
15
- });
16
- function normalizeNowProxyEvent(event) {
17
- let bodyBuffer;
18
- const { method, path, headers, encoding, body } = JSON.parse(event.body);
19
- if (body) {
20
- if (encoding === 'base64') {
21
- bodyBuffer = Buffer.from(body, encoding);
22
- }
23
- else if (encoding === undefined) {
24
- bodyBuffer = Buffer.from(body);
25
- }
26
- else {
27
- throw new Error(`Unsupported encoding: ${encoding}`);
28
- }
29
- }
30
- else {
31
- bodyBuffer = Buffer.alloc(0);
32
- }
33
- return { isApiGateway: false, method, path, headers, body: bodyBuffer };
34
- }
35
- function normalizeAPIGatewayProxyEvent(event) {
36
- let bodyBuffer;
37
- const { httpMethod: method, path, headers, body } = event;
38
- if (body) {
39
- if (event.isBase64Encoded) {
40
- bodyBuffer = Buffer.from(body, 'base64');
41
- }
42
- else {
43
- bodyBuffer = Buffer.from(body);
44
- }
45
- }
46
- else {
47
- bodyBuffer = Buffer.alloc(0);
48
- }
49
- return { isApiGateway: true, method, path, headers, body: bodyBuffer };
50
- }
51
- function normalizeEvent(event) {
52
- if ('Action' in event) {
53
- if (event.Action === 'Invoke') {
54
- return normalizeNowProxyEvent(event);
55
- }
56
- else {
57
- throw new Error(`Unexpected event.Action: ${event.Action}`);
58
- }
59
- }
60
- else {
61
- return normalizeAPIGatewayProxyEvent(event);
62
- }
63
- }
64
- class Bridge {
65
- constructor(server, shouldStoreEvents = false) {
66
- this.events = {};
67
- this.reqIdSeed = 1;
68
- this.shouldStoreEvents = false;
69
- this.server = null;
70
- this.shouldStoreEvents = shouldStoreEvents;
71
- if (server) {
72
- this.setServer(server);
73
- }
74
- this.launcher = this.launcher.bind(this);
75
- // This is just to appease TypeScript strict mode, since it doesn't
76
- // understand that the Promise constructor is synchronous
77
- this.resolveListening = (_info) => { }; // eslint-disable-line @typescript-eslint/no-unused-vars
78
- this.listening = new Promise(resolve => {
79
- this.resolveListening = resolve;
80
- });
81
- }
82
- setServer(server) {
83
- this.server = server;
84
- }
85
- listen() {
86
- const { server, resolveListening } = this;
87
- if (!server) {
88
- throw new Error('Server has not been set!');
89
- }
90
- if (typeof server.timeout === 'number' && server.timeout > 0) {
91
- // Disable timeout (usually 2 minutes until Node 13).
92
- // Instead, user should assign function `maxDuration`.
93
- server.timeout = 0;
94
- }
95
- return server.listen({
96
- host: '127.0.0.1',
97
- port: 0,
98
- }, function listeningCallback() {
99
- if (!this || typeof this.address !== 'function') {
100
- throw new Error('Missing server.address() function on `this` in server.listen()');
101
- }
102
- const addr = this.address();
103
- if (!addr) {
104
- throw new Error('`server.address()` returned `null`');
105
- }
106
- if (typeof addr === 'string') {
107
- throw new Error(`Unexpected string for \`server.address()\`: ${addr}`);
108
- }
109
- resolveListening(addr);
110
- });
111
- }
112
- async launcher(event, context) {
113
- context.callbackWaitsForEmptyEventLoop = false;
114
- const { port } = await this.listening;
115
- const normalizedEvent = normalizeEvent(event);
116
- const { isApiGateway, method, path, headers, body } = normalizedEvent;
117
- if (this.shouldStoreEvents) {
118
- const reqId = `${this.reqIdSeed++}`;
119
- this.events[reqId] = normalizedEvent;
120
- headers['x-now-bridge-request-id'] = reqId;
121
- }
122
- // eslint-disable-next-line consistent-return
123
- return new Promise((resolve, reject) => {
124
- const opts = { hostname: '127.0.0.1', port, path, method };
125
- const req = http_1.request(opts, res => {
126
- const response = res;
127
- const respBodyChunks = [];
128
- response.on('data', chunk => respBodyChunks.push(Buffer.from(chunk)));
129
- response.on('error', reject);
130
- response.on('end', () => {
131
- const bodyBuffer = Buffer.concat(respBodyChunks);
132
- delete response.headers.connection;
133
- if (isApiGateway) {
134
- delete response.headers['content-length'];
135
- }
136
- else if (response.headers['content-length']) {
137
- response.headers['content-length'] = String(bodyBuffer.length);
138
- }
139
- resolve({
140
- statusCode: response.statusCode || 200,
141
- headers: response.headers,
142
- body: bodyBuffer.toString('base64'),
143
- encoding: 'base64',
144
- });
145
- });
146
- });
147
- req.on('error', error => {
148
- setTimeout(() => {
149
- // this lets express print the true error of why the connection was closed.
150
- // it is probably 'Cannot set headers after they are sent to the client'
151
- reject(error);
152
- }, 2);
153
- });
154
- for (const [name, value] of Object.entries(headers)) {
155
- if (value === undefined) {
156
- console.error('Skipping HTTP request header %j because value is undefined', name);
157
- continue;
158
- }
159
- try {
160
- req.setHeader(name, value);
161
- }
162
- catch (err) {
163
- console.error('Skipping HTTP request header: %j', `${name}: ${value}`);
164
- console.error(err.message);
165
- }
166
- }
167
- if (body)
168
- req.write(body);
169
- req.end();
170
- });
171
- }
172
- consumeEvent(reqId) {
173
- const event = this.events[reqId];
174
- delete this.events[reqId];
175
- return event;
176
- }
177
- }
178
- exports.Bridge = Bridge;
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- let buildUtils;
4
- try {
5
- buildUtils = require('@vercel/build-utils');
6
- }
7
- catch (e) {
8
- // Fallback for older CLI versions
9
- buildUtils = require('@now/build-utils');
10
- }
11
- exports.default = buildUtils;