Skip to content

Commit ab5f1f7

Browse files
committed
Merge branch 'main' into vercel-blog-example
2 parents 2d48c79 + e7311df commit ab5f1f7

File tree

11 files changed

+93
-52
lines changed

11 files changed

+93
-52
lines changed

packages/cloudflare/CHANGELOG.md

+18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# @opennextjs/cloudflare
22

3+
## 0.2.0
4+
5+
### Minor Changes
6+
7+
- 6acf0fd: feat: cli arg to disable minification
8+
9+
The cache handler currently forces minification. There is now a CLI arg to disable minification for the build. At the moment, this only applies to the cache handler but may be used for other parts of the build in the future when minification is introduced to them. By default, minification is enabled, but can be disabled by passing `--noMinify`.
10+
11+
## 0.1.1
12+
13+
### Patch Changes
14+
15+
- 66ba0ff: enhancement: Expand missing next.config error message
16+
17+
Found out that next dev can run the a Next.js app without next.config but
18+
if we are using the adapter we throw an error if we don't find the config.
19+
So expanded the error for users.
20+
321
## 0.1.0
422

523
### Minor Changes

packages/cloudflare/TODO.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ DONE:
88
- figure out the assets
99
- copy the template folders
1010

11-
## Open next [example app](https://github.com/sst/open-next/tree/main/example)
11+
## Open next [example app](https://github.com/opennextjs/opennextjs-aws/tree/main/example)
1212

1313
Changes:
1414

