Skip to content

Commit 966fa0c

Browse files
conico974vicb
andauthored
Make a default overridable adapter in core (#35)
* refactor: remove createServerBundle.ts and integrate its functionality into core adapter feat: enhance build process with additional server bundle customization options chore: update package.json scripts for improved build and testing workflow test: add unit tests for adapter build process and server bundle generation fix: ensure proper handling of external dependencies and edge configuration in server bundle * feat: implement default overrides for bundle configurations and add tests for resolve plugin * format * fix ts issue * feat: add default overrides for AWS adapter and integrate Cloudflare specific overrides * Revert "feat: add default overrides for AWS adapter and integrate Cloudflare specific overrides" This reverts commit 37c4d90. * feat: enhance AWS adapter with default overrides and improve middleware configuration * refactor(core): return ValidateConfigResult from validateConfig instead of throwing - Extract ValidateConfigResult type with success/message/shouldThrow/level - Convert validateFunctionOptions and validateSplittedFunctionOptions to return result objects - Remove logger dependency from validateConfig.ts - Preserve compatibilityMatrix, TODO comment, @ts-expect-error pragmas - Add 5 characterization tests in validateConfig.spec.ts - No caller impact: compileConfig.ts is the sole importer (updated in T3) * refactor(core): extract buildOpenNextOutput, export OpenNextOutput type - Export OpenNextOutput interface (was internal) - Extract buildOpenNextOutput(buildOpts) for construction-only (no fs write) - Keep legacy generateOutput as thin wrapper (construction + file write) - Preserve all construction logic verbatim, including @ts-expect-error - Add 3 characterization tests in generateOutput.spec.ts - Backward compatible: byte-equivalent output to today * refactor(core): branch on ValidateConfigResult in compileOpenNextConfig - Replace bare validateConfig(config) call with result-handling block - Throw on shouldThrow:true (bad routes — preserves existing behavior) - Log at appropriate level on shouldThrow:false (level field from T1) - All 3 export signatures and edge-runtime detection block unchanged - Direct callers (aws/build.ts, cloudflare/utils.ts) unaffected * feat(core): overridable validateConfig and generic generateOutput on OpenNextAdapterOptions - Make OpenNextAdapterOptions<T = OpenNextOutput> and buildAdapter<T> generic - Add validateConfig override hook (runs after callback in modifyConfig) - Add generateOutput override hook (returns T, gated by skipGenerateOutput) - buildAdapter serializes override return via fs.writeFileSync (override never touches fs) - Default path uses buildOpenNextOutput (extracted in T2) - Add 5 new tests covering override behaviors + default path + skipGenerateOutput - All 16 existing adapter tests preserved; AWS/Cloudflare adapters compile with default T * fix(core): use require.resolve for full-path overrides in resolve plugin When an adapter config specifies full package-specifier paths (e.g., @opennextjs/aws/overrides/wrappers/aws-lambda.js), esbuild cannot resolve them during bundling. Use createRequire(args.path).resolve() in the openNextResolvePlugin to convert package specifiers to filesystem-relative paths at build time, falling back to the original value if resolution fails. This fixes the openbuild:local build error: ERROR: Could not resolve "@opennextjs/aws/overrides/wrappers/aws-lambda.js" ERROR: Could not resolve "@opennextjs/aws/overrides/tagCache/dynamodb.js" Added test I verifying resolution of a mock package in node_modules. * format * feat(core): enforce mandatory externals in serverBundle and update related hooks * refactor(core): enhance resolve plugin to support dynamic override resolution and improve path handling * fixup! minor cleanup * fixup! oopsy --------- Co-authored-by: Victor Berchet <victor@suumit.com>
1 parent d018dd1 commit 966fa0c

27 files changed

Lines changed: 1885 additions & 786 deletions

packages/aws/src/adapter.ts

Lines changed: 41 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,46 @@
1-
import fs from "node:fs";
2-
import { createRequire } from "node:module";
3-
import path from "node:path";
4-
5-
import { compileCache } from "@opennextjs/core/build/compileCache.js";
6-
import { compileOpenNextConfig } from "@opennextjs/core/build/compileConfig.js";
7-
import { compileTagCacheProvider } from "@opennextjs/core/build/compileTagCacheProvider.js";
8-
import { createCacheAssets, createStaticAssets } from "@opennextjs/core/build/createAssets.js";
9-
import { createImageOptimizationBundle } from "@opennextjs/core/build/createImageOptimizationBundle.js";
10-
import { createMiddleware } from "@opennextjs/core/build/createMiddleware.js";
11-
import { createRevalidationBundle } from "@opennextjs/core/build/createRevalidationBundle.js";
12-
import { createServerBundle } from "@opennextjs/core/build/createServerBundle.js";
13-
import { createWarmerBundle } from "@opennextjs/core/build/createWarmerBundle.js";
14-
import { generateOutput } from "@opennextjs/core/build/generateOutput.js";
1+
import { buildAdapter } from "@opennextjs/core/build/adapter.js";
2+
import type { BuildOptions } from "@opennextjs/core/build/helper.js";
153
import * as buildHelper from "@opennextjs/core/build/helper.js";
16-
import { addDebugFile } from "@opennextjs/core/debug.js";
174
import type { ContentUpdater } from "@opennextjs/core/plugins/content-updater.js";
185
import { externalChunksPlugin, inlineRouteHandler } from "@opennextjs/core/plugins/inlineRouteHandlers.js";
19-
import type { NextConfig } from "@opennextjs/core/types/next-types.js";
20-
21-
export type NextAdapterOutput = {
22-
pathname: string;
23-
filePath: string;
24-
assets: Record<string, unknown>;
25-
};
26-
27-
export type NextAdapterOutputs = {
28-
pages: NextAdapterOutput[];
29-
pagesApi: NextAdapterOutput[];
30-
appPages: NextAdapterOutput[];
31-
appRoutes: NextAdapterOutput[];
32-
middleware?: NextAdapterOutput;
33-
};
34-
35-
type NextAdapter = {
36-
name: string;
37-
modifyConfig: (config: NextConfig, { phase }: { phase: string }) => Promise<NextConfig>;
38-
onBuildComplete: (props: {
39-
routes: unknown;
40-
outputs: NextAdapterOutputs;
41-
projectDir: string;
42-
repoRoot: string;
43-
distDir: string;
44-
config: NextConfig;
45-
nextVersion: string;
46-
}) => Promise<void>;
47-
}; //TODO: use the one provided by Next
48-
49-
let buildOpts: buildHelper.BuildOptions;
50-
51-
export default {
52-
name: "OpenNext",
53-
async modifyConfig(nextConfig, { phase }) {
54-
// We have to precompile the cache here, probably compile OpenNext config as well
55-
const { config, buildDir } = await compileOpenNextConfig("open-next.config.ts", {
56-
nodeExternals: undefined,
57-
});
58-
59-
const require = createRequire(import.meta.url);
60-
//TODO: change that
61-
const openNextDistDir = path.dirname(require.resolve("@opennextjs/core/debug.js"));
62-
63-
buildOpts = buildHelper.normalizeOptions(config, openNextDistDir, buildDir);
64-
65-
buildHelper.initOutputDir(buildOpts);
66-
67-
const cache = compileCache(buildOpts);
68-
69-
const packagePath = buildHelper.getPackagePath(buildOpts);
70-
71-
// We then have to copy the cache files to the .next dir so that they are available at runtime
72-
//TODO: use a better path, this one is temporary just to make it work
73-
const tempCachePath = path.join(
74-
buildOpts.outputDir,
75-
"server-functions/default",
76-
packagePath,
77-
".open-next/.build"
78-
);
79-
fs.mkdirSync(tempCachePath, { recursive: true });
80-
fs.copyFileSync(cache.cache, path.join(tempCachePath, "cache.cjs"));
81-
fs.copyFileSync(cache.composableCache, path.join(tempCachePath, "composable-cache.cjs"));
82-
83-
//TODO: We should check the version of Next here, below 16 we'd throw or show a warning
84-
return {
85-
...nextConfig,
86-
cacheHandler: cache.cache, //TODO: compute that here,
87-
cacheHandlers: {
88-
default: cache.composableCache,
89-
remote: cache.composableCache,
90-
},
91-
cacheMaxMemorySize: 0,
92-
experimental: {
93-
...nextConfig.experimental,
94-
trustHostHeader: true,
95-
},
96-
};
6+
import type { NextAdapterOutputs } from "@opennextjs/core/types/adapter.js";
7+
8+
export default buildAdapter((_config, buildOpts: BuildOptions) => ({
9+
defaultOverrides: {
10+
server: {
11+
wrapper: "@opennextjs/aws/overrides/wrappers/aws-lambda-streaming.js",
12+
converter: "@opennextjs/aws/overrides/converters/aws-apigw-v2.js",
13+
incrementalCache: "@opennextjs/aws/overrides/incrementalCache/s3.js",
14+
tagCache: "@opennextjs/aws/overrides/tagCache/dynamodb.js",
15+
queue: "@opennextjs/aws/overrides/queue/sqs.js",
16+
},
17+
revalidation: {
18+
wrapper: "@opennextjs/aws/overrides/wrappers/aws-lambda.js",
19+
converter: "@opennextjs/aws/overrides/converters/sqs-revalidate.js",
20+
},
21+
imageOptimization: {
22+
wrapper: "@opennextjs/aws/overrides/wrappers/aws-lambda.js",
23+
converter: "@opennextjs/aws/overrides/converters/aws-apigw-v2.js",
24+
imageLoader: "@opennextjs/aws/overrides/imageLoader/s3.js",
25+
},
26+
warmer: { wrapper: "@opennextjs/aws/overrides/wrappers/aws-lambda.js" },
27+
tagCache: {
28+
wrapper: "@opennextjs/aws/overrides/wrappers/aws-lambda.js",
29+
tagCache: "@opennextjs/aws/overrides/tagCache/dynamodb.js",
30+
},
31+
middleware: {
32+
wrapper: "@opennextjs/aws/overrides/wrappers/aws-lambda.js",
33+
converter: "@opennextjs/aws/overrides/converters/aws-cloudfront.js",
34+
incrementalCache: "@opennextjs/aws/overrides/incrementalCache/s3-lite.js",
35+
tagCache: "@opennextjs/aws/overrides/tagCache/dynamodb-lite.js",
36+
queue: "@opennextjs/aws/overrides/queue/sqs-lite.js",
37+
},
9738
},
98-
async onBuildComplete(outputs) {
99-
console.log("OpenNext build will start now");
100-
101-
// TODO(vicb): save outputs
102-
addDebugFile(buildOpts, "outputs.json", outputs);
103-
104-
// Compile middleware
105-
await createMiddleware(buildOpts);
106-
console.log("Middleware created");
107-
108-
createStaticAssets(buildOpts);
109-
console.log("Static assets created");
110-
111-
if (buildOpts.config.dangerous?.disableIncrementalCache !== true) {
112-
const { useTagCache } = createCacheAssets(buildOpts);
113-
console.log("Cache assets created");
114-
if (useTagCache) {
115-
await compileTagCacheProvider(buildOpts);
116-
console.log("Tag cache provider compiled");
117-
}
118-
}
119-
120-
await createServerBundle(
121-
buildOpts,
122-
{
123-
additionalPlugins: getAdditionalPluginsFactory(buildOpts, outputs.outputs),
124-
},
125-
outputs.outputs
126-
);
127-
128-
console.log("Server bundle created");
129-
await createRevalidationBundle(buildOpts);
130-
console.log("Revalidation bundle created");
131-
await createImageOptimizationBundle(buildOpts);
132-
console.log("Image optimization bundle created");
133-
await createWarmerBundle(buildOpts);
134-
console.log("Warmer bundle created");
135-
await generateOutput(buildOpts);
136-
console.log("Output generated");
39+
serverBundle: {
40+
externals: ["./middleware.mjs"],
41+
additionalPlugins: (updater: ContentUpdater, outputs: NextAdapterOutputs) => {
42+
const packagePath = buildHelper.getPackagePath(buildOpts);
43+
return [inlineRouteHandler(updater, outputs, packagePath), externalChunksPlugin(outputs, packagePath)];
44+
},
13745
},
138-
} satisfies NextAdapter;
139-
140-
function getAdditionalPluginsFactory(buildOpts: buildHelper.BuildOptions, outputs: NextAdapterOutputs) {
141-
//TODO: we should make this a property of buildOpts
142-
const packagePath = buildHelper.getPackagePath(buildOpts);
143-
return (updater: ContentUpdater) => [
144-
inlineRouteHandler(updater, outputs, packagePath),
145-
externalChunksPlugin(outputs, packagePath),
146-
];
147-
}
46+
}));

packages/aws/src/build.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,8 @@ import path from "node:path";
33
import url from "node:url";
44

55
import { buildNextjsApp, setStandaloneBuildMode } from "@opennextjs/core/build/buildNextApp.js";
6-
import { compileCache } from "@opennextjs/core/build/compileCache.js";
76
import { compileOpenNextConfig } from "@opennextjs/core/build/compileConfig.js";
8-
import { compileTagCacheProvider } from "@opennextjs/core/build/compileTagCacheProvider.js";
9-
import { createCacheAssets, createStaticAssets } from "@opennextjs/core/build/createAssets.js";
10-
import { createImageOptimizationBundle } from "@opennextjs/core/build/createImageOptimizationBundle.js";
11-
import { createMiddleware } from "@opennextjs/core/build/createMiddleware.js";
12-
import { createRevalidationBundle } from "@opennextjs/core/build/createRevalidationBundle.js";
13-
import { createServerBundle } from "@opennextjs/core/build/createServerBundle.js";
14-
import { createWarmerBundle } from "@opennextjs/core/build/createWarmerBundle.js";
15-
import { generateOutput } from "@opennextjs/core/build/generateOutput.js";
167
import * as buildHelper from "@opennextjs/core/build/helper.js";
17-
import { patchOriginalNextConfig } from "@opennextjs/core/build/patch/patches/index.js";
188
import { printHeader, showWarningOnWindows } from "@opennextjs/core/build/utils.js";
199
import logger from "@opennextjs/core/logger.js";
2010

0 commit comments

Comments
 (0)