Skip to content

Commit

Permalink
Use @vercel/nft to create lambdas (#4969)
Browse files Browse the repository at this point in the history
* revert to using cjs for lambda

* use nodeFileTrace to build lambda

* lint

* fix unrelated lint error

* update changesets

* update turbo config

* add some logging to try and figure out build failures

* Revert "add some logging to try and figure out build failures"

This reverts commit 6f699e6.

* bump turbo

* fix some tangentially-related typescript stuff
  • Loading branch information
Rich-Harris authored May 24, 2022
1 parent e675f64 commit 60370cc
Show file tree
Hide file tree
Showing 9 changed files with 382 additions and 116 deletions.
5 changes: 5 additions & 0 deletions .changeset/lovely-seahorses-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/adapter-vercel': patch
---

Use @vercel/nft to include dependencies in lambda without bundling with esbuild, when using v3 build output API
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
{
"files": [
"**/CHANGELOG.md",
"**/.svelte-kit/**",
"packages/kit/src/packaging/test/fixtures/**/expected/**/*",
"packages/kit/src/packaging/test/watch/expected/**/*",
"packages/kit/src/packaging/test/watch/package/**/*",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"svelte-preprocess": "^4.9.8",
"svelte2tsx": "~0.5.0",
"tiny-glob": "^0.2.9",
"turbo": "^1.2.6",
"turbo": "^1.2.12",
"typescript": "~4.7.2",
"uvu": "^0.5.2"
},
Expand Down
123 changes: 90 additions & 33 deletions packages/adapter-vercel/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mkdirSync, writeFileSync } from 'fs';
import { dirname, posix } from 'path';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { nodeFileTrace } from '@vercel/nft';
import esbuild from 'esbuild';

// rules for clean URLs and trailing slash handling,
Expand Down Expand Up @@ -80,6 +81,8 @@ const redirects = {
]
};

const files = fileURLToPath(new URL('./files', import.meta.url).href);

