Skip to content

Commit d677a01

Browse files
author
Miriad
committed
fix: split remotion.ts to isolate native binary imports from Vercel bundle
Move deploySite/deployFunction/getOrCreateBucket into remotion-deploy.ts (one-time CLI setup). remotion.ts now only imports renderMediaOnLambda + getRenderProgress — no @rspack/binding dependency chain in serverless routes. Also remove @remotion/bundler, @remotion/cli, @rspack/core, @rspack/binding from serverExternalPackages in next.config.ts (no longer needed).
1 parent f39e91f commit d677a01

File tree

3 files changed

+179
-147
lines changed

3 files changed

+179
-147
lines changed

lib/services/remotion-deploy.ts

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/**
2+
* Remotion Lambda deployment service — one-time CLI setup only.
3+
*
4+
* This file imports deploySite, deployFunction, and getOrCreateBucket from
5+
* @remotion/lambda, which pull in @rspack/core → @rspack/binding (a native
6+
* binary). These MUST NOT be imported from Vercel serverless routes.
7+
*
8+
* Run this locally or in CI to set up the Lambda infrastructure, then store
9+
* the resulting REMOTION_SERVE_URL and REMOTION_FUNCTION_NAME as env vars.
10+
*
11+
* @module lib/services/remotion-deploy
12+
*/
13+
14+
import {
15+
deploySite,
16+
deployFunction,
17+
getOrCreateBucket,
18+
type AwsRegion,
19+
} from "@remotion/lambda";
20+
21+
// ---------------------------------------------------------------------------
22+
// Helpers
23+
// ---------------------------------------------------------------------------
24+
25+
function log(message: string, data?: Record<string, unknown>): void {
26+
const ts = new Date().toISOString();
27+
if (data) {
28+
console.log(`[REMOTION] [${ts}] ${message}`, data);
29+
} else {
30+
console.log(`[REMOTION] [${ts}] ${message}`);
31+
}
32+
}
33+
34+
// ---------------------------------------------------------------------------
35+
// Types
36+
// ---------------------------------------------------------------------------
37+
38+
export interface DeployResult {
39+
functionName: string;
40+
serveUrl: string;
41+
siteName: string;
42+
bucketName: string;
43+
region: string;
44+
}
45+
46+
// ---------------------------------------------------------------------------
47+
// Deploy helper (one-time setup)
48+
// ---------------------------------------------------------------------------
49+
50+
/**
51+
* Deploy the Remotion Lambda infrastructure (one-time setup).
52+
*
53+
* This will:
54+
* 1. Create or reuse an S3 bucket for Remotion
55+
* 2. Deploy the Remotion bundle (site) to S3
56+
* 3. Deploy the Lambda function
57+
*
58+
* After running this, set the returned `serveUrl` as REMOTION_SERVE_URL
59+
* and `functionName` as REMOTION_FUNCTION_NAME in your environment.
60+
*
61+
* @param entryPoint - Path to the Remotion entry file (e.g., "remotion/index.ts")
62+
* @returns Deploy result with function name, serve URL, etc.
63+
*/
64+
export async function deployRemotionLambda(
65+
entryPoint: string = "remotion/index.ts"
66+
): Promise<DeployResult> {
67+
const region = (process.env.REMOTION_AWS_REGION || "us-east-1") as AwsRegion;
68+
69+
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
70+
throw new Error(
71+
"[REMOTION] Cannot deploy: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY " +
72+
"must be set in environment variables."
73+
);
74+
}
75+
76+
log("Starting Remotion Lambda deployment", { region, entryPoint });
77+
78+
// Step 1: Get or create the S3 bucket
79+
log("Step 1/3: Getting or creating S3 bucket...");
80+
let bucketName: string;
81+
try {
82+
const bucketResult = await getOrCreateBucket({ region });
83+
bucketName = bucketResult.bucketName;
84+
log(`Bucket ready: ${bucketName}`);
85+
} catch (err: unknown) {
86+
const message = err instanceof Error ? err.message : String(err);
87+
throw new Error(
88+
`[REMOTION] Failed to get or create S3 bucket in ${region}: ${message}. ` +
89+
`Ensure your AWS credentials have S3 permissions.`
90+
);
91+
}
92+
93+
// Step 2: Deploy the site (bundle) to S3
94+
log("Step 2/3: Deploying Remotion bundle to S3...");
95+
let serveUrl: string;
96+
let siteName: string;
97+
try {
98+
const siteResult = await deploySite({
99+
entryPoint,
100+
bucketName,
101+
region,
102+
siteName: "codingcat-video-pipeline",
103+
options: {
104+
onBundleProgress: (progress: number) => {
105+
if (progress % 25 === 0 || progress === 100) {
106+
log(`Bundle progress: ${progress}%`);
107+
}
108+
},
109+
onUploadProgress: (upload) => {
110+
if (upload.totalFiles > 0) {
111+
const pct = Math.round(
112+
(upload.filesUploaded / upload.totalFiles) * 100
113+
);
114+
if (pct % 25 === 0) {
115+
log(
116+
`Upload progress: ${upload.filesUploaded}/${upload.totalFiles} files (${pct}%)`
117+
);
118+
}
119+
}
120+
},
121+
},
122+
});
123+
serveUrl = siteResult.serveUrl;
124+
siteName = siteResult.siteName;
125+
log(`Site deployed: ${serveUrl}`, { siteName });
126+
} catch (err: unknown) {
127+
const message = err instanceof Error ? err.message : String(err);
128+
throw new Error(
129+
`[REMOTION] Failed to deploy site to S3: ${message}. ` +
130+
`Ensure the entry point "${entryPoint}" exists and is a valid Remotion project.`
131+
);
132+
}
133+
134+
// Step 3: Deploy the Lambda function
135+
log("Step 3/3: Deploying Lambda function...");
136+
let functionName: string;
137+
try {
138+
const fnResult = await deployFunction({
139+
region,
140+
timeoutInSeconds: 240,
141+
memorySizeInMb: 2048,
142+
createCloudWatchLogGroup: true,
143+
cloudWatchLogRetentionPeriodInDays: 14,
144+
diskSizeInMb: 2048,
145+
});
146+
functionName = fnResult.functionName;
147+
log(
148+
`Lambda function deployed: ${functionName}` +
149+
(fnResult.alreadyExisted ? " (already existed)" : " (newly created)")
150+
);
151+
} catch (err: unknown) {
152+
const message = err instanceof Error ? err.message : String(err);
153+
throw new Error(
154+
`[REMOTION] Failed to deploy Lambda function: ${message}. ` +
155+
`Ensure your AWS credentials have Lambda and IAM permissions. ` +
156+
`See: https://www.remotion.dev/docs/lambda/permissions`
157+
);
158+
}
159+
160+
log("Deployment complete! Set these environment variables:", {
161+
REMOTION_SERVE_URL: serveUrl,
162+
REMOTION_FUNCTION_NAME: functionName,
163+
REMOTION_AWS_REGION: region,
164+
});
165+
166+
return {
167+
functionName,
168+
serveUrl,
169+
siteName,
170+
bucketName,
171+
region,
172+
};
173+
}

