Feat: add maxDuration setting for API/Trigger route in the CLI Init Command for Next.js (#617)
* add cli init maxDuration to the api/trigger route for nextjs * refactor createTriggerRoute * move boxen log to createTriggerRoute function * refine detectNextVersion and versionNumberPattern regex to match the latest nextjs version * add tests for the detectNextVersion function * add changeset file * If the regex doesn't match, it returns null instead of throwing * Tweaked message about the max duration --------- Co-authored-by: Matt Aitken <matt@mattaitken.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Added Next.js `maxDuration` commented out to the api/trigger file using CLI init
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "fs/promises";
|
||||
import pathModule from "path";
|
||||
import boxen from "boxen";
|
||||
import { Framework } from "..";
|
||||
import { templatesPath } from "../../paths";
|
||||
import { InstallPackage } from "../../utils/addDependencies";
|
||||
@@ -50,17 +51,46 @@ export class NextJs implements Framework {
|
||||
}
|
||||
|
||||
const nextJsDir = await detectPagesOrAppDir(path);
|
||||
const nextJsVersion = await detectNextVersion(path);
|
||||
const routeDir = pathModule.join(path, usesSrcDir ? "src" : "");
|
||||
const pathAlias = await getPathAlias({
|
||||
projectPath: path,
|
||||
isTypescriptProject: options.typescript,
|
||||
extraDirectories: usesSrcDir ? ["src"] : undefined,
|
||||
});
|
||||
const fileExtension = options.typescript ? ".ts" : ".js";
|
||||
|
||||
if (nextJsDir === "pages") {
|
||||
await createTriggerPageRoute(routeDir, options.endpointSlug, options.typescript, pathAlias);
|
||||
const apiRoutePath = pathModule.join(routeDir, "pages", "api", `trigger${fileExtension}`);
|
||||
if (nextJsVersion && nextJsVersion !== 'latest' && nextJsVersion < "13.5") {
|
||||
await createTriggerRoute({
|
||||
path: routeDir,
|
||||
apiRoutePath,
|
||||
template: "pagesApiRoute.js",
|
||||
fileExtension,
|
||||
endpointSlug: options.endpointSlug,
|
||||
pathAlias
|
||||
});
|
||||
} else {
|
||||
await createTriggerRoute({
|
||||
path: routeDir,
|
||||
apiRoutePath,
|
||||
template: "pagesApiRouteWithConfigObject.js",
|
||||
fileExtension,
|
||||
endpointSlug: options.endpointSlug,
|
||||
pathAlias
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await createTriggerAppRoute(routeDir, options.endpointSlug, options.typescript, pathAlias);
|
||||
const apiRoutePath = pathModule.join(routeDir, "app", "api", "trigger", `route${fileExtension}`);
|
||||
await createTriggerRoute({
|
||||
path: routeDir,
|
||||
apiRoutePath,
|
||||
template: "appApiRoute.js",
|
||||
fileExtension,
|
||||
endpointSlug: options.endpointSlug,
|
||||
pathAlias
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,45 +174,34 @@ export async function detectPagesOrAppDir(path: string): Promise<"pages" | "app"
|
||||
return "pages";
|
||||
}
|
||||
|
||||
async function createTriggerPageRoute(
|
||||
path: string,
|
||||
endpointSlug: string,
|
||||
isTypescriptProject: boolean,
|
||||
pathAlias: string | undefined
|
||||
) {
|
||||
const templatesDir = pathModule.join(templatesPath(), "nextjs");
|
||||
const fileExtension = isTypescriptProject ? ".ts" : ".js";
|
||||
|
||||
//pages/api/trigger.js or src/pages/api/trigger.js
|
||||
const apiRoutePath = pathModule.join(path, "pages", "api", `trigger${fileExtension}`);
|
||||
const apiRouteResult = await createFileFromTemplate({
|
||||
templatePath: pathModule.join(templatesDir, "pagesApiRoute.js"),
|
||||
replacements: {
|
||||
routePathPrefix: pathAlias ? pathAlias + "/" : "../../",
|
||||
},
|
||||
outputPath: apiRoutePath,
|
||||
});
|
||||
if (!apiRouteResult.success) {
|
||||
throw new Error("Failed to create API route file");
|
||||
export async function detectNextVersion(path: string) {
|
||||
const packageJsonContent = await readPackageJson(path);
|
||||
if (!packageJsonContent) {
|
||||
return null;
|
||||
}
|
||||
logger.success(`✔ Created API route at ${apiRoutePath}`);
|
||||
|
||||
await createJobsAndTriggerFile(path, endpointSlug, fileExtension, pathAlias, templatesDir);
|
||||
const versionNumberPattern = /[\d.]+|latest/;
|
||||
if (packageJsonContent.dependencies?.next !== undefined)
|
||||
return packageJsonContent.dependencies?.next?.match(versionNumberPattern)?.at(0) ?? null;
|
||||
if (packageJsonContent.devDependencies?.next !== undefined)
|
||||
return packageJsonContent.devDependencies?.next?.match(versionNumberPattern)?.at(0) ?? null;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async function createTriggerAppRoute(
|
||||
async function createTriggerRoute(options: {
|
||||
path: string,
|
||||
apiRoutePath: string,
|
||||
template: string,
|
||||
fileExtension: string,
|
||||
endpointSlug: string,
|
||||
isTypescriptProject: boolean,
|
||||
pathAlias: string | undefined
|
||||
) {
|
||||
const templatesDir = pathModule.join(templatesPath(), "nextjs");
|
||||
const fileExtension = isTypescriptProject ? ".ts" : ".js";
|
||||
}) {
|
||||
const { path, apiRoutePath, template, pathAlias, endpointSlug, fileExtension } = options;
|
||||
|
||||
//app/api/trigger/route.js or src/app/api/trigger/route.js
|
||||
const apiRoutePath = pathModule.join(path, "app", "api", "trigger", `route${fileExtension}`);
|
||||
const templatesDir = pathModule.join(templatesPath(), "nextjs");
|
||||
const apiRouteResult = await createFileFromTemplate({
|
||||
templatePath: pathModule.join(templatesDir, "appApiRoute.js"),
|
||||
templatePath: pathModule.join(templatesDir, template),
|
||||
replacements: {
|
||||
routePathPrefix: pathAlias ? pathAlias + "/" : "../../",
|
||||
},
|
||||
@@ -192,6 +211,14 @@ async function createTriggerAppRoute(
|
||||
throw new Error("Failed to create API route file");
|
||||
}
|
||||
logger.success(`✔ Created API route at ${apiRoutePath}`);
|
||||
logger.info(
|
||||
boxen(`If you're deploying to Vercel, configure your max duration in ${apiRoutePath}`, {
|
||||
padding: 1,
|
||||
margin: 1,
|
||||
borderStyle: "double",
|
||||
borderColor: "magenta",
|
||||
})
|
||||
);
|
||||
|
||||
await createJobsAndTriggerFile(path, endpointSlug, fileExtension, pathAlias, templatesDir);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import mock from "mock-fs";
|
||||
import { NextJs, detectPagesOrAppDir, detectUseOfSrcDir } from ".";
|
||||
import { NextJs, detectPagesOrAppDir, detectUseOfSrcDir, detectNextVersion } from ".";
|
||||
import { getFramework } from "..";
|
||||
import { pathExists } from "../../utils/fileSystem";
|
||||
import { detectMiddlewareUsage } from "./middleware";
|
||||
@@ -57,6 +57,35 @@ describe("Next project detection", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Next version detection", () => {
|
||||
test("detect Nextjs latest version", async () => {
|
||||
mock({
|
||||
"package.json": JSON.stringify({ dependencies: { next: "latest" } }),
|
||||
});
|
||||
|
||||
const nextJsVersion = await detectNextVersion("");
|
||||
expect(nextJsVersion).toEqual("latest");
|
||||
});
|
||||
|
||||
test("detect Nextjs 13.0.0 version", async () => {
|
||||
mock({
|
||||
"package.json": JSON.stringify({ dependencies: { next: "13.0.0" } }),
|
||||
});
|
||||
|
||||
const nextJsVersion = await detectNextVersion("");
|
||||
expect(nextJsVersion).toEqual("13.0.0");
|
||||
});
|
||||
|
||||
test("detect Nextjs version as a dev dependency", async () => {
|
||||
mock({
|
||||
"package.json": JSON.stringify({ devDependencies: { next: "^12.0.0" } }),
|
||||
});
|
||||
|
||||
const nextJsVersion = await detectNextVersion("");
|
||||
expect(nextJsVersion).toEqual("12.0.0");
|
||||
});
|
||||
});
|
||||
|
||||
describe("src directory", () => {
|
||||
test("has src directory", async () => {
|
||||
mock({
|
||||
|
||||
@@ -5,3 +5,6 @@ import "${routePathPrefix}jobs";
|
||||
|
||||
//this route is used to send and receive data with Trigger.dev
|
||||
export const { POST, dynamic } = createAppRoute(client);
|
||||
|
||||
//uncomment this to set a higher max duration (it must be inside your plan limits). Full docs: https://vercel.com/docs/functions/serverless-functions/runtimes#max-duration
|
||||
//export const maxDuration = 60;
|
||||
@@ -0,0 +1,15 @@
|
||||
import { createPagesRoute } from "@trigger.dev/nextjs";
|
||||
import { client } from "${routePathPrefix}trigger";
|
||||
|
||||
import "${routePathPrefix}jobs";
|
||||
|
||||
//uncomment this to set a higher max duration (it must be inside your plan limits). Full docs: https://vercel.com/docs/functions/serverless-functions/runtimes#max-duration
|
||||
//export const config = {
|
||||
// maxDuration: 60,
|
||||
//};
|
||||
|
||||
//this route is used to send and receive data with Trigger.dev
|
||||
const { handler, config } = createPagesRoute(client);
|
||||
export { config };
|
||||
|
||||
export default handler;
|
||||
Reference in New Issue
Block a user