summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/proud-forks-rescue.md6
-rw-r--r--packages/integrations/vercel/src/lib/fs.ts13
-rw-r--r--packages/integrations/vercel/src/lib/nft.ts32
-rw-r--r--packages/integrations/vercel/src/serverless/adapter.ts40
4 files changed, 64 insertions, 27 deletions
diff --git a/.changeset/proud-forks-rescue.md b/.changeset/proud-forks-rescue.md
new file mode 100644
index 000000000..e968a699f
--- /dev/null
+++ b/.changeset/proud-forks-rescue.md
@@ -0,0 +1,6 @@
+---
+'@astrojs/vercel': patch
+---
+
+- Cache result during bundling, to speed up the process of multiple functions;
+- Avoid creating multiple symbolic links of the dependencies when building the project with `funcitonPerRoute` enabled;
diff --git a/packages/integrations/vercel/src/lib/fs.ts b/packages/integrations/vercel/src/lib/fs.ts
index 51b12d52f..3ef9adadb 100644
--- a/packages/integrations/vercel/src/lib/fs.ts
+++ b/packages/integrations/vercel/src/lib/fs.ts
@@ -1,5 +1,6 @@
import type { PathLike } from 'node:fs';
import * as fs from 'node:fs/promises';
+import { existsSync } from 'node:fs';
import nodePath from 'node:path';
import { fileURLToPath } from 'node:url';
@@ -74,11 +75,13 @@ export async function copyFilesToFunction(
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'
- );
+ const target = nodePath.relative(fileURLToPath(new URL('.', dest)), realdest);
+ // NOTE: when building function per route, dependencies are linked at the first run, then there's no need anymore to do that once more.
+ // So we check if the destination already exists. If it does, move on.
+ // Symbolic links here are usually dependencies and not user code. Symbolic links exist because of the pnpm strategy.
+ if (!existsSync(dest)) {
+ await fs.symlink(target, dest, isDir ? 'dir' : 'file');
+ }
} else if (!isDir) {
await fs.copyFile(origin, dest);
}
diff --git a/packages/integrations/vercel/src/lib/nft.ts b/packages/integrations/vercel/src/lib/nft.ts
index 10c298a1d..95c06f07c 100644
--- a/packages/integrations/vercel/src/lib/nft.ts
+++ b/packages/integrations/vercel/src/lib/nft.ts
@@ -1,19 +1,28 @@
import { relative as relativePath } from 'node:path';
import { fileURLToPath } from 'node:url';
+import { relative } from 'node:path';
import { copyFilesToFunction } from './fs.js';
+import type { AstroIntegrationLogger } from 'astro';
-export async function copyDependenciesToFunction({
- entry,
- outDir,
- includeFiles,
- excludeFiles,
-}: {
- entry: URL;
- outDir: URL;
- includeFiles: URL[];
- excludeFiles: URL[];
-}): Promise<{ handler: string }> {
+export async function copyDependenciesToFunction(
+ {
+ entry,
+ outDir,
+ includeFiles,
+ excludeFiles,
+ logger,
+ }: {
+ entry: URL;
+ outDir: URL;
+ includeFiles: URL[];
+ excludeFiles: URL[];
+ logger: AstroIntegrationLogger;
+ },
+ // 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 ${relative(fileURLToPath(outDir), entryPath)}`);
// Get root of folder of the system (like C:\ on Windows or / on Linux)
let base = entry;
@@ -31,6 +40,7 @@ export async function copyDependenciesToFunction({
// If you have a route of /dev this appears in source and NFT will try to
// scan your local /dev :8
ignore: ['/dev/**'],
+ cache,
});
for (const error of result.warnings) {
diff --git a/packages/integrations/vercel/src/serverless/adapter.ts b/packages/integrations/vercel/src/serverless/adapter.ts
index 90d40a52d..24db23f80 100644
--- a/packages/integrations/vercel/src/serverless/adapter.ts
+++ b/packages/integrations/vercel/src/serverless/adapter.ts
@@ -1,4 +1,10 @@
-import type { AstroAdapter, AstroConfig, AstroIntegration, RouteData } from 'astro';
+import type {
+ AstroAdapter,
+ AstroConfig,
+ AstroIntegration,
+ RouteData,
+ AstroIntegrationLogger,
+} from 'astro';
import { AstroError } from 'astro/errors';
import glob from 'fast-glob';
import { basename } from 'node:path';
@@ -78,16 +84,27 @@ export default function vercelServerless({
// Extra files to be merged with `includeFiles` during build
const extraFilesToInclude: URL[] = [];
- async function createFunctionFolder(funcName: string, entry: URL, inc: URL[]) {
+ const NTF_CACHE = Object.create(null);
+
+ async function createFunctionFolder(
+ funcName: string,
+ entry: URL,
+ inc: URL[],
+ logger: AstroIntegrationLogger
+ ) {
const functionFolder = new URL(`./functions/${funcName}.func/`, _config.outDir);
// Copy necessary files (e.g. node_modules/)
- const { handler } = await copyDependenciesToFunction({
- entry,
- outDir: functionFolder,
- includeFiles: inc,
- excludeFiles: excludeFiles?.map((file) => new URL(file, _config.root)) || [],
- });
+ const { handler } = await copyDependenciesToFunction(
+ {
+ entry,
+ outDir: functionFolder,
+ includeFiles: inc,
+ excludeFiles: excludeFiles?.map((file) => new URL(file, _config.root)) || [],
+ logger,
+ },
+ NTF_CACHE
+ );
// Enable ESM
// https://aws.amazon.com/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda/
@@ -167,7 +184,7 @@ You can set functionPerRoute: false to prevent surpassing the limit.`
}
},
- 'astro:build:done': async ({ routes }) => {
+ 'astro:build:done': async ({ routes, logger }) => {
// Merge any includes from `vite.assetsInclude
if (_config.vite.assetsInclude) {
const mergeGlobbedIncludes = (globPattern: unknown) => {
@@ -192,7 +209,7 @@ You can set functionPerRoute: false to prevent surpassing the limit.`
if (_entryPoints.size) {
for (const [route, entryFile] of _entryPoints) {
const func = basename(entryFile.toString()).replace(/\.mjs$/, '');
- await createFunctionFolder(func, entryFile, filesToInclude);
+ await createFunctionFolder(func, entryFile, filesToInclude, logger);
routeDefinitions.push({
src: route.pattern.source,
dest: func,
@@ -202,7 +219,8 @@ You can set functionPerRoute: false to prevent surpassing the limit.`
await createFunctionFolder(
'render',
new URL(serverEntry, buildTempFolder),
- filesToInclude
+ filesToInclude,
+ logger
);
routeDefinitions.push({ src: '/.*', dest: 'render' });
}