-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support monorepo builds in Next.js adapter #160
Conversation
// dynamically load NextJS so this can be used in an NPX context | ||
const require = createRequire(import.meta.url); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this change? We might have discussed this but I forgot the reason
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah we discussed this a few weeks ago and my memory was also a bit fuzzy, but we need this in order to locate the package in the root node_modules folder (which is relevant for monorepo contexts).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any additional documentation we can link to in this line comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry not to be too pedantic but this comment explains what this does as opposed to why we need it.
Can we have a comment here explaining the motivation behind this statement? eg "Intentionally use ESM module resolution here to support blah blah blah"
See go/tott/563
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A good litmus test is: Would someone who's not you, a year from now, understand why we need this statement based on the line comment? Would they be able to gather sufficient context either from the code, the comment, or linked docs to own it going forward?
@@ -17,6 +18,13 @@ describe("build commands", () => { | |||
outputStaticDirectory: path.join(tmpDir, ".apphosting/.next/static"), | |||
serverFilePath: path.join(tmpDir, ".apphosting/server.js"), | |||
}; | |||
outputBundleMonorepoOptions = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit I would inline this, see go/tott/643
const root = process.cwd(); | ||
|
||
let projectRoot = root; | ||
if (process.env.MONOREPO_PROJECT && process.env.FIREBASE_APP_DIRECTORY) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OOC why do we need the MONOREPO_PROJECT check? Shouldn't we always respect FIREBASE_APP_DIRECTORY?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we should always be respecting FIREBASE_APP_DIRECTORY.
Overall, this seems like a reasonable approach and I see now that this follows the pattern used by the Angular adapter as well. My high level feedback is: Any env vars that we introduce as inputs into the build adapter should be treated as a public API for other framework (adapter) authors down the road. We should make sure that this API is 1) thoroughly documented, and 2) follows our usual standards of API design including go/easy-to-use-and-hard-to-misuse (also see go/tott/523). In particular, I would recommend re-examining our current set of env vars. As of right now, we have:
It seems like some (MONOREPO_BUILDER) are not always used, while others (MONOREPO_PROJECT) can probably be removed all together. It also seems like a bug that FIREBASE_APP_DIRECTORY is only ever respected in MONOREPO contexts. IMO we should either rename it to MONOREPO_APP_DIRECTORY or always respect it. |
I wonder if our API could be simplified down to:
This gives (community) adapter authors the most flexibility as opposed to having to handle our buildpack-specific logic such as
|
MONOREPO_BUILDER is not used in the Next.js buildpack, but is necessary for the Angular buildpack. The Nx buildpack is responsible for reading project config files (i.e. project.json), which is how we determine which application builder Angular is using in an Nx monorepo (in non-Nx environments we would read the angular.json, but there is no angular.json for Nx + Angular projects). We need some way to pass the information of which app builder is being used. The alternative would be to have the adapter read Nx project config files. I do agree that MONOREPO_BUILDER is optional in many circumstances, however. This should be reflected in documentation.
In the case of Nx, this is true - the MONOREPO_PROJECT is not strictly necessary because we can simply run
We should probably always respect it to support setups where the repo root != the app root. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM pending a few small nits.
My main ask following this CL is to see if we can encapsulate all of the env var wrangling in a single nx library that can be shareable across both the angular and the next adapters
// dynamically load NextJS so this can be used in an NPX context | ||
const require = createRequire(import.meta.url); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any additional documentation we can link to in this line comment?
// fs-extra is CJS, readJson can't be imported using shorthand | ||
export const { move, exists, writeFile, readJson } = fsExtra; | ||
|
||
export async function loadConfig(cwd: string) { | ||
// The default fallback command prefix to run a build. | ||
export const DEFAULT_COMMAND = "npm"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why npm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Yuangwang might be able to provide more context, but my understanding is that we always run npm run build
in non-monorepo scenarios to run the custom build command that a user has defined as their build script. Monorepo tools can be configured to run custom build scripts if desired (https://nx.dev/nx-api/nx/executors/run-script).
Sounds good - do you mean a single monorepo library? |
Currently, the Next.js adapter is unable to specify a custom build command to run the Angular application builder. It also makes certain assumptions that no longer hold true in monorepo contexts. We adjust those conditions to enable builds of Next.js projects using monorepo tooling.