Skip to content

Commit

Permalink
Add support to next.config.mjs (#6933)
Browse files Browse the repository at this point in the history
  • Loading branch information
leoortizz authored Apr 4, 2024
1 parent 02e3701 commit e1a4a16
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
- Adds (opt-out) experiment to disable cleaning up containers after a functions deploy (#6861)
- Fix Next.js image optimization check in app directory for Windows (#6930)
- Add support to next.config.mjs (#6933)
2 changes: 2 additions & 0 deletions src/frameworks/next/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const APP_PATHS_MANIFEST: typeof APP_PATHS_MANIFEST_TYPE = "app-paths-man
export const SERVER_REFERENCE_MANIFEST: `${typeof SERVER_REFERENCE_MANIFEST_TYPE}.json` =
"server-reference-manifest.json";

export const CONFIG_FILES = ["next.config.js", "next.config.mjs"] as const;

export const ESBUILD_VERSION = "0.19.2";

// This is copied from Next.js source code to keep WEBPACK_LAYERS in sync with the Next.js definition.
Expand Down
36 changes: 20 additions & 16 deletions src/frameworks/next/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type { DomainLocale } from "next/dist/server/config";
import type { PagesManifest } from "next/dist/build/webpack/plugins/pages-manifest-plugin";
import { copy, mkdirp, pathExists, pathExistsSync } from "fs-extra";
import { pathToFileURL, parse } from "url";
import { existsSync } from "fs";
import { gte } from "semver";
import { IncomingMessage, ServerResponse } from "http";
import * as clc from "colorette";
Expand Down Expand Up @@ -55,6 +54,7 @@ import {
getNextVersion,
hasStaticAppNotFoundComponent,
getRoutesWithServerAction,
whichNextConfigFile,
} from "./utils";
import { NODE_VERSION, NPM_COMMAND_TIMEOUT_MILLIES, SHARP_VERSION, I18N_ROOT } from "../constants";
import type {
Expand Down Expand Up @@ -102,7 +102,7 @@ function getReactVersion(cwd: string): string | undefined {
export async function discover(dir: string) {
if (!(await pathExists(join(dir, "package.json")))) return;
const version = getNextVersion(dir);
if (!(await pathExists("next.config.js")) && !version) return;
if (!(await whichNextConfigFile(dir)) && !version) return;

return { mayWantBackend: true, publicDirectory: join(dir, PUBLIC_DIR), version };
}
Expand Down Expand Up @@ -568,7 +568,8 @@ export async function ɵcodegenFunctionsDirectory(
// macs and older Node versions; either way, we should avoid taking on any deps in firebase-tools
// Alternatively I tried using @swc/spack and the webpack bundled into Next.js but was
// encountering difficulties with both of those
if (existsSync(join(sourceDir, "next.config.js"))) {
const configFile = await whichNextConfigFile(sourceDir);
if (configFile) {
try {
const productionDeps = await new Promise<string[]>((resolve) => {
const dependencies: string[] = [];
Expand All @@ -595,16 +596,18 @@ export async function ɵcodegenFunctionsDirectory(
// DevDeps won't be included in the Cloud Function, so they should be bundled
const esbuildArgs = productionDeps
.map((it) => `--external:${it}`)
.concat(
"--bundle",
"--platform=node",
`--target=node${NODE_VERSION}`,
`--outdir=${destDir}`,
"--log-level=error",
);
.concat("--bundle", "--platform=node", `--target=node${NODE_VERSION}`, "--log-level=error");

if (configFile === "next.config.mjs") {
// ensure generated file is .mjs if the config is .mjs
esbuildArgs.push(...[`--outfile=${join(destDir, configFile)}`, "--format=esm"]);
} else {
esbuildArgs.push(`--outfile=${join(destDir, configFile)}`);
}

const bundle = spawnSync(
"npx",
["--yes", `esbuild@${ESBUILD_VERSION}`, "next.config.js", ...esbuildArgs],
["--yes", `esbuild@${ESBUILD_VERSION}`, configFile, ...esbuildArgs],
{
cwd: sourceDir,
timeout: BUNDLE_NEXT_CONFIG_TIMEOUT,
Expand All @@ -615,10 +618,10 @@ export async function ɵcodegenFunctionsDirectory(
}
} catch (e: any) {
console.warn(
"Unable to bundle next.config.js for use in Cloud Functions, proceeding with deploy but problems may be enountered.",
`Unable to bundle ${configFile} for use in Cloud Functions, proceeding with deploy but problems may be encountered.`,
);
console.error(e.message || e);
copy(join(sourceDir, "next.config.js"), join(destDir, "next.config.js"));
await copy(join(sourceDir, configFile), join(destDir, configFile));
}
}
if (await pathExists(join(sourceDir, "public"))) {
Expand Down Expand Up @@ -688,7 +691,8 @@ async function getConfig(
dir: string,
): Promise<Partial<NextConfig> & { distDir: string; trailingSlash: boolean; basePath: string }> {
let config: NextConfig = {};
if (existsSync(join(dir, "next.config.js"))) {
const configFile = await whichNextConfigFile(dir);
if (configFile) {
const version = getNextVersion(dir);
if (!version) throw new Error("Unable to find the next dep, try NPM installing?");
if (gte(version, "12.0.0")) {
Expand All @@ -699,9 +703,9 @@ async function getConfig(
config = await loadConfig(PHASE_PRODUCTION_BUILD, dir);
} else {
try {
config = await import(pathToFileURL(join(dir, "next.config.js")).toString());
config = await import(pathToFileURL(join(dir, configFile)).toString());
} catch (e) {
throw new Error("Unable to load next.config.js.");
throw new Error(`Unable to load ${configFile}.`);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/frameworks/next/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { RouteHas } from "next/dist/lib/load-custom-routes";
import type { ImageConfigComplete } from "next/dist/shared/lib/image-config";
import type { MiddlewareManifest as MiddlewareManifestV2FromNext } from "next/dist/build/webpack/plugins/middleware-plugin";
import type { HostingHeaders } from "../../firebaseConfig";
import type { CONFIG_FILES } from "./constants";

export interface RoutesManifestRewriteObject {
beforeFiles?: RoutesManifestRewrite[];
Expand Down Expand Up @@ -156,3 +157,5 @@ type Actions = {
};
};
};

export type NextConfigFileName = (typeof CONFIG_FILES)[number];
14 changes: 14 additions & 0 deletions src/frameworks/next/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ import type {
HostingHeadersWithSource,
AppPathRoutesManifest,
ActionManifest,
NextConfigFileName,
} from "./interfaces";
import {
APP_PATH_ROUTES_MANIFEST,
EXPORT_MARKER,
IMAGES_MANIFEST,
MIDDLEWARE_MANIFEST,
WEBPACK_LAYERS,
CONFIG_FILES,
} from "./constants";
import { dirExistsSync, fileExistsSync } from "../../fsutils";
import { IS_WINDOWS } from "../../utils";
Expand Down Expand Up @@ -458,3 +460,15 @@ export function getRoutesWithServerAction(

return Array.from(routesWithServerAction);
}

/**
* Get the Next.js config file name in the project directory, either
* `next.config.js` or `next.config.mjs`. If none of them exist, return null.
*/
export async function whichNextConfigFile(dir: string): Promise<NextConfigFileName | null> {
for (const file of CONFIG_FILES) {
if (await pathExists(join(dir, file))) return file;
}

return null;
}

0 comments on commit e1a4a16

Please sign in to comment.