@vercel/build-utils 2.12.3-canary.29 → 2.12.3-canary.32

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.
@@ -24,6 +24,22 @@ const shouldIgnorePath = (file, ignoreFilter, ignoreFile) => {
24
24
  }
25
25
  return isNative || ignoreFilter(file);
26
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
+ };
27
43
  /**
28
44
  * Convert legacy Runtime to a Plugin.
29
45
  * @param buildRuntime - a legacy build() function from a Runtime
@@ -33,22 +49,25 @@ const shouldIgnorePath = (file, ignoreFilter, ignoreFile) => {
33
49
  function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
34
50
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
35
51
  return async function build({ workPath }) {
36
- const opts = { cwd: workPath };
37
- const files = await glob_1.default('**', opts);
38
52
  // We also don't want to provide any files to Runtimes that were ignored
39
53
  // through `.vercelignore` or `.nowignore`, because the Build Step does the same.
40
54
  const ignoreFilter = await _1.getIgnoreFilter(workPath);
41
- // We're not passing this as an `ignore` filter to the `glob` function above,
42
- // so that we can re-use exactly the same `getIgnoreFilter` method that the
43
- // Build Step uses (literally the same code). Note that this exclusion only applies
44
- // when deploying. Locally, another exclusion further below is needed.
45
- for (const file in files) {
46
- if (shouldIgnorePath(file, ignoreFilter, true)) {
47
- 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];
48
69
  }
49
70
  }
50
- const entrypointPattern = `api/**/*${ext}`;
51
- const entrypoints = await glob_1.default(entrypointPattern, opts);
52
71
  const pages = {};
53
72
  const pluginName = packageName.replace('vercel-plugin-', '');
54
73
  const traceDir = path_1.join(workPath, `.output`, `inputs`,
@@ -60,7 +79,7 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
60
79
  await fs_extra_1.default.ensureDir(traceDir);
61
80
  for (const entrypoint of Object.keys(entrypoints)) {
62
81
  const { output } = await buildRuntime({
63
- files,
82
+ files: sourceFilesPreBuild,
64
83
  entrypoint,
65
84
  workPath,
66
85
  config: {
@@ -70,8 +89,23 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
70
89
  avoidTopLevelInstall: true,
71
90
  },
72
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}`, '');
73
107
  pages[entrypoint] = {
74
- handler: output.handler,
108
+ handler: handler,
75
109
  runtime: output.runtime,
76
110
  memory: output.memory,
77
111
  maxDuration: output.maxDuration,
@@ -86,15 +120,36 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
86
120
  // to the outputs that they are returning instead.
87
121
  for (const file in lambdaFiles) {
88
122
  if (shouldIgnorePath(file, ignoreFilter, false)) {
89
- delete files[file];
123
+ delete lambdaFiles[file];
90
124
  }
91
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
+ }
92
133
  const entry = path_1.join(workPath, '.output', 'server', 'pages', entrypoint);
93
134
  await fs_extra_1.default.ensureDir(path_1.dirname(entry));
94
- 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);
95
146
  const tracedFiles = [];