/** @type {import('.')} **/
export default function ({ external = [], edge, split } = {}) {
return {
Expand Down Expand Up @@ -113,16 +116,14 @@ async function v1(builder, external) {
builder.rimraf(dir);
builder.rimraf(tmp);

const files = fileURLToPath(new URL('./files', import.meta.url).href);

const dirs = {
static: `${dir}/static`,
lambda: `${dir}/functions/node/render`
};

builder.log.minor('Generating serverless function...');

const relativePath = posix.relative(tmp, builder.getServerDirectory());
const relativePath = path.posix.relative(tmp, builder.getServerDirectory());

builder.copy(`${files}/serverless.js`, `${tmp}/serverless.js`, {
replace: {
Expand All @@ -131,7 +132,7 @@ async function v1(builder, external) {
}
});

writeFileSync(
fs.writeFileSync(
`${tmp}/manifest.js`,
`export const manifest = ${builder.generateManifest({
relativePath
Expand All @@ -148,7 +149,7 @@ async function v1(builder, external) {
format: 'cjs'
});

writeFileSync(`${dirs.lambda}/package.json`, JSON.stringify({ type: 'commonjs' }));
fs.writeFileSync(`${dirs.lambda}/package.json`, JSON.stringify({ type: 'commonjs' }));

builder.log.minor('Copying assets...');

Expand All @@ -173,7 +174,7 @@ async function v1(builder, external) {
status: redirect.status
}));

writeFileSync(
fs.writeFileSync(
`${dir}/config/routes.json`,
JSON.stringify([
...redirects[builder.config.kit.trailingSlash],
Expand Down Expand Up @@ -250,10 +251,9 @@ async function v3(builder, external, edge, split) {
* @param {(options: { relativePath: string }) => string} generate_manifest
*/
async function generate_serverless_function(name, pattern, generate_manifest) {
const tmp = builder.getBuildDirectory(`vercel-tmp/${name}`);
const relativePath = posix.relative(tmp, builder.getServerDirectory());
const relativePath = path.posix.relative(tmp, builder.getServerDirectory());

builder.copy(`${files}/serverless.js`, `${tmp}/serverless.js`, {
builder.copy(`${files}/serverless.js`, `${tmp}/index.js`, {
replace: {
SERVER: `${relativePath}/index.js`,
MANIFEST: './manifest.js'
Expand All @@ -265,27 +265,12 @@ async function v3(builder, external, edge, split) {
`export const manifest = ${generate_manifest({ relativePath })};\n`
);

await esbuild.build({
entryPoints: [`${tmp}/serverless.js`],
outfile: `${dirs.functions}/${name}.func/index.js`,
target: `node${node_version.full}`,
bundle: true,
platform: 'node',
format: 'cjs',
external
});

write(
`${dirs.functions}/${name}.func/.vc-config.json`,
JSON.stringify({
runtime: `nodejs${node_version.major}.x`,
handler: 'index.js',
launcherType: 'Nodejs'
})
await create_function_bundle(
`${tmp}/index.js`,
`${dirs.functions}/${name}.func`,
`nodejs${node_version.major}.x`
);

write(`${dirs.functions}/${name}.func/package.json`, JSON.stringify({ type: 'commonjs' }));

routes.push({ src: pattern, dest: `/${name}` });
}

Expand All @@ -296,7 +281,7 @@ async function v3(builder, external, edge, split) {
*/
async function generate_edge_function(name, pattern, generate_manifest) {
const tmp = builder.getBuildDirectory(`vercel-tmp/${name}`);
const relativePath = posix.relative(tmp, builder.getServerDirectory());
const relativePath = path.posix.relative(tmp, builder.getServerDirectory());

builder.copy(`${files}/edge.js`, `${tmp}/edge.js`, {
replace: {
Expand Down Expand Up @@ -392,12 +377,12 @@ async function v3(builder, external, edge, split) {
*/
function write(file, data) {
try {
mkdirSync(dirname(file), { recursive: true });
fs.mkdirSync(path.dirname(file), { recursive: true });
} catch {
// do nothing
}

writeFileSync(file, data);
fs.writeFileSync(file, data);
}

function get_node_version() {
Expand All @@ -412,3 +397,75 @@ function get_node_version() {

return { major, full };
}

/**
* @param {string} entry
* @param {string} dir
* @param {string} runtime
*/
async function create_function_bundle(entry, dir, runtime) {
let base = entry;
while (base !== (base = path.dirname(base)));

const traced = await nodeFileTrace([entry], { base });

traced.warnings.forEach((error) => {
// pending https://github.com/vercel/nft/issues/284
if (error.message.startsWith('Failed to resolve dependency node:')) return;
console.error(error);
});

// find common ancestor directory
let common_parts;

for (const file of traced.fileList) {
if (common_parts) {
const parts = file.split(path.sep);

for (let i = 0; i < common_parts.length; i += 1) {
if (parts[i] !== common_parts[i]) {
common_parts = common_parts.slice(0, i);
break;
}
}
} else {
common_parts = path.dirname(file).split(path.sep);
}
}

const ancestor = base + common_parts.join(path.sep);

for (const file of traced.fileList) {
const source = base + file;
const dest = path.join(dir, path.relative(ancestor, source));

const stats = fs.statSync(source);
const is_dir = stats.isDirectory();

const realpath = fs.realpathSync(source);

try {
fs.mkdirSync(path.dirname(dest), { recursive: true });
} catch {
// do nothing
}

if (source !== realpath) {
const realdest = path.join(dir, path.relative(ancestor, realpath));
fs.symlinkSync(path.relative(path.dirname(dest), realdest), dest, is_dir ? 'dir' : 'file');
} else if (!is_dir) {
fs.copyFileSync(source, dest);
}
}

write(
`${dir}/.vc-config.json`,
JSON.stringify({
runtime,
handler: path.relative(base + ancestor, entry),
launcherType: 'Nodejs'
})
);

write(`${dir}/package.json`, JSON.stringify({ type: 'module' }));
}
1 change: 1 addition & 0 deletions packages/adapter-vercel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"check": "tsc"
},
"dependencies": {
"@vercel/nft": "^0.18.2",
"esbuild": "^0.14.29"
},
"devDependencies": {
Expand Down
3 changes: 2 additions & 1 deletion packages/adapter-vercel/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
"checkJs": true,
"noEmit": true,
"noImplicitAny": true,
"module": "es2020",
"module": "es2022",
"moduleResolution": "node",
"target": "es2022",
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"paths": {
Expand Down
1 change: 1 addition & 0 deletions packages/kit/test/apps/amp/src/app.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="@sveltejs/kit" />
Loading

0 comments on commit 60370cc

Please sign in to comment.