packages/cloudflare/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@opennextjs/cloudflare",
33
"description": "Cloudflare builder for next apps",
4-
"version": "0.1.0",
4+
"version": "0.2.0",
55
"scripts": {
66
"build": "tsup",
77
"build:watch": "tsup --watch src",

packages/cloudflare/src/cli/args.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import { parseArgs } from "node:util";
33
import { resolve } from "node:path";
44

55
export function getArgs(): {
6-
skipBuild: boolean;
6+
skipNextBuild: boolean;
77
outputDir?: string;
8+
minify: boolean;
89
} {
910
const {
10-
values: { skipBuild, output },
11+
values: { skipBuild, output, noMinify },
1112
} = parseArgs({
1213
options: {
1314
skipBuild: {
@@ -19,6 +20,10 @@ export function getArgs(): {
1920
type: "string",
2021
short: "o",
2122
},
23+
noMinify: {
24+
type: "boolean",
25+
default: false,
26+
},
2227
},
2328
allowPositionals: false,
2429
});
@@ -31,7 +36,8 @@ export function getArgs(): {
3136

3237
return {
3338
outputDir,
34-
skipBuild: skipBuild || ["1", "true", "yes"].includes(String(process.env.SKIP_NEXT_APP_BUILD)),
39+
skipNextBuild: skipBuild || ["1", "true", "yes"].includes(String(process.env.SKIP_NEXT_APP_BUILD)),
40+
minify: !noMinify,
3541
};
3642
}
3743

packages/cloudflare/src/cli/build/build-next-app.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ export async function buildNextjsApp(nextAppDir: string): Promise<void> {
1818
runNextBuildCommand(pm.name, nextAppDir);
1919
}
2020

21-
// equivalent to: https://github.com/sst/open-next/blob/f61b0e94/packages/open-next/src/build.ts#L175-L186
21+
// equivalent to: https://github.com/opennextjs/opennextjs-aws/blob/f61b0e94/packages/open-next/src/build.ts#L175-L186
2222
function runNextBuildCommand(packager: PackageManager, nextAppDir: string) {
2323
const command = `${packager === "npm" ? "npx" : packager} next build`;
2424
execSync(command, {
2525
stdio: "inherit",
2626
cwd: nextAppDir,
2727
env: {
2828
...process.env,
29-
// equivalent to: https://github.com/sst/open-next/blob/f61b0e9/packages/open-next/src/build.ts#L168-L173
29+
// equivalent to: https://github.com/opennextjs/opennextjs-aws/blob/f61b0e9/packages/open-next/src/build.ts#L168-L173
3030
// Equivalent to setting `output: "standalone"` in next.config.js
3131
NEXT_PRIVATE_STANDALONE: "true",
3232
},

packages/cloudflare/src/cli/build/build-worker.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,16 @@ export async function buildWorker(config: Config): Promise<void> {
3232
// Copy over client-side generated files
3333
await cp(
3434
path.join(config.paths.dotNext, "static"),
35-
path.join(config.paths.builderOutput, "assets", "_next", "static"),
35+
path.join(config.paths.outputDir, "assets", "_next", "static"),
3636
{
3737
recursive: true,
3838
}
3939
);
4040

4141
// Copy over any static files (e.g. images) from the source project
42-
const publicDir = path.join(config.paths.nextApp, "public");
42+
const publicDir = path.join(config.paths.sourceDir, "public");
4343
if (existsSync(publicDir)) {
44-
await cp(publicDir, path.join(config.paths.builderOutput, "assets"), {
44+
await cp(publicDir, path.join(config.paths.outputDir, "assets"), {
4545
recursive: true,
4646
});
4747
}
@@ -52,7 +52,7 @@ export async function buildWorker(config: Config): Promise<void> {
5252
copyPackageCliFiles(packageDistDir, config);
5353

5454
const workerEntrypoint = path.join(config.paths.internalTemplates, "worker.ts");
55-
const workerOutputFile = path.join(config.paths.builderOutput, "index.mjs");
55+
const workerOutputFile = path.join(config.paths.outputDir, "index.mjs");
5656

5757
const nextConfigStr =
5858
readFileSync(path.join(config.paths.standaloneApp, "/server.js"), "utf8")?.match(
+12-19
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,39 @@
11
import { containsDotNextDir, getConfig } from "../config";
2+
import type { ProjectOptions } from "../config";
23
import { buildNextjsApp } from "./build-next-app";
34
import { buildWorker } from "./build-worker";
45
import { cpSync } from "node:fs";
5-
import path from "node:path";
6+
import { join } from "node:path";
67
import { rm } from "node:fs/promises";
78

89
/**
910
* Builds the application in a format that can be passed to workerd
1011
*
1112
* It saves the output in a `.worker-next` directory
1213
*
13-
* @param appDir the directory of the Next.js app to build
14-
* @param opts.outputDir the directory where to save the output (defaults to the app's directory)
15-
* @param opts.skipBuild boolean indicating whether the Next.js build should be skipped (i.e. if the `.next` dir is already built)
14+
* @param projectOpts The options for the project
1615
*/
17-
export async function build(appDir: string, opts: BuildOptions): Promise<void> {
18-
if (!opts.skipBuild) {
16+
export async function build(projectOpts: ProjectOptions): Promise<void> {
17+
if (!projectOpts.skipNextBuild) {
1918
// Build the next app
20-
await buildNextjsApp(appDir);
19+
await buildNextjsApp(projectOpts.sourceDir);
2120
}
2221

23-
if (!containsDotNextDir(appDir)) {
24-
throw new Error(`.next folder not found in ${appDir}`);
22+
if (!containsDotNextDir(projectOpts.sourceDir)) {
23+
throw new Error(`.next folder not found in ${projectOpts.sourceDir}`);
2524
}
2625

27-
// Create a clean output directory
28-
const outputDir = path.resolve(opts.outputDir ?? appDir, ".worker-next");
29-
await cleanDirectory(outputDir);
26+
// Clean the output directory
27+
await cleanDirectory(projectOpts.outputDir);
3028

3129
// Copy the .next directory to the output directory so it can be mutated.
32-
cpSync(path.join(appDir, ".next"), path.join(outputDir, ".next"), { recursive: true });
30+
cpSync(join(projectOpts.sourceDir, ".next"), join(projectOpts.outputDir, ".next"), { recursive: true });
3331

34-
const config = getConfig(appDir, outputDir);
32+
const config = getConfig(projectOpts);
3533

3634
await buildWorker(config);
3735
}
3836

39-
type BuildOptions = {
40-
skipBuild: boolean;
41-
outputDir?: string;
42-
};
43-
4437
async function cleanDirectory(path: string): Promise<void> {
4538
return await rm(path, { recursive: true, force: true });
4639
}

packages/cloudflare/src/cli/build/patches/investigated/patch-cache.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ export async function patchCache(code: string, config: Config): Promise<string>
1818

1919
const cacheHandlerFileName = "cache-handler.mjs";
2020
const cacheHandlerEntrypoint = join(config.paths.internalTemplates, "cache-handler", "index.ts");
21-
const cacheHandlerOutputFile = join(config.paths.builderOutput, cacheHandlerFileName);
21+
const cacheHandlerOutputFile = join(config.paths.outputDir, cacheHandlerFileName);
2222

2323
await build({
2424
entryPoints: [cacheHandlerEntrypoint],
2525
bundle: true,
2626
outfile: cacheHandlerOutputFile,
2727
format: "esm",
2828
target: "esnext",
29-
minify: true,
29+
minify: config.build.shouldMinify,
3030
define: {
3131
"process.env.__OPENNEXT_KV_BINDING_NAME": `"${config.cache.kvBindingName}"`,
3232
},

packages/cloudflare/src/cli/build/utils/copy-prerendered-routes.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function copyPrerenderedRoutes(config: Config) {
1919

2020
const serverAppDirPath = join(config.paths.standaloneAppServer, "app");
2121
const prerenderManifestPath = join(config.paths.standaloneAppDotNext, "prerender-manifest.json");
22-
const outputPath = join(config.paths.builderOutput, "assets", SEED_DATA_DIR);
22+
const outputPath = join(config.paths.outputDir, "assets", SEED_DATA_DIR);
2323

2424
const prerenderManifest: PrerenderManifest = existsSync(prerenderManifestPath)
2525
? JSON.parse(readFileSync(prerenderManifestPath, "utf8"))
@@ -38,7 +38,7 @@ export function copyPrerenderedRoutes(config: Config) {
3838

3939
if (fullPath.endsWith(NEXT_META_SUFFIX)) {
4040
const data = JSON.parse(readFileSync(fullPath, "utf8"));
41-
writeFileSync(destPath, JSON.stringify({ ...data, lastModified: config.buildTimestamp }));
41+
writeFileSync(destPath, JSON.stringify({ ...data, lastModified: config.build.timestamp }));
4242
} else {
4343
copyFileSync(fullPath, destPath);
4444
}

packages/cloudflare/src/cli/config.ts

+32-13
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,20 @@ import { readdirSync, statSync } from "node:fs";
44
const PACKAGE_NAME = "@opennextjs/cloudflare";
55

66
export type Config = {
7-
// Timestamp for when the build was started
8-
buildTimestamp: number;
7+
build: {
8+
// Timestamp for when the build was started
9+
timestamp: number;
10+
// Whether to skip building the Next.js app or not
11+
skipNextBuild: boolean;
12+
// Whether minification should be enabled or not
13+
shouldMinify: boolean;
14+
};
915

1016
paths: {
1117
// Path to the next application
12-
nextApp: string;
18+
sourceDir: string;
1319
// Path to the output folder
14-
builderOutput: string;
20+
outputDir: string;
1521
// Path to the app's `.next` directory (where `next build` saves the build output)
1622
dotNext: string;
1723
// Path to the application standalone root directory
@@ -39,13 +45,11 @@ export type Config = {
3945
/**
4046
* Computes the configuration.
4147
*
42-
* @param appDir Next app root folder
43-
* @param outputDir Output of the cloudflare builder
44-
*
45-
* @returns the configuration, see `Config`
48+
* @param projectOpts The options for the project
49+
* @returns The configuration, see `Config`
4650
*/
47-
export function getConfig(appDir: string, outputDir: string): Config {
48-
const dotNext = path.join(outputDir, ".next");
51+
export function getConfig(projectOpts: ProjectOptions): Config {
52+
const dotNext = path.join(projectOpts.outputDir, ".next");
4953
const appPath = getNextjsApplicationPath(dotNext).replace(/\/$/, "");
5054
const standaloneRoot = path.join(dotNext, "standalone");
5155
const standaloneApp = path.join(standaloneRoot, appPath);
@@ -59,11 +63,15 @@ export function getConfig(appDir: string, outputDir: string): Config {
5963
process.env.__OPENNEXT_KV_BINDING_NAME ??= "NEXT_CACHE_WORKERS_KV";
6064

6165
return {
62-
buildTimestamp: Date.now(),
66+
build: {
67+
timestamp: Date.now(),
68+
skipNextBuild: projectOpts.skipNextBuild,
69+
shouldMinify: projectOpts.minify,
70+
},
6371

6472
paths: {
65-
nextApp: appDir,
66-
builderOutput: outputDir,
73+
sourceDir: projectOpts.sourceDir,
74+
outputDir: projectOpts.outputDir,
6775
dotNext,
6876
standaloneRoot,
6977
standaloneApp,
@@ -89,6 +97,17 @@ export function containsDotNextDir(folder: string): boolean {
8997
}
9098
}
9199

100+
export type ProjectOptions = {
101+
// Next app root folder
102+
sourceDir: string;
103+
// The directory to save the output to (defaults to the app's directory)
104+
outputDir: string;
105+
// Whether the Next.js build should be skipped (i.e. if the `.next` dir is already built)
106+
skipNextBuild: boolean;
107+
// Whether minification of the worker should be enabled
108+
minify: boolean;
109+
};
110+
92111
/**
93112
* It basically tries to find the path that the application is under inside the `.next/standalone` directory, using the `.next/server` directory
94113
* presence as the condition that needs to be met.

packages/cloudflare/src/cli/index.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ console.log(`Building the Next.js app in the current folder (${nextAppDir})`);
1010

1111
if (!["js", "cjs", "mjs", "ts"].some((ext) => existsSync(`./next.config.${ext}`))) {
1212
// TODO: we can add more validation later
13-
throw new Error("Error: Not in a Next.js app project");
13+
console.error(
14+
"Error: next.config file not found. Please make sure you run the command inside a Next.js app"
15+
);
16+
process.exit(1);
1417
}
1518

16-
const { skipBuild, outputDir } = getArgs();
19+
const { skipNextBuild, outputDir, minify } = getArgs();
1720

18-
await build(nextAppDir, {
19-
outputDir,
20-
skipBuild: !!skipBuild,
21+
await build({
22+
sourceDir: nextAppDir,
23+
outputDir: resolve(outputDir ?? nextAppDir, ".worker-next"),
24+
skipNextBuild,
25+
minify,
2126
});

0 commit comments

Comments
 (0)