diff --git a/.changeset/angry-cougars-tap.md b/.changeset/angry-cougars-tap.md new file mode 100644 index 000000000..c3d99a871 --- /dev/null +++ b/.changeset/angry-cougars-tap.md @@ -0,0 +1,7 @@ +--- +"@opennextjs/aws": patch +--- + +fix(middleware): always compiles the middleware. + +Prior to this PR the middleware would only be compiled when a middleware.ts exists. diff --git a/packages/open-next/src/adapters/plugins/README.md b/packages/open-next/src/adapters/plugins/README.md index 324cf3737..ebc4a1f2f 100644 --- a/packages/open-next/src/adapters/plugins/README.md +++ b/packages/open-next/src/adapters/plugins/README.md @@ -1,10 +1,10 @@ -### Known issues +# Known issues -Do not include `types` in #override and #imports, as esbuild will remove preceeding comments (ie it removes //#override id)when it builds. +Do not include `types` in #override and #imports, as esbuild will remove preceding comments (ie it removes //#override id)when it builds. Instead, put the `import type` outside like: -``` +```ts import type { PluginHandler } from "../next-types.js"; import type { IncomingMessage } from "../request.js"; import type { ServerResponse } from "../response.js"; diff --git a/packages/open-next/src/adapters/plugins/without-routing/requestHandler.ts b/packages/open-next/src/adapters/plugins/without-routing/requestHandler.ts deleted file mode 100644 index 834a05aec..000000000 --- a/packages/open-next/src/adapters/plugins/without-routing/requestHandler.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable unused-imports/no-unused-vars */ -import type { InternalEvent } from "types/open-next"; - -import type { MiddlewareOutputEvent } from "../../../core/routingHandler"; -// This is available in requestHandler.ts -declare const internalEvent: InternalEvent; - -//#override withRouting -const preprocessResult: MiddlewareOutputEvent = { - internalEvent: internalEvent, - isExternalRewrite: false, - origin: false, - isISR: false, -}; -//#endOverride - -// We need to export something otherwise when compiled in js it creates an empty export {} inside the override -export default {}; diff --git a/packages/open-next/src/build/createMiddleware.ts b/packages/open-next/src/build/createMiddleware.ts index bfa845cf5..2271b0af4 100644 --- a/packages/open-next/src/build/createMiddleware.ts +++ b/packages/open-next/src/build/createMiddleware.ts @@ -2,7 +2,10 @@ import fs from "node:fs"; import path from "node:path"; import logger from "../logger.js"; -import { type MiddlewareManifest } from "../types/next-types.js"; +import { + type MiddlewareInfo, + type MiddlewareManifest, +} from "../types/next-types.js"; import { buildEdgeBundle } from "./edge/createEdgeBundle.js"; import * as buildHelper from "./helper.js"; import { installDependencies } from "./installDeps.js"; @@ -11,7 +14,6 @@ import { installDependencies } from "./installDeps.js"; * Compiles the middleware bundle. * * @param options Build Options. - * @returns Whether the app uses a Middleware. */ export async function createMiddleware(options: buildHelper.BuildOptions) { logger.info(`Bundling middleware function...`); @@ -26,15 +28,9 @@ export async function createMiddleware(options: buildHelper.BuildOptions) { ), ) as MiddlewareManifest; - const entry = middlewareManifest.middleware["/"]; - if (!entry) { - return { useMiddleware: false }; - } - - const commonMiddlewareOptions = { - middlewareInfo: entry, - options, - }; + const middlewareInfo = middlewareManifest.middleware["/"] as + | MiddlewareInfo + | undefined; if (config.middleware?.external) { const outputPath = path.join(outputDir, "middleware"); @@ -55,7 +51,8 @@ export async function createMiddleware(options: buildHelper.BuildOptions) { "middleware.js", ), outfile: path.join(outputPath, "handler.mjs"), - ...commonMiddlewareOptions, + middlewareInfo, + options, overrides: config.middleware?.override, defaultConverter: "aws-cloudfront", includeCache: config.dangerous?.enableCacheInterception, @@ -71,10 +68,9 @@ export async function createMiddleware(options: buildHelper.BuildOptions) { "edgeFunctionHandler.js", ), outfile: path.join(options.buildDir, "middleware.mjs"), - ...commonMiddlewareOptions, + middlewareInfo, + options, onlyBuildOnce: true, }); } - - return { useMiddleware: true }; } diff --git a/packages/open-next/src/build/createServerBundle.ts b/packages/open-next/src/build/createServerBundle.ts index 29e33a05d..3590de236 100644 --- a/packages/open-next/src/build/createServerBundle.ts +++ b/packages/open-next/src/build/createServerBundle.ts @@ -1,5 +1,4 @@ import fs from "node:fs"; -import { createRequire } from "node:module"; import path from "node:path"; import type { FunctionOptions, SplittedFunctionOptions } from "types/open-next"; @@ -15,8 +14,6 @@ import { generateEdgeBundle } from "./edge/createEdgeBundle.js"; import * as buildHelper from "./helper.js"; import { installDependencies } from "./installDeps.js"; -const require = createRequire(import.meta.url); - export async function createServerBundle(options: buildHelper.BuildOptions) { const { config } = options; const foundRoutes = new Set(); @@ -146,10 +143,7 @@ async function generateBundle( } // Copy middleware - if ( - !config.middleware?.external && - fs.existsSync(path.join(options.buildDir, "middleware.mjs")) - ) { + if (!config.middleware?.external) { fs.copyFileSync( path.join(options.buildDir, "middleware.mjs"), path.join(outputPath, packagePath, "middleware.mjs"), @@ -191,18 +185,15 @@ async function generateBundle( buildHelper.compareSemver(options.nextVersion, "14.0.4") >= 0; const disableRouting = isBefore13413 || config.middleware?.external; + const plugins = [ openNextReplacementPlugin({ name: `requestHandlerOverride ${name}`, target: /core(\/|\\)requestHandler\.js/g, - deletes: disableNextPrebundledReact ? ["applyNextjsPrebundledReact"] : [], - replacements: disableRouting - ? [ - require.resolve( - "../adapters/plugins/without-routing/requestHandler.js", - ), - ] - : [], + deletes: [ + ...(disableNextPrebundledReact ? ["applyNextjsPrebundledReact"] : []), + ...(disableRouting ? ["withRouting"] : []), + ], }), openNextReplacementPlugin({ name: `utilOverride ${name}`, diff --git a/packages/open-next/src/build/edge/createEdgeBundle.ts b/packages/open-next/src/build/edge/createEdgeBundle.ts index dd9b7d19a..255f15b1d 100644 --- a/packages/open-next/src/build/edge/createEdgeBundle.ts +++ b/packages/open-next/src/build/edge/createEdgeBundle.ts @@ -19,7 +19,7 @@ import type { BuildOptions } from "../helper.js"; import { copyOpenNextConfig, esbuildAsync } from "../helper.js"; interface BuildEdgeBundleOptions { - middlewareInfo: MiddlewareInfo; + middlewareInfo?: MiddlewareInfo; entrypoint: string; outfile: string; options: BuildOptions; @@ -158,8 +158,6 @@ globalThis.AsyncLocalStorage = AsyncLocalStorage; } } -export function copyMiddlewareAssetsAndWasm({}) {} - export async function generateEdgeBundle( name: string, options: BuildOptions, @@ -191,10 +189,10 @@ export async function generateEdgeBundle( if (functions.length > 1) { throw new Error("Only one function is supported for now"); } - const fn = functions[0]; + const middlewareInfo = functions[0]; //Copy wasm files - const wasmFiles = fn.wasm; + const wasmFiles = middlewareInfo.wasm; mkdirSync(path.join(outputPath, "wasm"), { recursive: true }); for (const wasmFile of wasmFiles) { fs.copyFileSync( @@ -204,7 +202,7 @@ export async function generateEdgeBundle( } // Copy assets - const assets = fn.assets; + const assets = middlewareInfo.assets; mkdirSync(path.join(outputPath, "assets"), { recursive: true }); for (const asset of assets) { fs.copyFileSync( @@ -214,7 +212,7 @@ export async function generateEdgeBundle( } await buildEdgeBundle({ - middlewareInfo: fn, + middlewareInfo, entrypoint: path.join( options.openNextDistDir, "adapters", diff --git a/packages/open-next/src/core/requestHandler.ts b/packages/open-next/src/core/requestHandler.ts index f255c5e35..8d1758ae9 100644 --- a/packages/open-next/src/core/requestHandler.ts +++ b/packages/open-next/src/core/requestHandler.ts @@ -31,13 +31,14 @@ export async function openNextHandler( } debug("internalEvent", internalEvent); - //#override withRouting let preprocessResult: InternalResult | MiddlewareOutputEvent = { internalEvent: internalEvent, isExternalRewrite: false, origin: false, isISR: false, }; + + //#override withRouting try { preprocessResult = await routingHandler(internalEvent); } catch (e) { diff --git a/packages/open-next/src/plugins/edge.ts b/packages/open-next/src/plugins/edge.ts index 6a87b6108..fb8ab805c 100644 --- a/packages/open-next/src/plugins/edge.ts +++ b/packages/open-next/src/plugins/edge.ts @@ -18,14 +18,14 @@ import { export interface IPluginSettings { nextDir: string; edgeFunctionHandlerPath?: string; - middlewareInfo: MiddlewareInfo; + middlewareInfo?: MiddlewareInfo; isInCloudfare?: boolean; } /** * @param opts.nextDir - The path to the .next directory * @param opts.edgeFunctionHandlerPath - The path to the edgeFunctionHandler.js file that we'll use to bundle the routing - * @param opts.entryFiles - The entry files that we'll inject into the edgeFunctionHandler.js file + * @param opts.middlewareInfo - The entry files that we'll inject into the edgeFunctionHandler.js file * @returns */ export function openNextEdgePlugins({ @@ -34,17 +34,19 @@ export function openNextEdgePlugins({ middlewareInfo, isInCloudfare, }: IPluginSettings): Plugin { - const entryFiles = middlewareInfo.files.map((file: string) => - path.join(nextDir, file), - ); - const routes = [ - { - name: middlewareInfo.name || "/", - page: middlewareInfo.page, - regex: middlewareInfo.matchers.map((m) => m.regexp), - }, - ]; - const wasmFiles = middlewareInfo.wasm ?? []; + const entryFiles = + middlewareInfo?.files.map((file: string) => path.join(nextDir, file)) ?? []; + const routes = middlewareInfo + ? [ + { + name: middlewareInfo.name || "/", + page: middlewareInfo.page, + regex: middlewareInfo.matchers.map((m) => m.regexp), + }, + ] + : []; + const wasmFiles = middlewareInfo?.wasm ?? []; + return { name: "opennext-edge", setup(build) { @@ -134,7 +136,7 @@ if(!globalThis.Crypto) { globalThis.Crypto = webcrypto.Crypto } // We also need to polyfill URLPattern -if (!globalThis.URLPattern) { +if (!globalThis.URLPattern) { await import("urlpattern-polyfill"); } ` @@ -146,8 +148,8 @@ ${wasmFiles : `const ${file.name} = readFileSync(path.join(__dirname,'/wasm/${file.name}.wasm'));`, ) .join("\n")} -${entryFiles?.map((file) => `require("${file}");`).join("\n")} -${contents} +${entryFiles.map((file) => `require("${file}");`).join("\n")} +${contents} `; return { contents, @@ -166,18 +168,18 @@ ${contents} const contents = ` import path from "path"; - + import { debug } from "../logger"; - + if(!globalThis.__dirname) { globalThis.__dirname = "" } - + export const NEXT_DIR = path.join(__dirname, ".next"); export const OPEN_NEXT_DIR = path.join(__dirname, ".open-next"); - + debug({ NEXT_DIR, OPEN_NEXT_DIR }); - + export const NextConfig = ${JSON.stringify(NextConfig)}; export const BuildId = ${JSON.stringify(BuildId)}; export const HtmlPages = ${JSON.stringify(HtmlPages)}; @@ -188,7 +190,7 @@ ${contents} export const MiddlewareManifest = ${JSON.stringify(MiddlewareManifest)}; process.env.NEXT_BUILD_ID = BuildId; - + `; return { contents,