Skip to content

Commit 86431bd

Browse files
committed
refactor: build command
1 parent ccd6d49 commit 86431bd

File tree

3 files changed

+112
-229
lines changed

3 files changed

+112
-229
lines changed

packages/cli/src/commands/build.ts

Lines changed: 103 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,125 @@
1-
import { Command } from 'commander';
1+
import { build as openNextBuild } from '@opennextjs/cloudflare/cli/build/build';
2+
import { compileConfig, getNormalizedOptions } from '@opennextjs/cloudflare/cli/commands/utils';
3+
import { Command, Option } from 'commander';
24
import consola from 'consola';
35
import { execa } from 'execa';
4-
import { cp } from 'node:fs/promises';
5-
import { join, relative, sep } from 'node:path';
6-
import { addDevDependency, installDependencies, runScript } from 'nypm';
6+
import { copyFile, cp, rm, writeFile } from 'node:fs/promises';
7+
import { join } from 'node:path';
78

89
import { getModuleCliPath } from '../lib/get-module-cli-path';
9-
import { mkTempDir } from '../lib/mk-temp-dir';
10+
import { getProjectConfig } from '../lib/project-config';
11+
import { getWranglerConfig } from '../lib/wrangler-config';
1012

11-
const OPENNEXTJS_CLOUDFLARE_VERSION = '1.5.2';
1213
const WRANGLER_VERSION = '4.24.3';
1314

