Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/@apphosting/adapter-nextjs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apphosting/adapter-nextjs",
"version": "14.0.17",
"version": "14.0.18",
"main": "dist/index.js",
"description": "Experimental addon to the Firebase CLI to add web framework support",
"repository": {
Expand Down
94 changes: 90 additions & 4 deletions packages/@apphosting/adapter-nextjs/src/bin/build.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,95 @@ outputFiles:
async () => await validateOutputDirectory(outputBundleOptions, path.join(tmpDir, ".next")),
);
});
it(".apphosting gitignored correctly in a monorepo setup", async () => {
const { generateBuildOutput } = await importUtils;
const files = {
".next/standalone/apps/next-app/standalonefile": "",
".next/static/staticfile": "",
};
generateTestFiles(tmpDir, files);
const standaloneAppPath = path.join(tmpDir, ".next", "standalone", "apps", "next-app");
await generateBuildOutput(
tmpDir,
"apps/next-app",
{
bundleYamlPath: path.join(tmpDir, ".apphosting", "bundle.yaml"),
outputDirectoryBasePath: path.join(tmpDir, ".apphosting"),
outputDirectoryAppPath: standaloneAppPath,
outputPublicDirectoryPath: path.join(standaloneAppPath, "public"),
outputStaticDirectoryPath: path.join(standaloneAppPath, ".next", "static"),
serverFilePath: path.join(standaloneAppPath, "server.js"),
},
path.join(tmpDir, ".next"),
defaultNextVersion,
adapterMetadata,
);

const expectedFiles = {
".gitignore": "/.apphosting/",
};
const expectedPartialYaml = {
version: "v1",
runConfig: { runCommand: "node .next/standalone/apps/next-app/server.js" },
};
validateTestFiles(tmpDir, expectedFiles);
validatePartialYamlContents(tmpDir, ".apphosting/bundle.yaml", expectedPartialYaml);
});

it(".apphosting gitignored without existing .gitignore file", async () => {
const { generateBuildOutput, validateOutputDirectory } = await importUtils;
const files = {
// .next/standalone/.next/ must be created beforehand otherwise
// generateBuildOutput will attempt to copy
// .next/ into .next/standalone/.next
".next/standalone/.next/package.json": "",
".next/static/staticfile": "",
};
generateTestFiles(tmpDir, files);
await generateBuildOutput(
tmpDir,
tmpDir,
outputBundleOptions,
path.join(tmpDir, ".next"),
defaultNextVersion,
adapterMetadata,
);
await validateOutputDirectory(outputBundleOptions, path.join(tmpDir, ".next"));

const expectedFiles = {
".gitignore": "/.apphosting/",
};
validateTestFiles(tmpDir, expectedFiles);
});
it(".apphosting gitignored in existing .gitignore file", async () => {
const { generateBuildOutput, validateOutputDirectory } = await importUtils;
const files = {
// .next/standalone/.next/ must be created beforehand otherwise
// generateBuildOutput will attempt to copy
// .next/ into .next/standalone/.next
".next/standalone/.next/package.json": "",
".next/static/staticfile": "",
".gitignore": "/.next/",
};
generateTestFiles(tmpDir, files);
await generateBuildOutput(
tmpDir,
tmpDir,
outputBundleOptions,
path.join(tmpDir, ".next"),
defaultNextVersion,
{
adapterPackageName: "@apphosting/adapter-nextjs",
adapterVersion: "14.0.1",
},
);
await validateOutputDirectory(outputBundleOptions, path.join(tmpDir, ".next"));

const expectedFiles = {
".gitignore": "/.next/\n/.apphosting/",
};
validateTestFiles(tmpDir, expectedFiles);
});
it("expects directories and other files to be copied over", async () => {
const { generateBuildOutput, validateOutputDirectory } = await importUtils;
const files = {
Expand All @@ -188,10 +277,7 @@ outputFiles:
outputBundleOptions,
path.join(tmpDir, ".next"),
defaultNextVersion,
{
adapterPackageName: "@apphosting/adapter-nextjs",
adapterVersion: "14.0.1",
},
adapterMetadata,
);
await validateOutputDirectory(outputBundleOptions, path.join(tmpDir, ".next"));

Expand Down
10 changes: 7 additions & 3 deletions packages/@apphosting/adapter-nextjs/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import {
MiddlewareManifest,
} from "./interfaces.js";
import { NextConfigComplete } from "next/dist/server/config-shared.js";
import { OutputBundleConfig } from "@apphosting/common";
import { OutputBundleConfig, updateOrCreateGitignore } from "@apphosting/common";

// fs-extra is CJS, readJson can't be imported using shorthand
export const { copy, exists, writeFile, readJson, readdir, readFileSync, existsSync, mkdir } =
export const { copy, exists, writeFile, readJson, readdir, readFileSync, existsSync, ensureDir } =
fsExtra;

// Loads the user's next.config.js file.
Expand Down Expand Up @@ -135,6 +135,10 @@ export async function generateBuildOutput(
copyResources(appDir, opts.outputDirectoryAppPath, opts.bundleYamlPath),
generateBundleYaml(opts, rootDir, nextVersion, adapterMetadata),
]);
// generateBundleYaml creates the output directory (if it does not already exist).
// We need to make sure it is gitignored.
const normalizedBundleDir = normalize(relative(rootDir, opts.outputDirectoryBasePath));
updateOrCreateGitignore(rootDir, [`/${normalizedBundleDir}/`]);
return;
}

Expand Down Expand Up @@ -181,7 +185,7 @@ async function generateBundleYaml(
nextVersion: string,
adapterMetadata: AdapterMetadata,
): Promise<void> {
await mkdir(opts.outputDirectoryBasePath);
await ensureDir(opts.outputDirectoryBasePath);
const outputBundle: OutputBundleConfig = {
version: "v1",
runConfig: {
Expand Down