lib/services/remotion.ts

Lines changed: 6 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
/**
2-
* Remotion Lambda rendering service.
2+
* Remotion Lambda rendering service — runtime only.
33
*
4-
* Handles deploying and triggering Remotion Lambda renders for video production.
4+
* Handles triggering and polling Remotion Lambda renders for video production.
55
* Produces both 16:9 (main) and 9:16 (short) video formats.
66
*
7+
* Deploy functions (deploySite, deployFunction, getOrCreateBucket) live in
8+
* `remotion-deploy.ts` to avoid pulling @rspack/binding into Vercel bundles.
9+
*
710
* Requires env vars:
811
* - AWS_ACCESS_KEY_ID
912
* - AWS_SECRET_ACCESS_KEY
1013
* - REMOTION_AWS_REGION
1114
* - REMOTION_SERVE_URL (generated during Lambda deployment)
12-
* - REMOTION_FUNCTION_NAME (optional, from deployRemotionLambda)
15+
* - REMOTION_FUNCTION_NAME (optional, defaults to DEFAULT_FUNCTION_NAME)
1316
*
1417
* @module lib/services/remotion
1518
*/
1619

1720
import {
1821
renderMediaOnLambda,
1922
getRenderProgress,
20-
deploySite,
21-
deployFunction,
22-
getOrCreateBucket,
2323
type AwsRegion,
2424
} from "@remotion/lambda";
2525