14-
const SKIP_DIRS = new Set([
15-
'node_modules',
16-
'.bigcommerce',
17-
'.git',
18-
'.turbo',
19-
'.next',
20-
'.vscode',
21-
'.github',
22-
'.changeset',
23-
'dist',
24-
]);
25-
26-
export function createFilter(root: string, skipDirs: Set<string>) {
27-
return (src: string) => {
28-
const rel = relative(root, src);
29-
const parts = rel.split(sep);
30-
31-
return !parts.some((part) => skipDirs.has(part));
32-
};
33-
}
34-
3515
export const build = new Command('build')
36-
.option('--keep-temp-dir', 'Keep the temporary directory after the build')
16+
.addOption(
17+
new Option(
18+
'--store-hash <hash>',
19+
'BigCommerce store hash. Can be found in the URL of your store Control Panel.',
20+
).env('BIGCOMMERCE_STORE_HASH'),
21+
)
22+
.addOption(
23+
new Option('--framework <framework>', 'The framework to use for the build').choices([
24+
'catalyst',
25+
'nextjs',
26+
]),
27+
)
28+
.option(
29+
'--project-uuid <uuid>',
30+
'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/headless/projects). Use this to link directly without fetching projects.',
31+
)
3732
.action(async (options) => {
38-
const [tmpDir, rmTempDir] = await mkTempDir('catalyst-build-');
39-
4033
try {
41-
consola.start('Copying project to temp directory...');
42-
43-
const packageManager = 'pnpm';
44-
45-
const cwd = process.cwd();
46-
const tmpCoreDir = join(tmpDir, 'core');
47-
const wranglerOutDir = join(tmpCoreDir, '.dist');
48-
const openNextOutDir = join(tmpCoreDir, '.open-next');
49-
const bigcommerceDistDir = join(cwd, '.bigcommerce', 'dist');
50-
51-
await cp(cwd, tmpDir, {
52-
recursive: true,
53-
force: true,
54-
preserveTimestamps: true,
55-
filter: createFilter(cwd, SKIP_DIRS),
56-
});
57-
58-
consola.success(`Project copied to temp directory: ${tmpDir}`);
59-
60-
consola.start('Installing dependencies...');
34+
const projectConfig = getProjectConfig();
35+
const framework = options.framework ?? projectConfig.get('framework');
36+
const projectUuid = options.projectUuid ?? projectConfig.get('projectUuid');
6137

62-
await installDependencies({
63-
cwd: tmpDir,
64-
packageManager,
65-
});
66-
67-
await addDevDependency(`@opennextjs/cloudflare@${OPENNEXTJS_CLOUDFLARE_VERSION}`, {
68-
cwd: tmpCoreDir,
69-
packageManager,
70-
});
71-
72-
consola.success('Dependencies installed');
73-
74-
consola.start('Building dependencies...');
75-
76-
await runScript('build', {
77-
cwd: join(tmpDir, 'packages', 'client'),
78-
packageManager,
79-
});
80-
81-
consola.success('Dependencies built');
82-
83-
consola.start('Copying templates...');
84-
85-
await cp(join(getModuleCliPath(), 'templates'), tmpCoreDir, {
86-
recursive: true,
87-
force: true,
88-
});
89-
90-
consola.success('Templates copied');
91-
92-
consola.start('Building project...');
38+
if (!projectUuid) {
39+
throw new Error('Project UUID is required. Please run `link` or provide `--project-uuid`');
40+
}
9341

94-
await execa('pnpm', ['exec', 'opennextjs-cloudflare', 'build'], {
95-
stdout: ['pipe', 'inherit'],
96-
cwd: tmpCoreDir,
97-
});
42+
consola.info(`Building with framework \`${framework}\`...`);
9843

99-
await execa(
100-
'pnpm',
101-
[
102-
'dlx',
103-
`wrangler@${WRANGLER_VERSION}`,
104-
'deploy',
105-
'--keep-vars',
106-
'--outdir',
107-
wranglerOutDir,
108-
'--dry-run',
109-
],
110-
{
111-
stdout: ['pipe', 'inherit'],
112-
cwd: tmpCoreDir,
113-
},
114-
);
115-
116-
consola.success('Project built');
117-
118-
consola.start('Copying build to project...');
119-
120-
await cp(wranglerOutDir, bigcommerceDistDir, {
121-
recursive: true,
122-
force: true,
123-
});
44+
if (framework === 'nextjs') {
45+
const nextBin = join(process.cwd(), 'node_modules', '.bin', 'next');
12446

125-
await cp(join(openNextOutDir, 'assets'), join(bigcommerceDistDir, 'assets'), {
126-
recursive: true,
127-
force: true,
128-
});
47+
consola.start('Running `next build`...');
48+
await execa(nextBin, ['build']);
49+
consola.success('Next.js build completed');
50+
}
12951

130-
consola.success('Build copied to project');
52+
if (framework === 'catalyst') {
53+
consola.start('Running `catalyst build`...');
54+
55+
// @todo get KV namespace from Ignition?
56+
const wranglerConfig = getWranglerConfig(projectUuid, 'placeholder-kv-namespace-id');
57+
58+
await copyFile(
59+
join(getModuleCliPath(), 'templates', 'open-next.config.ts'),
60+
join(process.cwd(), 'open-next.config.ts'),
61+
);
62+
await writeFile(
63+
join(process.cwd(), '.bigcommerce', 'wrangler.jsonc'),
64+
JSON.stringify(wranglerConfig, null, 2),
65+
);
66+
67+
const { config: openNextConfig, buildDir } = await compileConfig();
68+
const openNextBuildOptions = getNormalizedOptions(openNextConfig, buildDir);
69+
70+
await openNextBuild(
71+
openNextBuildOptions,
72+
openNextConfig,
73+
{
74+
sourceDir: process.cwd(),
75+
skipNextBuild: false,
76+
skipWranglerConfigCheck: true,
77+
minify: false,
78+
},
79+
// @ts-expect-error - @todo fix types, @opennextjs/cloudflare does not export the type
80+
wranglerConfig,
81+
);
82+
83+
consola.success('Catalyst build completed');
84+
consola.start('Compiling build for deployment...');
85+
86+
await execa(
87+
'pnpm',
88+
[
89+
'dlx',
90+
`wrangler@${WRANGLER_VERSION}`,
91+
'deploy',
92+
'--config',
93+
join(process.cwd(), '.bigcommerce', 'wrangler.jsonc'),
94+
'--keep-vars',
95+
'--outdir',
96+
join(process.cwd(), '.bigcommerce', 'dist'),
97+
'--dry-run',
98+
],
99+
{
100+
stdout: ['pipe', 'inherit'],
101+
cwd: process.cwd(),
102+
},
103+
);
104+
105+
await cp(
106+
join(process.cwd(), '.open-next', 'assets'),
107+
join(process.cwd(), '.bigcommerce', 'dist', 'assets'),
108+
{
109+
recursive: true,
110+
force: true,
111+
},
112+
);
113+
114+
consola.success('Build compiled and ready for deployment');
115+
}
131116
} catch (error) {
132117
consola.error(error);
133118
process.exitCode = 1;
134119
} finally {
135-
if (!options.keepTempDir) {
136-
await rmTempDir();
137-
}
120+
await rm(join(process.cwd(), 'open-next.config.ts')).catch(() => {
121+
// noop to silence ENOENT error
122+
});
138123

139124
process.exit();
140125
}

packages/cli/templates/open-next.config.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// @ts-nocheck
21
import { defineCloudflareConfig } from '@opennextjs/cloudflare';
32
import { purgeCache } from '@opennextjs/cloudflare/overrides/cache-purge/index';
43
import kvIncrementalCache from '@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache';
54
import doQueue from '@opennextjs/cloudflare/overrides/queue/do-queue';
65
import queueCache from '@opennextjs/cloudflare/overrides/queue/queue-cache';
76
import doShardedTagCache from '@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache';
7+
import { type OpenNextConfig } from '@opennextjs/cloudflare';
88

9-
export default defineCloudflareConfig({
9+
const cloudflareConfig = defineCloudflareConfig({
1010
incrementalCache: kvIncrementalCache,
1111
queue: queueCache(doQueue, {
1212
regionalCacheTtlSec: 5,
@@ -27,3 +27,10 @@ export default defineCloudflareConfig({
2727
enableCacheInterception: false,
2828
cachePurge: purgeCache({ type: 'durableObject' }),
2929
});
30+
31+
const config: OpenNextConfig = {
32+
buildCommand: 'node_modules/.bin/next build',
33+
...cloudflareConfig,
34+
};
35+
36+
export default config;

packages/cli/tests/commands/build.spec.ts

Lines changed: 0 additions & 109 deletions
This file was deleted.

0 commit comments

Comments
 (0)