diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..64233aef0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2020 Cloudflare, Inc. + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/TODO.md b/TODO.md index 1e96a5f06..5fcdc2b53 100644 --- a/TODO.md +++ b/TODO.md @@ -14,6 +14,7 @@ DONE: ## Install - `npx create-next-app@latest --use-npm` (use npm to avoid symlinks) + - update next.config.mjs as follows ```typescript diff --git a/builder/README.md b/builder/README.md new file mode 100644 index 000000000..44edd76c0 --- /dev/null +++ b/builder/README.md @@ -0,0 +1,46 @@ +# Next.js builder for Cloudflare + +## Build your app + +- update the `next.config.mjs` as follows + + ```typescript + /** @type {import('next').NextConfig} */ + const nextConfig = { + output: "standalone", + experimental: { + serverMinification: false, + }, + }; + + export default nextConfig; + ``` + +- add the following `devDependency` to the `package.json`: + + ```json + "node-url": "npm:url@^0.11.4", + "wrangler": "^3.77.0" + ``` + +- Execute `npx @flarelabs-net/builder@latest` in your app folder + +## Serve your app + +- add a `wrangler.toml` at the root of your project + + ```toml + #:schema node_modules/wrangler/config-schema.json + name = "" + main = ".worker-next/index.mjs" + + compatibility_date = "2024-08-29" + compatibility_flags = ["nodejs_compat_v2"] + workers_dev = true + minify = false + + # Use the new Workers + Assets to host the static frontend files + experimental_assets = { directory = ".worker-next/assets", binding = "ASSETS" } + ``` + +- Use `wrangler dev` diff --git a/builder/package.json b/builder/package.json index 60d37121e..a8fe26e6c 100644 --- a/builder/package.json +++ b/builder/package.json @@ -1,13 +1,31 @@ { - "name": "builder", + "name": "@flarelabs-net/builder", + "description": "Cloudflare builder for next apps", + "version": "0.0.1", "scripts": { "build": "tsup", "build:watch": "tsup --watch src" }, "bin": "dist/index.mjs", "files": [ + "README.md", "dist" ], + "repository": { + "type": "git", + "url": "https://github.com/flarelabs-net/poc-next.git", + "directory": "builder" + }, + "keywords": [ + "cloudflare", + "workers", + "next.js" + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/flarelabs-net/poc-next/issues" + }, + "homepage": "https://github.com/flarelabs-net/poc-next", "devDependencies": { "@types/node": "^22.2.0", "esbuild": "^0.23.0", diff --git a/builder/src/build/build-worker/index.ts b/builder/src/build/build-worker.ts similarity index 99% rename from builder/src/build/build-worker/index.ts rename to builder/src/build/build-worker.ts index 6e0a572db..07b0078b4 100644 --- a/builder/src/build/build-worker/index.ts +++ b/builder/src/build/build-worker.ts @@ -1,4 +1,4 @@ -import { NextjsAppPaths } from "../../nextjs-paths"; +import { NextjsAppPaths } from "../nextjs-paths"; import { build, Plugin } from "esbuild"; import { readdirSync, readFileSync, writeFileSync } from "node:fs"; import { cp, readFile, writeFile } from "node:fs/promises"; diff --git a/builder/src/build/index.ts b/builder/src/build/build.ts similarity index 97% rename from builder/src/build/index.ts rename to builder/src/build/build.ts index aa8be9892..e4bbec393 100644 --- a/builder/src/build/index.ts +++ b/builder/src/build/build.ts @@ -43,8 +43,6 @@ export async function build(inputNextAppDir: string, opts: BuildOptions): Promis const templateDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "templates"); - console.log({ outputDir, nextjsAppPaths, templateDir }); - await buildWorker(outputDir, nextjsAppPaths, templateDir); } diff --git a/builder/src/build/build-worker/patches/investigated/copy-templates.ts b/builder/src/build/patches/investigated/copy-templates.ts similarity index 90% rename from builder/src/build/build-worker/patches/investigated/copy-templates.ts rename to builder/src/build/patches/investigated/copy-templates.ts index fb0bb2083..fd144db08 100644 --- a/builder/src/build/build-worker/patches/investigated/copy-templates.ts +++ b/builder/src/build/patches/investigated/copy-templates.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import { NextjsAppPaths } from "../../../../nextjs-paths"; +import { NextjsAppPaths } from "../../../nextjs-paths"; import { cpSync } from "node:fs"; /** diff --git a/builder/src/build/build-worker/patches/investigated/patch-require.ts b/builder/src/build/patches/investigated/patch-require.ts similarity index 100% rename from builder/src/build/build-worker/patches/investigated/patch-require.ts rename to builder/src/build/patches/investigated/patch-require.ts diff --git a/builder/src/build/build-worker/patches/investigated/patch-url.ts b/builder/src/build/patches/investigated/patch-url.ts similarity index 100% rename from builder/src/build/build-worker/patches/investigated/patch-url.ts rename to builder/src/build/patches/investigated/patch-url.ts diff --git a/builder/src/build/build-worker/patches/to-investigate/inline-eval-manifest.ts b/builder/src/build/patches/to-investigate/inline-eval-manifest.ts similarity index 96% rename from builder/src/build/build-worker/patches/to-investigate/inline-eval-manifest.ts rename to builder/src/build/patches/to-investigate/inline-eval-manifest.ts index 58d8ddebb..1b0a9e553 100644 --- a/builder/src/build/build-worker/patches/to-investigate/inline-eval-manifest.ts +++ b/builder/src/build/patches/to-investigate/inline-eval-manifest.ts @@ -1,5 +1,5 @@ import { globSync } from "glob"; -import { NextjsAppPaths } from "../../../../nextjs-paths"; +import { NextjsAppPaths } from "../../../nextjs-paths"; /** * `evalManifest` relies on readFileSync so we need to patch the function so that it instead returns the content of the manifest files diff --git a/builder/src/build/build-worker/patches/to-investigate/inline-next-require.ts b/builder/src/build/patches/to-investigate/inline-next-require.ts similarity index 96% rename from builder/src/build/build-worker/patches/to-investigate/inline-next-require.ts rename to builder/src/build/patches/to-investigate/inline-next-require.ts index 48467f8f4..a0332dc16 100644 --- a/builder/src/build/build-worker/patches/to-investigate/inline-next-require.ts +++ b/builder/src/build/patches/to-investigate/inline-next-require.ts @@ -1,5 +1,5 @@ import { readFileSync, existsSync } from "node:fs"; -import { NextjsAppPaths } from "../../../../nextjs-paths"; +import { NextjsAppPaths } from "../../../nextjs-paths"; /** * The following avoid various Next.js specific files `require`d at runtime since we can just read diff --git a/builder/src/build/build-worker/patches/to-investigate/patch-find-dir.ts b/builder/src/build/patches/to-investigate/patch-find-dir.ts similarity index 94% rename from builder/src/build/build-worker/patches/to-investigate/patch-find-dir.ts rename to builder/src/build/patches/to-investigate/patch-find-dir.ts index b1d3cb2ed..03ba5b5f9 100644 --- a/builder/src/build/build-worker/patches/to-investigate/patch-find-dir.ts +++ b/builder/src/build/patches/to-investigate/patch-find-dir.ts @@ -1,4 +1,4 @@ -import { NextjsAppPaths } from "../../../../nextjs-paths"; +import { NextjsAppPaths } from "../../../nextjs-paths"; import { existsSync } from "node:fs"; /** diff --git a/builder/src/build/build-worker/patches/to-investigate/patch-read-file.ts b/builder/src/build/patches/to-investigate/patch-read-file.ts similarity index 96% rename from builder/src/build/build-worker/patches/to-investigate/patch-read-file.ts rename to builder/src/build/patches/to-investigate/patch-read-file.ts index 6c9a4e0e9..19a7b4ffe 100644 --- a/builder/src/build/build-worker/patches/to-investigate/patch-read-file.ts +++ b/builder/src/build/patches/to-investigate/patch-read-file.ts @@ -1,6 +1,6 @@ import { readFileSync } from "node:fs"; import { globSync } from "glob"; -import { NextjsAppPaths } from "../../../../nextjs-paths"; +import { NextjsAppPaths } from "../../../nextjs-paths"; export function patchReadFile(code: string, nextjsAppPaths: NextjsAppPaths): string { console.log("# patchReadFile"); diff --git a/builder/src/build/build-worker/patches/to-investigate/wrangler-deps.ts b/builder/src/build/patches/to-investigate/wrangler-deps.ts similarity index 97% rename from builder/src/build/build-worker/patches/to-investigate/wrangler-deps.ts rename to builder/src/build/patches/to-investigate/wrangler-deps.ts index 93a9991e2..b482bcbb2 100644 --- a/builder/src/build/build-worker/patches/to-investigate/wrangler-deps.ts +++ b/builder/src/build/patches/to-investigate/wrangler-deps.ts @@ -1,6 +1,6 @@ import path from "node:path"; import fs, { writeFileSync } from "node:fs"; -import { NextjsAppPaths } from "../../../../nextjs-paths"; +import { NextjsAppPaths } from "../../../nextjs-paths"; export function patchWranglerDeps(paths: NextjsAppPaths) { console.log("# patchWranglerDeps"); diff --git a/builder/src/index.ts b/builder/src/index.ts index df2e8df37..036a12d7d 100644 --- a/builder/src/index.ts +++ b/builder/src/index.ts @@ -1,11 +1,11 @@ import { resolve } from "node:path"; import { getArgs } from "./args"; import { existsSync } from "node:fs"; -import { build } from "./build"; +import { build } from "./build/build"; -const inputNextAppDir = resolve("."); +const nextAppDir = resolve("."); -console.log({ inputNextAppDir }); +console.log(`Building the Next.js app in the current folder (${nextAppDir})`); if (!["js", "cjs", "mjs", "ts"].some((ext) => existsSync(`./next.config.${ext}`))) { // TODO: we can add more validation later @@ -14,7 +14,7 @@ if (!["js", "cjs", "mjs", "ts"].some((ext) => existsSync(`./next.config.${ext}`) const { skipBuild, outputDir } = getArgs(); -await build(inputNextAppDir, { +await build(nextAppDir, { outputDir, skipBuild: !!skipBuild, }); diff --git a/builder/src/build/build-worker/templates/shims/empty.ts b/builder/src/templates/shims/empty.ts similarity index 100% rename from builder/src/build/build-worker/templates/shims/empty.ts rename to builder/src/templates/shims/empty.ts diff --git a/builder/src/build/build-worker/templates/shims/env.ts b/builder/src/templates/shims/env.ts similarity index 100% rename from builder/src/build/build-worker/templates/shims/env.ts rename to builder/src/templates/shims/env.ts diff --git a/builder/src/build/build-worker/templates/shims/node-fs.ts b/builder/src/templates/shims/node-fs.ts similarity index 100% rename from builder/src/build/build-worker/templates/shims/node-fs.ts rename to builder/src/templates/shims/node-fs.ts diff --git a/builder/src/build/build-worker/templates/shims/throw.ts b/builder/src/templates/shims/throw.ts similarity index 100% rename from builder/src/build/build-worker/templates/shims/throw.ts rename to builder/src/templates/shims/throw.ts diff --git a/builder/src/build/build-worker/templates/worker.ts b/builder/src/templates/worker.ts similarity index 100% rename from builder/src/build/build-worker/templates/worker.ts rename to builder/src/templates/worker.ts diff --git a/builder/tsup.config.ts b/builder/tsup.config.ts index 8d1ff8478..a1ed4703e 100644 --- a/builder/tsup.config.ts +++ b/builder/tsup.config.ts @@ -4,12 +4,12 @@ import { defineConfig } from "tsup"; export default defineConfig({ entry: ["src/index.ts"], outDir: "dist", - dts: true, + dts: false, format: ["esm"], platform: "node", external: ["esbuild"], onSuccess: async () => { - await cp(`${__dirname}/src/build/build-worker/templates`, `${__dirname}/dist/templates`, { + await cp(`${__dirname}/src/templates`, `${__dirname}/dist/templates`, { recursive: true, }); }, diff --git a/examples/api/package.json b/examples/api/package.json index 8059d8e32..9c79fc7b5 100644 --- a/examples/api/package.json +++ b/examples/api/package.json @@ -7,7 +7,7 @@ "build": "next build", "start": "next start", "lint": "next lint", - "build:worker": "builder", + "build:worker": "pnpm builder", "dev:worker": "wrangler dev --port 8770", "preview:worker": "pnpm build:worker && pnpm dev:worker", "e2e": "playwright test" @@ -18,7 +18,7 @@ "react-dom": "^18" }, "devDependencies": { - "builder": "workspace:*", + "@flarelabs-net/builder": "workspace:*", "@playwright/test": "1.47.0", "@types/node": "^22.2.0", "node-url": "npm:url@^0.11.4", diff --git a/examples/create-next-app/package.json b/examples/create-next-app/package.json index 412e3e8ce..02072267b 100644 --- a/examples/create-next-app/package.json +++ b/examples/create-next-app/package.json @@ -7,7 +7,7 @@ "build": "next build", "start": "next start", "lint": "next lint", - "build:worker": "builder", + "build:worker": "pnpm builder", "dev:worker": "wrangler dev --port 8771", "preview:worker": "pnpm build:worker && pnpm dev:worker", "e2e": "playwright test -c e2e/playwright.config.ts" @@ -18,7 +18,7 @@ "next": "14.2.11" }, "devDependencies": { - "builder": "workspace:*", + "@flarelabs-net/builder": "workspace:*", "@playwright/test": "1.47.0", "@types/node": "^20", "@types/react": "^18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2ce78890..1cafdce81 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,15 +48,15 @@ importers: specifier: ^18 version: 18.3.1(react@18.3.1) devDependencies: + '@flarelabs-net/builder': + specifier: workspace:* + version: link:../../builder '@playwright/test': specifier: 1.47.0 version: 1.47.0 '@types/node': specifier: ^22.2.0 version: 22.2.0 - builder: - specifier: workspace:* - version: link:../../builder node-url: specifier: npm:url@^0.11.4 version: url@0.11.4 @@ -76,6 +76,9 @@ importers: specifier: ^18 version: 18.3.1(react@18.3.1) devDependencies: + '@flarelabs-net/builder': + specifier: workspace:* + version: link:../../builder '@playwright/test': specifier: 1.47.0 version: 1.47.0 @@ -88,9 +91,6 @@ importers: '@types/react-dom': specifier: ^18 version: 18.3.0 - builder: - specifier: workspace:* - version: link:../../builder eslint: specifier: ^8 version: 8.57.0