@@ -417,140 +417,3 @@ export async function renderBothFormats(
417417

418418
return { main, short };
419419
}
420-
421-
// ---------------------------------------------------------------------------
422-
// Deploy helper (one-time setup)
423-
// ---------------------------------------------------------------------------
424-
425-
export interface DeployResult {
426-
functionName: string;
427-
serveUrl: string;
428-
siteName: string;
429-
bucketName: string;
430-
region: string;
431-
}
432-
433-
/**
434-
* Deploy the Remotion Lambda infrastructure (one-time setup).
435-
*
436-
* This will:
437-
* 1. Create or reuse an S3 bucket for Remotion
438-
* 2. Deploy the Remotion bundle (site) to S3
439-
* 3. Deploy the Lambda function
440-
*
441-
* After running this, set the returned `serveUrl` as REMOTION_SERVE_URL
442-
* and `functionName` as REMOTION_FUNCTION_NAME in your environment.
443-
*
444-
* @param entryPoint - Path to the Remotion entry file (e.g., "remotion/index.ts")
445-
* @returns Deploy result with function name, serve URL, etc.
446-
*/
447-
export async function deployRemotionLambda(
448-
entryPoint: string = "remotion/index.ts"
449-
): Promise<DeployResult> {
450-
const region = (process.env.REMOTION_AWS_REGION || "us-east-1") as AwsRegion;
451-
452-
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
453-
throw new Error(
454-
"[REMOTION] Cannot deploy: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY " +
455-
"must be set in environment variables."
456-
);
457-
}
458-
459-
log("Starting Remotion Lambda deployment", { region, entryPoint });
460-
461-
// Step 1: Get or create the S3 bucket
462-
log("Step 1/3: Getting or creating S3 bucket...");
463-
let bucketName: string;
464-
try {
465-
const bucketResult = await getOrCreateBucket({ region });
466-
bucketName = bucketResult.bucketName;
467-
log(`Bucket ready: ${bucketName}`);
468-
} catch (err: unknown) {
469-
const message = err instanceof Error ? err.message : String(err);
470-
throw new Error(
471-
`[REMOTION] Failed to get or create S3 bucket in ${region}: ${message}. ` +
472-
`Ensure your AWS credentials have S3 permissions.`
473-
);
474-
}
475-
476-
// Step 2: Deploy the site (bundle) to S3
477-
log("Step 2/3: Deploying Remotion bundle to S3...");
478-
let serveUrl: string;
479-
let siteName: string;
480-
try {
481-
const siteResult = await deploySite({
482-
entryPoint,
483-
bucketName,
484-
region,
485-
siteName: "codingcat-video-pipeline",
486-
options: {
487-
onBundleProgress: (progress: number) => {
488-
if (progress % 25 === 0 || progress === 100) {
489-
log(`Bundle progress: ${progress}%`);
490-
}
491-
},
492-
onUploadProgress: (upload) => {
493-
if (upload.totalFiles > 0) {
494-
const pct = Math.round(
495-
(upload.filesUploaded / upload.totalFiles) * 100
496-
);
497-
if (pct % 25 === 0) {
498-
log(
499-
`Upload progress: ${upload.filesUploaded}/${upload.totalFiles} files (${pct}%)`
500-
);
501-
}
502-
}
503-
},
504-
},
505-
});
506-
serveUrl = siteResult.serveUrl;
507-
siteName = siteResult.siteName;
508-
log(`Site deployed: ${serveUrl}`, { siteName });
509-
} catch (err: unknown) {
510-
const message = err instanceof Error ? err.message : String(err);
511-
throw new Error(
512-
`[REMOTION] Failed to deploy site to S3: ${message}. ` +
513-
`Ensure the entry point "${entryPoint}" exists and is a valid Remotion project.`
514-
);
515-
}
516-
517-
// Step 3: Deploy the Lambda function
518-
log("Step 3/3: Deploying Lambda function...");
519-
let functionName: string;
520-
try {
521-
const fnResult = await deployFunction({
522-
region,
523-
timeoutInSeconds: 240,
524-
memorySizeInMb: 2048,
525-
createCloudWatchLogGroup: true,
526-
cloudWatchLogRetentionPeriodInDays: 14,
527-
diskSizeInMb: 2048,
528-
});
529-
functionName = fnResult.functionName;
530-
log(
531-
`Lambda function deployed: ${functionName}` +
532-
(fnResult.alreadyExisted ? " (already existed)" : " (newly created)")
533-
);
534-
} catch (err: unknown) {
535-
const message = err instanceof Error ? err.message : String(err);
536-
throw new Error(
537-
`[REMOTION] Failed to deploy Lambda function: ${message}. ` +
538-
`Ensure your AWS credentials have Lambda and IAM permissions. ` +
539-
`See: https://www.remotion.dev/docs/lambda/permissions`
540-
);
541-
}
542-
543-
log("Deployment complete! Set these environment variables:", {
544-
REMOTION_SERVE_URL: serveUrl,
545-
REMOTION_FUNCTION_NAME: functionName,
546-
REMOTION_AWS_REGION: region,
547-
});
548-
549-
return {
550-
functionName,
551-
serveUrl,
552-
siteName,
553-
bucketName,
554-
region,
555-
};
556-
}

next.config.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ const nextConfig: NextConfig = {
1414
},
1515
serverExternalPackages: [
1616
"@remotion/lambda",
17-
"@remotion/bundler",
18-
"@remotion/cli",
19-
"@rspack/core",
20-
"@rspack/binding",
2117
],
2218
};
2319

0 commit comments

Comments
 (0)