diff options
Diffstat (limited to 'packages/integrations/vercel/src/lib')
-rw-r--r-- | packages/integrations/vercel/src/lib/fs.ts | 57 | ||||
-rw-r--r-- | packages/integrations/vercel/src/lib/nft.ts | 69 |
2 files changed, 77 insertions, 49 deletions
diff --git a/packages/integrations/vercel/src/lib/fs.ts b/packages/integrations/vercel/src/lib/fs.ts index 64c4c69ba..47b218ce5 100644 --- a/packages/integrations/vercel/src/lib/fs.ts +++ b/packages/integrations/vercel/src/lib/fs.ts @@ -1,5 +1,7 @@ import type { PathLike } from 'node:fs'; import * as fs from 'node:fs/promises'; +import nodePath from 'node:path'; +import { fileURLToPath } from 'node:url'; export async function writeJson<T>(path: PathLike, data: T) { await fs.writeFile(path, JSON.stringify(data), { encoding: 'utf-8' }); @@ -15,3 +17,58 @@ export async function emptyDir(dir: PathLike): Promise<void> { } export const getVercelOutput = (root: URL) => new URL('./.vercel/output/', root); + +/** + * Copies files into a folder keeping the folder structure intact. + * The resulting file tree will start at the common ancestor. + * + * @param {URL[]} files A list of files to copy (absolute path). + * @param {URL} outDir Destination folder where to copy the files to (absolute path). + * @param {URL[]} [exclude] A list of files to exclude (absolute path). + * @returns {Promise<string>} The common ancestor of the copied files. + */ +export async function copyFilesToFunction( + files: URL[], + outDir: URL, + exclude: URL[] = [] +): Promise<string> { + const excludeList = exclude.map(fileURLToPath); + const fileList = files.map(fileURLToPath).filter((f) => !excludeList.includes(f)); + + if (files.length === 0) throw new Error('[@astrojs/vercel] No files found to copy'); + + let commonAncestor = nodePath.dirname(fileList[0]); + for (const file of fileList.slice(1)) { + while (!file.startsWith(commonAncestor)) { + commonAncestor = nodePath.dirname(commonAncestor); + } + } + + for (const origin of fileList) { + const dest = new URL(nodePath.relative(commonAncestor, origin), outDir); + + const realpath = await fs.realpath(origin); + const isSymlink = realpath !== origin; + const isDir = (await fs.stat(origin)).isDirectory(); + + // Create directories recursively + if (isDir && !isSymlink) { + await fs.mkdir(new URL('..', dest), { recursive: true }); + } else { + await fs.mkdir(new URL('.', dest), { recursive: true }); + } + + if (isSymlink) { + const realdest = fileURLToPath(new URL(nodePath.relative(commonAncestor, realpath), outDir)); + await fs.symlink( + nodePath.relative(fileURLToPath(new URL('.', dest)), realdest), + dest, + isDir ? 'dir' : 'file' + ); + } else if (!isDir) { + await fs.copyFile(origin, dest); + } + } + + return commonAncestor; +} diff --git a/packages/integrations/vercel/src/lib/nft.ts b/packages/integrations/vercel/src/lib/nft.ts index ba3677583..6a9ac116e 100644 --- a/packages/integrations/vercel/src/lib/nft.ts +++ b/packages/integrations/vercel/src/lib/nft.ts @@ -1,12 +1,20 @@ import { nodeFileTrace } from '@vercel/nft'; -import * as fs from 'node:fs/promises'; -import nodePath from 'node:path'; +import { relative as relativePath } from 'node:path'; import { fileURLToPath } from 'node:url'; -export async function copyDependenciesToFunction( - entry: URL, - outDir: URL -): Promise<{ handler: string }> { +import { copyFilesToFunction } from './fs.js'; + +export async function copyDependenciesToFunction({ + entry, + outDir, + includeFiles, + excludeFiles, +}: { + entry: URL; + outDir: URL; + includeFiles: URL[]; + excludeFiles: URL[]; +}): Promise<{ handler: string }> { const entryPath = fileURLToPath(entry); // Get root of folder of the system (like C:\ on Windows or / on Linux) @@ -19,8 +27,6 @@ export async function copyDependenciesToFunction( base: fileURLToPath(base), }); - if (result.fileList.size === 0) throw new Error('[@astrojs/vercel] No files found'); - 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)!; @@ -42,49 +48,14 @@ export async function copyDependenciesToFunction( } } - const fileList = [...result.fileList]; - - let commonAncestor = nodePath.dirname(fileList[0]); - for (const file of fileList.slice(1)) { - while (!file.startsWith(commonAncestor)) { - commonAncestor = nodePath.dirname(commonAncestor); - } - } - - for (const file of fileList) { - const origin = new URL(file, base); - const dest = new URL(nodePath.relative(commonAncestor, file), outDir); - - const realpath = await fs.realpath(origin); - const isSymlink = realpath !== fileURLToPath(origin); - const isDir = (await fs.stat(origin)).isDirectory(); - - // Create directories recursively - if (isDir && !isSymlink) { - await fs.mkdir(new URL('..', dest), { recursive: true }); - } else { - await fs.mkdir(new URL('.', dest), { recursive: true }); - } - - if (isSymlink) { - const realdest = fileURLToPath( - new URL( - nodePath.relative(nodePath.join(fileURLToPath(base), commonAncestor), realpath), - outDir - ) - ); - await fs.symlink( - nodePath.relative(fileURLToPath(new URL('.', dest)), realdest), - dest, - isDir ? 'dir' : 'file' - ); - } else if (!isDir) { - await fs.copyFile(origin, dest); - } - } + const commonAncestor = await copyFilesToFunction( + [...result.fileList].map((file) => new URL(file, base)).concat(includeFiles), + outDir, + excludeFiles + ); return { // serverEntry location inside the outDir - handler: nodePath.relative(nodePath.join(fileURLToPath(base), commonAncestor), entryPath), + handler: relativePath(commonAncestor, entryPath), }; } |