Skip to content

refactor: run build directly on catalyst core application#2517

Closed
matthewvolk wants to merge 5 commits intocanaryfrom
build-refactor
Closed

refactor: run build directly on catalyst core application#2517
matthewvolk wants to merge 5 commits intocanaryfrom
build-refactor

Conversation

@matthewvolk
Copy link
Copy Markdown
Contributor

@matthewvolk matthewvolk commented Aug 11, 2025

What/Why?

Previously, build was running inside of a temporary directory in an effort to abstract away Cloudflare-related configuration files (wrangler.jsonc, open-next.config.ts) and dependencies (@opennextjs/cloudflare). The only artifact that we copied from this temporary directory back into the original Catalyst project was a single worker.js file.

Unfortunately, we discovered that the opennextjs-cloudflare preview command needs access to some of the intermediary files that were being deleted when the temporary folder was deleted at the end of build. So, we had to change course. We are now installing Cloudflare-related dependencies in the CLI (instead of core) and using an esbuild plugin to resolve imports pointing to these dependencies. To make this work, we had to resort to patching @opennextjs/cloudflare, but have started a conversation with Cloudflare to see if we can more reliable support.

Testing

Updated test suite

Migration

N/A

JIRA: CATALYST-1421

@matthewvolk matthewvolk requested a review from a team August 11, 2025 22:14
@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 11, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
catalyst-b2b Error Error Aug 18, 2025 9:41pm
catalyst-canary Error Error Aug 18, 2025 9:41pm
3 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
catalyst Ignored Ignored Aug 18, 2025 9:41pm
catalyst-au Ignored Ignored Aug 18, 2025 9:41pm
catalyst-uk Ignored Ignored Aug 18, 2025 9:41pm

Comment thread packages/cli/src/commands/build/opennext-build.ts
Comment thread packages/cli/package.json
Comment thread packages/cli/src/commands/build/action.ts Outdated
Comment thread core/package.json Outdated
Comment thread packages/cli/src/commands/build/action.ts Outdated
Comment thread packages/cli/src/commands/build/action.ts
Comment thread packages/cli/src/commands/build/action.ts
}),
};

const wranglerConfig = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we moving away from templates then? For preview, I need to create a copy of wranger.jsonc too and want to make sure we have one source of truth.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not opinionated on this, and I agree that my only requirement is that we have a single source of truth. If we want, I can read wrangler.jsonc from fs, and pass that to the build function from OpenNext... keep in mind, we also need to modify certain fields in wrangler.jsonc, so maybe we make a lib function to handle reading/writing/etc. the file. The file can have the config as an object, and then methods to write to wrangler.jsonc using fs, both using the same object as a source of truth?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine either way by me, just feel like we should delete the other templates if we're not using them?

Comment thread packages/cli/src/commands/build/opennext-build.ts Outdated
return createConsola({ level: options.verbose ? LogLevels.verbose : LogLevels.info });
}

export function createExec(options: BuildCommandOptions, exec: Exec = _execa) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if these abstraction are worth it, can you provide your reasoning? Maybe they need to be lib utilities?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm cool with lib utils - I'm trying to follow some of the principles in this article, so this abstraction does a couple things:

  1. Helps asserts behavior (“verbose uses inherit”), not which process lib (execa, child_process, etc.) we called.
  2. It also encodes the --verbose policy on exec in a single place. Other commands can use createExec and get --verbose logging options for free. No drift across different call sites.

If you still think it's too early of an abstraction, let's discuss; I'm not set in stone by any means, and open to inlining it if you think it's better

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Been thinking about this all day.

  1. How are you asserting the behavior? Just curious, seems to be it would look the same with or without the abstraction. I understand we don't want to test implementation details, only outputs, but how do we test the output of the command?
  2. I agree, but thinking about start as an example, we wouldn't really want to hide it away, thinking this is only required here for the moment?

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Aug 12, 2025

⚠️ No Changeset found

Latest commit: aa41902

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

💥 An error occurred when fetching the changed packages and changesets in this PR
Some errors occurred when validating the changesets config:
The package "@bigcommerce/catalyst-core" depends on the ignored package "@bigcommerce/catalyst", but "@bigcommerce/catalyst-core" is not being ignored. Please add "@bigcommerce/catalyst-core" to the `ignore` option.

}),
};

const wranglerConfig = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine either way by me, just feel like we should delete the other templates if we're not using them?

};

export function resolveFramework(options: Options, getConfig: Config, logger: Logger) {
const config = getConfig();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing rootDir being passed to this function.

Which brings up another talking point, do we care about the rootDir option for commands? I know some of them have it, others don't. For my tests, adding this rootDir option was valuable.

import { getProjectConfig } from '../../lib/project-config';
import { resolveFramework } from '../../lib/resolve-framework';

import { opennextBuild } from './opennext-build';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openNextBuild or opennextBuild? 🤔

return createConsola({ level: options.verbose ? LogLevels.verbose : LogLevels.info });
}

export function createExec(options: BuildCommandOptions, exec: Exec = _execa) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Been thinking about this all day.

  1. How are you asserting the behavior? Just curious, seems to be it would look the same with or without the abstraction. I understand we don't want to test implementation details, only outputs, but how do we test the output of the command?
  2. I agree, but thinking about start as an example, we wouldn't really want to hide it away, thinking this is only required here for the moment?


try {
const openNextConfig = {
buildCommand: 'dotenv -e .env.local -- node ./scripts/generate.cjs && next build',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
buildCommand: 'dotenv -e .env.local -- node ./scripts/generate.cjs && next build',
buildCommand: 'next build',

`wrangler@${WRANGLER_VERSION}`,
'deploy',
'--config',
join(process.cwd(), '.bigcommerce', 'wrangler.jsonc'),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is process.cwd() necessary since we define the cwd below?

@matthewvolk
Copy link
Copy Markdown
Contributor Author

Fixed by #2527

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants