@vercel/build-utils 2.12.3-canary.28 → 2.12.3-canary.31

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.
@@ -10,6 +10,36 @@ const glob_1 = __importDefault(require("./fs/glob"));
10
10
  const normalize_path_1 = require("./fs/normalize-path");
11
11
  const lambda_1 = require("./lambda");
12
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
+ };
13
43
  /**
14
44
  * Convert legacy Runtime to a Plugin.
15
45
  * @param buildRuntime - a legacy build() function from a Runtime
@@ -19,29 +49,25 @@ const _1 = require(".");
19
49
  function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
20
50
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
21
51
  return async function build({ workPath }) {
22
- const opts = { cwd: workPath };
23
- const files = await glob_1.default('**', opts);
24
- // `.output` was already created by the Build Command, so we have
25
- // to ensure its contents don't get bundled into the Lambda. Similarily,
26
- // we don't want to bundle anything from `.vercel` either. Lastly,
27
- // Builders/Runtimes didn't have `vercel.json` or `now.json`.
28
- const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
29
52
  // We also don't want to provide any files to Runtimes that were ignored
30
53
  // through `.vercelignore` or `.nowignore`, because the Build Step does the same.
31
54
  const ignoreFilter = await _1.getIgnoreFilter(workPath);
32
- // We're not passing this as an `ignore` filter to the `glob` function above,
33
- // so that we can re-use exactly the same `getIgnoreFilter` method that the
34
- // Build Step uses (literally the same code).
35
- for (const file in files) {
36
- const isNative = ignoredPaths.some(item => {
37
- return file.startsWith(item);
38
- });
39
- if (isNative || ignoreFilter(file)) {
40
- delete files[file];
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];
41
69
  }
42
70
  }
43
- const entrypointPattern = `api/**/*${ext}`;
44
- const entrypoints = await glob_1.default(entrypointPattern, opts);
45
71
  const pages = {};
46
72
  const pluginName = packageName.replace('vercel-plugin-', '');
47
73
  const traceDir = path_1.join(workPath, `.output`, `inputs`,
@@ -53,7 +79,7 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
53
79
  await fs_extra_1.default.ensureDir(traceDir);
54
80
  for (const entrypoint of Object.keys(entrypoints)) {
55
81
  const { output } = await buildRuntime({
56
- files,
82
+ files: sourceFilesPreBuild,
57
83
  entrypoint,
58
84
  workPath,
59
85
  config: {
@@ -63,8 +89,23 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
63
89
  avoidTopLevelInstall: true,
64
90
  },
65
91
  });
92
+ // Legacy Runtimes tend to pollute the `workPath` with compiled results,
93
+ // because the `workPath` used to be a place that was a place where they could
94
+ // just put anything, but nowadays it's the working directory of the `vercel build`
95
+ // command, which is the place where the developer keeps their source files,
96
+ // so we don't want to pollute this space unnecessarily. That means we have to clean
97
+ // up files that were created by the build, which is done further below.
98
+ const sourceFilesAfterBuild = await getSourceFiles(workPath, ignoreFilter);
99
+ // Further down, we will need the filename of the Lambda handler
100
+ // for placing it inside `server/pages/api`, but because Legacy Runtimes
101
+ // don't expose the filename directly, we have to construct it
102
+ // from the handler name, and then find the matching file further below,
103
+ // because we don't yet know its extension here.
104
+ const handler = output.handler;
105
+ const handlerMethod = handler.split('.').reverse()[0];
106
+ const handlerFileName = handler.replace(`.${handlerMethod}`, '');
66
107
  pages[entrypoint] = {
67
- handler: output.handler,
108
+ handler: handler,
68
109
  runtime: output.runtime,
69
110
  memory: output.memory,
70
111
  maxDuration: output.maxDuration,
@@ -73,12 +114,42 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
73
114
  };
74
115
  // @ts-ignore This symbol is a private API
75
116
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
117
+ // When deploying, the `files` that are passed to the Legacy Runtimes already
118
+ // have certain files that are ignored stripped, but locally, that list of
119
+ // files isn't used by the Legacy Runtimes, so we need to apply the filters
120
+ // to the outputs that they are returning instead.
121
+ for (const file in lambdaFiles) {
122
+ if (shouldIgnorePath(file, ignoreFilter, false)) {
123
+ delete lambdaFiles[file];
124
+ }
125
+ }
126
+ const handlerFilePath = Object.keys(lambdaFiles).find(item => {
127
+ return path_1.parse(item).name === handlerFileName;
128
+ });
129
+ const handlerFileOrigin = lambdaFiles[handlerFilePath || ''].fsPath;
130
+ if (!handlerFileOrigin) {
131
+ 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).`);
132
+ }
76
133
  const entry = path_1.join(workPath, '.output', 'server', 'pages', entrypoint);
77
134
  await fs_extra_1.default.ensureDir(path_1.dirname(entry));
78
- await linkOrCopy(files[entrypoint].fsPath, entry);
135
+ await linkOrCopy(handlerFileOrigin, entry);
136
+ const toRemove = [];
137
+ // You can find more details about this at the point where the
138
+ // `sourceFilesAfterBuild` is created originally.
139
+ for (const file in sourceFilesAfterBuild) {
140
+ if (!sourceFilesPreBuild[file]) {
141
+ const path = sourceFilesAfterBuild[file].fsPath;
142
+ toRemove.push(fs_extra_1.default.remove(path));
143
+ }
144
+ }
145
+ await Promise.all(toRemove);
79
146
  const tracedFiles = [];
80
147
  Object.entries(lambdaFiles).forEach(async ([relPath, file]) => {
81
148
  const newPath = path_1.join(traceDir, relPath);
149
+ // The handler was already moved into position above.
150
+ if (relPath === handlerFilePath) {
151
+ return;
152
+ }
82
153
  tracedFiles.push({ absolutePath: newPath, relativePath: relPath });
83
154
  if (file.fsPath) {
84
155
  await linkOrCopy(file.fsPath, newPath);
@@ -94,9 +165,9 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
94
165
  const nft = path_1.join(workPath, '.output', 'server', 'pages', `${entrypoint}.nft.json`);
95
166
  const json = JSON.stringify({
96
167
  version: 1,
97
- files: tracedFiles.map(f => ({
98
- input: normalize_path_1.normalizePath(path_1.relative(nft, f.absolutePath)),
99
- output: normalize_path_1.normalizePath(f.relativePath),
168
+ files: tracedFiles.map(file => ({
169
+ input: normalize_path_1.normalizePath(path_1.relative(nft, file.absolutePath)),
170
+ output: normalize_path_1.normalizePath(file.relativePath),
100
171
  })),
101
172
  });
102
173
  await fs_extra_1.default.ensureDir(path_1.dirname(nft));
package/dist/index.js CHANGED
@@ -32757,6 +32757,36 @@ const glob_1 = __importDefault(__webpack_require__(4240));
32757
32757
  const normalize_path_1 = __webpack_require__(6261);
32758
32758
  const lambda_1 = __webpack_require__(6721);
32759
32759
  const _1 = __webpack_require__(2855);
32760
+ // `.output` was already created by the Build Command, so we have
32761
+ // to ensure its contents don't get bundled into the Lambda. Similarily,
32762
+ // we don't want to bundle anything from `.vercel` either. Lastly,
32763
+ // Builders/Runtimes didn't have `vercel.json` or `now.json`.
32764
+ const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
32765
+ const shouldIgnorePath = (file, ignoreFilter, ignoreFile) => {
32766
+ const isNative = ignoredPaths.some(item => {
32767
+ return file.startsWith(item);
32768
+ });
32769
+ if (!ignoreFile) {
32770
+ return isNative;
32771
+ }
32772
+ return isNative || ignoreFilter(file);
32773
+ };
32774
+ const getSourceFiles = async (workPath, ignoreFilter) => {
32775
+ const list = await glob_1.default('**', {
32776
+ cwd: workPath,
32777
+ });
32778
+ // We're not passing this as an `ignore` filter to the `glob` function above,
32779
+ // so that we can re-use exactly the same `getIgnoreFilter` method that the
32780
+ // Build Step uses (literally the same code). Note that this exclusion only applies
32781
+ // when deploying. Locally, another exclusion is needed, which is handled
32782
+ // further below in the `convertRuntimeToPlugin` function.
32783
+ for (const file in list) {
32784
+ if (shouldIgnorePath(file, ignoreFilter, true)) {
32785
+ delete list[file];
32786
+ }
32787
+ }
32788
+ return list;
32789
+ };
32760
32790
  /**
32761
32791
  * Convert legacy Runtime to a Plugin.
32762
32792
  * @param buildRuntime - a legacy build() function from a Runtime
@@ -32766,29 +32796,25 @@ const _1 = __webpack_require__(2855);
32766
32796
  function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32767
32797
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
32768
32798
  return async function build({ workPath }) {
32769
- const opts = { cwd: workPath };
32770
- const files = await glob_1.default('**', opts);
32771
- // `.output` was already created by the Build Command, so we have
32772
- // to ensure its contents don't get bundled into the Lambda. Similarily,
32773
- // we don't want to bundle anything from `.vercel` either. Lastly,
32774
- // Builders/Runtimes didn't have `vercel.json` or `now.json`.
32775
- const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
32776
32799
  // We also don't want to provide any files to Runtimes that were ignored
32777
32800
  // through `.vercelignore` or `.nowignore`, because the Build Step does the same.
32778
32801
  const ignoreFilter = await _1.getIgnoreFilter(workPath);
32779
- // We're not passing this as an `ignore` filter to the `glob` function above,
32780
- // so that we can re-use exactly the same `getIgnoreFilter` method that the
32781
- // Build Step uses (literally the same code).
32782
- for (const file in files) {
32783
- const isNative = ignoredPaths.some(item => {
32784
- return file.startsWith(item);
32785
- });
32786
- if (isNative || ignoreFilter(file)) {
32787
- delete files[file];
32802
+ // Retrieve the files that are currently available on the File System,
32803
+ // before the Legacy Runtime has even started to build.
32804
+ const sourceFilesPreBuild = await getSourceFiles(workPath, ignoreFilter);
32805
+ // Instead of doing another `glob` to get all the matching source files,
32806
+ // we'll filter the list of existing files down to only the ones
32807
+ // that are matching the entrypoint pattern, so we're first creating
32808
+ // a clean new list to begin.
32809
+ const entrypoints = Object.assign({}, sourceFilesPreBuild);
32810
+ const entrypointMatch = new RegExp(`^api/.*${ext}$`);
32811
+ // Up next, we'll strip out the files from the list of entrypoints
32812
+ // that aren't actually considered entrypoints.
32813
+ for (const file in entrypoints) {
32814
+ if (!entrypointMatch.test(file)) {
32815
+ delete entrypoints[file];
32788
32816
  }
32789
32817
  }
32790
- const entrypointPattern = `api/**/*${ext}`;
32791
- const entrypoints = await glob_1.default(entrypointPattern, opts);
32792
32818
  const pages = {};
32793
32819
  const pluginName = packageName.replace('vercel-plugin-', '');
32794
32820
  const traceDir = path_1.join(workPath, `.output`, `inputs`,
@@ -32800,7 +32826,7 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32800
32826
  await fs_extra_1.default.ensureDir(traceDir);
32801
32827
  for (const entrypoint of Object.keys(entrypoints)) {
32802
32828
  const { output } = await buildRuntime({
32803
- files,
32829
+ files: sourceFilesPreBuild,
32804
32830
  entrypoint,
32805
32831
  workPath,
32806
32832
  config: {
@@ -32810,8 +32836,23 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32810
32836
  avoidTopLevelInstall: true,
32811
32837
  },
32812
32838
  });
32839
+ // Legacy Runtimes tend to pollute the `workPath` with compiled results,
32840
+ // because the `workPath` used to be a place that was a place where they could
32841
+ // just put anything, but nowadays it's the working directory of the `vercel build`
32842
+ // command, which is the place where the developer keeps their source files,
32843
+ // so we don't want to pollute this space unnecessarily. That means we have to clean
32844
+ // up files that were created by the build, which is done further below.
32845
+ const sourceFilesAfterBuild = await getSourceFiles(workPath, ignoreFilter);
32846
+ // Further down, we will need the filename of the Lambda handler
32847
+ // for placing it inside `server/pages/api`, but because Legacy Runtimes
32848
+ // don't expose the filename directly, we have to construct it
32849
+ // from the handler name, and then find the matching file further below,
32850
+ // because we don't yet know its extension here.
32851
+ const handler = output.handler;
32852
+ const handlerMethod = handler.split('.').reverse()[0];
32853
+ const handlerFileName = handler.replace(`.${handlerMethod}`, '');
32813
32854
  pages[entrypoint] = {
32814
- handler: output.handler,
32855
+ handler: handler,
32815
32856
  runtime: output.runtime,
32816
32857
  memory: output.memory,
32817
32858
  maxDuration: output.maxDuration,
@@ -32820,12 +32861,42 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32820
32861
  };
32821
32862
  // @ts-ignore This symbol is a private API
32822
32863
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
32864
+ // When deploying, the `files` that are passed to the Legacy Runtimes already
32865
+ // have certain files that are ignored stripped, but locally, that list of
32866
+ // files isn't used by the Legacy Runtimes, so we need to apply the filters
32867
+ // to the outputs that they are returning instead.
32868
+ for (const file in lambdaFiles) {
32869
+ if (shouldIgnorePath(file, ignoreFilter, false)) {
32870
+ delete lambdaFiles[file];
32871
+ }
32872
+ }
32873
+ const handlerFilePath = Object.keys(lambdaFiles).find(item => {
32874
+ return path_1.parse(item).name === handlerFileName;
32875
+ });
32876
+ const handlerFileOrigin = lambdaFiles[handlerFilePath || ''].fsPath;
32877
+ if (!handlerFileOrigin) {
32878
+ 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).`);
32879
+ }
32823
32880
  const entry = path_1.join(workPath, '.output', 'server', 'pages', entrypoint);
32824
32881
  await fs_extra_1.default.ensureDir(path_1.dirname(entry));
32825
- await linkOrCopy(files[entrypoint].fsPath, entry);
32882
+ await linkOrCopy(handlerFileOrigin, entry);
32883
+ const toRemove = [];
32884
+ // You can find more details about this at the point where the
32885
+ // `sourceFilesAfterBuild` is created originally.
32886
+ for (const file in sourceFilesAfterBuild) {
32887
+ if (!sourceFilesPreBuild[file]) {
32888
+ const path = sourceFilesAfterBuild[file].fsPath;
32889
+ toRemove.push(fs_extra_1.default.remove(path));
32890
+ }
32891
+ }
32892
+ await Promise.all(toRemove);
32826
32893
  const tracedFiles = [];
32827
32894
  Object.entries(lambdaFiles).forEach(async ([relPath, file]) => {
32828
32895
  const newPath = path_1.join(traceDir, relPath);
32896
+ // The handler was already moved into position above.
32897
+ if (relPath === handlerFilePath) {
32898
+ return;
32899
+ }
32829
32900
  tracedFiles.push({ absolutePath: newPath, relativePath: relPath });
32830
32901
  if (file.fsPath) {
32831
32902
  await linkOrCopy(file.fsPath, newPath);
@@ -32841,9 +32912,9 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32841
32912
  const nft = path_1.join(workPath, '.output', 'server', 'pages', `${entrypoint}.nft.json`);
32842
32913
  const json = JSON.stringify({
32843
32914
  version: 1,
32844
- files: tracedFiles.map(f => ({
32845
- input: normalize_path_1.normalizePath(path_1.relative(nft, f.absolutePath)),
32846
- output: normalize_path_1.normalizePath(f.relativePath),
32915
+ files: tracedFiles.map(file => ({
32916
+ input: normalize_path_1.normalizePath(path_1.relative(nft, file.absolutePath)),
32917
+ output: normalize_path_1.normalizePath(file.relativePath),
32847
32918
  })),
32848
32919
  });
32849
32920
  await fs_extra_1.default.ensureDir(path_1.dirname(nft));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/build-utils",
3
- "version": "2.12.3-canary.28",
3
+ "version": "2.12.3-canary.31",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -49,5 +49,5 @@
49
49
  "typescript": "4.3.4",
50
50
  "yazl": "2.4.3"
51
51
  },
52
- "gitHead": "792ab38760eca4543a7ac02dd05eda280b5328a1"
52
+ "gitHead": "6f4a1b527ba01973490e1fb2e4c48ccb2841cd86"
53
53
  }