summaryrefslogtreecommitdiff
path: root/packages/integrations/vercel/src/lib/nft.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/vercel/src/lib/nft.ts')
-rw-r--r--packages/integrations/vercel/src/lib/nft.ts83
1 files changed, 83 insertions, 0 deletions
diff --git a/packages/integrations/vercel/src/lib/nft.ts b/packages/integrations/vercel/src/lib/nft.ts
new file mode 100644
index 000000000..d72979e89
--- /dev/null
+++ b/packages/integrations/vercel/src/lib/nft.ts
@@ -0,0 +1,83 @@
+import { relative as relativePath } from 'node:path';
+import { fileURLToPath, pathToFileURL } from 'node:url';
+import { copyFilesToFolder } from '@astrojs/internal-helpers/fs';
+import { appendForwardSlash } from '@astrojs/internal-helpers/path';
+import type { AstroIntegrationLogger } from 'astro';
+import { searchForWorkspaceRoot } from './searchRoot.js';
+
+export async function copyDependenciesToFunction(
+ {
+ entry,
+ outDir,
+ includeFiles,
+ excludeFiles,
+ logger,
+ root,
+ }: {
+ entry: URL;
+ outDir: URL;
+ includeFiles: URL[];
+ excludeFiles: URL[];
+ logger: AstroIntegrationLogger;
+ root: URL;
+ },
+ // we want to pass the caching by reference, and not by value
+ cache: object
+): Promise<{ handler: string }> {
+ const entryPath = fileURLToPath(entry);
+ logger.info(`Bundling function ${relativePath(fileURLToPath(outDir), entryPath)}`);
+
+ // Set the base to the workspace root
+ const base = pathToFileURL(appendForwardSlash(searchForWorkspaceRoot(fileURLToPath(root))));
+
+ // The Vite bundle includes an import to `@vercel/nft` for some reason,
+ // and that trips up `@vercel/nft` itself during the adapter build. Using a
+ // dynamic import helps prevent the issue.
+ // TODO: investigate why
+ const { nodeFileTrace } = await import('@vercel/nft');
+ const result = await nodeFileTrace([entryPath], {
+ base: fileURLToPath(base),
+ cache,
+ });
+
+ for (const error of result.warnings) {
+ if (error.message.startsWith('Failed to resolve dependency')) {
+ const [, module, file] = /Cannot find module '(.+?)' loaded from (.+)/.exec(error.message)!;
+
+ // The import(astroRemark) sometimes fails to resolve, but it's not a problem
+ if (module === '@astrojs/') continue;
+
+ // Sharp is always external and won't be able to be resolved, but that's also not a problem
+ if (module === 'sharp') continue;
+
+ if (entryPath === file) {
+ logger.debug(
+ `[@astrojs/vercel] The module "${module}" couldn't be resolved. This may not be a problem, but it's worth checking.`
+ );
+ } else {
+ logger.debug(
+ `[@astrojs/vercel] The module "${module}" inside the file "${file}" couldn't be resolved. This may not be a problem, but it's worth checking.`
+ );
+ }
+ }
+ // parse errors are likely not js and can safely be ignored,
+ // such as this html file in "main" meant for nw instead of node:
+ // https://github.com/vercel/nft/issues/311
+ else if (error.message.startsWith('Failed to parse')) {
+ continue;
+ } else {
+ throw error;
+ }
+ }
+
+ const commonAncestor = await copyFilesToFolder(
+ [...result.fileList].map((file) => new URL(file, base)).concat(includeFiles),
+ outDir,
+ excludeFiles
+ );
+
+ return {
+ // serverEntry location inside the outDir
+ handler: relativePath(commonAncestor, entryPath),
+ };
+}