96
147
  Object.entries(lambdaFiles).forEach(async ([relPath, file]) => {
97
148
  const newPath = path_1.join(traceDir, relPath);
149
+ // The handler was already moved into position above.
150
+ if (relPath === handlerFilePath) {
151
+ return;
152
+ }
98
153
  tracedFiles.push({ absolutePath: newPath, relativePath: relPath });
99
154
  if (file.fsPath) {
100
155
  await linkOrCopy(file.fsPath, newPath);
@@ -110,9 +165,9 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
110
165
  const nft = path_1.join(workPath, '.output', 'server', 'pages', `${entrypoint}.nft.json`);
111
166
  const json = JSON.stringify({
112
167
  version: 1,
113
- files: tracedFiles.map(f => ({
114
- input: normalize_path_1.normalizePath(path_1.relative(nft, f.absolutePath)),
115
- output: normalize_path_1.normalizePath(f.relativePath),
168
+ files: tracedFiles.map(file => ({
169
+ input: normalize_path_1.normalizePath(path_1.relative(path_1.dirname(nft), file.absolutePath)),
170
+ output: normalize_path_1.normalizePath(file.relativePath),
116
171
  })),
117
172
  });
118
173
  await fs_extra_1.default.ensureDir(path_1.dirname(nft));
package/dist/index.js CHANGED
@@ -32771,6 +32771,22 @@ const shouldIgnorePath = (file, ignoreFilter, ignoreFile) => {
32771
32771
  }
32772
32772
  return isNative || ignoreFilter(file);
32773
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
+ };
32774
32790
  /**
32775
32791
  * Convert legacy Runtime to a Plugin.
32776
32792
  * @param buildRuntime - a legacy build() function from a Runtime
@@ -32780,22 +32796,25 @@ const shouldIgnorePath = (file, ignoreFilter, ignoreFile) => {
32780
32796
  function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32781
32797
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
32782
32798
  return async function build({ workPath }) {
32783
- const opts = { cwd: workPath };
32784
- const files = await glob_1.default('**', opts);
32785
32799
  // We also don't want to provide any files to Runtimes that were ignored
32786
32800
  // through `.vercelignore` or `.nowignore`, because the Build Step does the same.
32787
32801
  const ignoreFilter = await _1.getIgnoreFilter(workPath);
32788
- // We're not passing this as an `ignore` filter to the `glob` function above,
32789
- // so that we can re-use exactly the same `getIgnoreFilter` method that the
32790
- // Build Step uses (literally the same code). Note that this exclusion only applies
32791
- // when deploying. Locally, another exclusion further below is needed.
32792
- for (const file in files) {
32793
- if (shouldIgnorePath(file, ignoreFilter, true)) {
32794
- 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];
32795
32816
  }
32796
32817
  }
32797
- const entrypointPattern = `api/**/*${ext}`;
32798
- const entrypoints = await glob_1.default(entrypointPattern, opts);
32799
32818
  const pages = {};
32800
32819
  const pluginName = packageName.replace('vercel-plugin-', '');
32801
32820
  const traceDir = path_1.join(workPath, `.output`, `inputs`,
@@ -32807,7 +32826,7 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32807
32826
  await fs_extra_1.default.ensureDir(traceDir);
32808
32827
  for (const entrypoint of Object.keys(entrypoints)) {
32809
32828
  const { output } = await buildRuntime({
32810
- files,
32829
+ files: sourceFilesPreBuild,
32811
32830
  entrypoint,
32812
32831
  workPath,
32813
32832
  config: {
@@ -32817,8 +32836,23 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32817
32836
  avoidTopLevelInstall: true,
32818
32837
  },
32819
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}`, '');
32820
32854
  pages[entrypoint] = {
32821
- handler: output.handler,
32855
+ handler: handler,
32822
32856
  runtime: output.runtime,
32823
32857
  memory: output.memory,
32824
32858
  maxDuration: output.maxDuration,
@@ -32833,15 +32867,36 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32833
32867
  // to the outputs that they are returning instead.
32834
32868
  for (const file in lambdaFiles) {
32835
32869
  if (shouldIgnorePath(file, ignoreFilter, false)) {
32836
- delete files[file];
32870
+ delete lambdaFiles[file];
32837
32871
  }
32838
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
+ }
32839
32880
  const entry = path_1.join(workPath, '.output', 'server', 'pages', entrypoint);
32840
32881
  await fs_extra_1.default.ensureDir(path_1.dirname(entry));
32841
- 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);
32842
32893
  const tracedFiles = [];
32843
32894
  Object.entries(lambdaFiles).forEach(async ([relPath, file]) => {
32844
32895
  const newPath = path_1.join(traceDir, relPath);
32896
+ // The handler was already moved into position above.
32897
+ if (relPath === handlerFilePath) {
32898
+ return;
32899
+ }
32845
32900
  tracedFiles.push({ absolutePath: newPath, relativePath: relPath });
32846
32901
  if (file.fsPath) {
32847
32902
  await linkOrCopy(file.fsPath, newPath);
@@ -32857,9 +32912,9 @@ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32857
32912
  const nft = path_1.join(workPath, '.output', 'server', 'pages', `${entrypoint}.nft.json`);
32858
32913
  const json = JSON.stringify({
32859
32914
  version: 1,
32860
- files: tracedFiles.map(f => ({
32861
- input: normalize_path_1.normalizePath(path_1.relative(nft, f.absolutePath)),
32862
- output: normalize_path_1.normalizePath(f.relativePath),
32915
+ files: tracedFiles.map(file => ({
32916
+ input: normalize_path_1.normalizePath(path_1.relative(path_1.dirname(nft), file.absolutePath)),
32917
+ output: normalize_path_1.normalizePath(file.relativePath),
32863
32918
  })),
32864
32919
  });
32865
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.29",
3
+ "version": "2.12.3-canary.32",
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": "9b3aa41f2e8d40b560969305af8cf26dcd6da8c9"
52
+ "gitHead": "ba7bf2e4a60bc4c9fd35ad33a11d94f1dae2ac81"
53
53
  }