Skip to content

Commit 97ace8e

Browse files
committed
refactor: run build directly on core
1 parent 18e8e09 commit 97ace8e

File tree

4 files changed

+3744
-250
lines changed

4 files changed

+3744
-250
lines changed

packages/cli/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,8 @@
4747
"tsup": "^8.5.0",
4848
"typescript": "^5.8.3",
4949
"vitest": "^3.2.4"
50+
},
51+
"peerDependencies": {
52+
"@opennextjs/cloudflare": "^1.6.5"
5053
}
5154
}

packages/cli/src/commands/build.ts

Lines changed: 10 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,29 @@ import { Command, Option } from 'commander';
22
import consola from 'consola';
33
import { execa } from 'execa';
44
import { cp } from 'node:fs/promises';
5-
import { join, relative, sep } from 'node:path';
5+
import { join } from 'node:path';
66

77
import { getModuleCliPath } from '../lib/get-module-cli-path';
8-
import { mkTempDir } from '../lib/mk-temp-dir';
98

109
const WRANGLER_VERSION = '4.24.3';
1110

12-
const SKIP_DIRS = new Set([
13-
'node_modules',
14-
'.bigcommerce',
15-
'.git',
16-
'.turbo',
17-
'.next',
18-
'.vscode',
19-
'.github',
20-
'.changeset',
21-
'dist',
22-
]);
23-
24-
export function createFilter(root: string, skipDirs: Set<string>) {
25-
return (src: string) => {
26-
const rel = relative(root, src);
27-
const parts = rel.split(sep);
28-
29-
return !parts.some((part) => skipDirs.has(part));
30-
};
31-
}
32-
3311
export const build = new Command('build')
34-
.option('--keep-temp-dir', 'Keep the temporary directory after the build')
3512
.option('--project-uuid <uuid>', 'Project UUID to be included in the deployment configuration.')
3613
.addOption(
3714
new Option('--framework <framework>', 'The framework to use for the build.').choices([
3815
'nextjs',
3916
'catalyst',
4017
]),
4118
)
42-
.action(async (options) => {
43-
const [tmpDir, rmTempDir] = await mkTempDir('catalyst-build-');
44-
19+
.action(async () => {
4520
try {
46-
consola.start('Copying project to temp directory...');
47-
48-
const cwd = process.cwd();
49-
const tmpCoreDir = join(tmpDir, 'core');
50-
const wranglerOutDir = join(tmpCoreDir, '.dist');
51-
const openNextOutDir = join(tmpCoreDir, '.open-next');
52-
const bigcommerceDistDir = join(cwd, '.bigcommerce', 'dist');
53-
54-
await cp(cwd, tmpDir, {
55-
recursive: true,
56-
force: true,
57-
preserveTimestamps: true,
58-
filter: createFilter(cwd, SKIP_DIRS),
59-
});
60-
61-
consola.success(`Project copied to temp directory: ${tmpDir}`);
21+
const coreDir = process.cwd();
22+
const openNextOutDir = join(coreDir, '.open-next');
23+
const bigcommerceDistDir = join(coreDir, '.bigcommerce', 'dist');
6224

6325
consola.start('Copying templates...');
6426

65-
await cp(join(getModuleCliPath(), 'templates'), tmpCoreDir, {
27+
await cp(join(getModuleCliPath(), 'templates'), coreDir, {
6628
recursive: true,
6729
force: true,
6830
});
@@ -73,7 +35,7 @@ export const build = new Command('build')
7335

7436
await execa('pnpm', ['exec', 'opennextjs-cloudflare', 'build'], {
7537
stdout: ['pipe', 'inherit'],
76-
cwd: tmpCoreDir,
38+
cwd: coreDir,
7739
});
7840

7941
await execa(
@@ -84,38 +46,23 @@ export const build = new Command('build')
8446
'deploy',
8547
'--keep-vars',
8648
'--outdir',
87-
wranglerOutDir,
49+
bigcommerceDistDir,
8850
'--dry-run',
8951
],
9052
{
9153
stdout: ['pipe', 'inherit'],
92-
cwd: tmpCoreDir,
54+
cwd: coreDir,
9355
},
9456
);
9557

9658
consola.success('Project built');
9759

98-
consola.start('Copying build to project...');
99-
100-
await cp(wranglerOutDir, bigcommerceDistDir, {
101-
recursive: true,
102-
force: true,
103-
});
104-
10560
await cp(join(openNextOutDir, 'assets'), join(bigcommerceDistDir, 'assets'), {
10661
recursive: true,
10762
force: true,
10863
});
109-
110-
consola.success('Build copied to project');
11164
} catch (error) {
11265
consola.error(error);
113-
process.exitCode = 1;
114-
} finally {
115-
if (!options.keepTempDir) {
116-
await rmTempDir();
117-
}
118-
119-
process.exit();
66+
process.exit(1);
12067
}
12168
});
Lines changed: 2 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,15 @@
11
import { Command } from 'commander';
2-
import consola from 'consola';
3-
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
2+
import { expect, test } from 'vitest';
43

5-
import { build, createFilter } from '../../src/commands/build';
6-
import { program } from '../../src/program';
7-
8-
const cleanup = vi.fn();
9-
10-
beforeAll(() => {
11-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
12-
vi.spyOn(process, 'exit').mockImplementation(() => null as never);
13-
14-
consola.wrapAll();
15-
16-
vi.mock('../../src/lib/mk-temp-dir', () => ({
17-
mkTempDir: vi.fn(() => ['/tmp/test', cleanup]),
18-
}));
19-
20-
vi.mock('node:fs/promises', () => ({
21-
cp: vi.fn(),
22-
}));
23-
24-
vi.mock('execa', () => ({
25-
execa: vi.fn(),
26-
}));
27-
});
28-
29-
beforeEach(() => {
30-
consola.mockTypes(() => vi.fn());
31-
});
32-
33-
afterEach(() => {
34-
vi.clearAllMocks();
35-
});
36-
37-
afterAll(() => {
38-
vi.restoreAllMocks();
39-
});
4+
import { build } from '../../src/commands/build';
405

416
test('properly configured Command instance', () => {
427
expect(build).toBeInstanceOf(Command);
438
expect(build.name()).toBe('build');
449
expect(build.options).toEqual(
4510
expect.arrayContaining([
46-
expect.objectContaining({ long: '--keep-temp-dir' }),
4711
expect.objectContaining({ long: '--framework' }),
4812
expect.objectContaining({ long: '--project-uuid' }),
4913
]),
5014
);
5115
});
52-
53-
test('does not remove temp dir if --keep-temp-dir is passed', async () => {
54-
await program.parseAsync(['node', 'catalyst', 'build', '--keep-temp-dir']);
55-
expect(cleanup).not.toHaveBeenCalled();
56-
});
57-
58-
test('removes temp dir if --keep-temp-dir is not passed', async () => {
59-
await program.parseAsync(['node', 'catalyst', 'build']);
60-
expect(cleanup).toHaveBeenCalled();
61-
});
62-
63-
test('successfully builds project', async () => {
64-
await program.parseAsync(['node', 'catalyst', 'build']);
65-
66-
expect(consola.success).toHaveBeenCalledWith('Project built');
67-
expect(consola.success).toHaveBeenCalledWith('Build copied to project');
68-
});
69-
70-
test('handles error if cp throws during build', async () => {
71-
// Dynamically mock cp for this test only
72-
// eslint-disable-next-line import/dynamic-import-chunkname
73-
const cpModule = await import('node:fs/promises');
74-
const originalCp = cpModule.cp;
75-
const cpMock = vi.fn(() => {
76-
throw new Error('cp failed');
77-
});
78-
79-
cpModule.cp = cpMock;
80-
81-
await program.parseAsync(['node', 'catalyst', 'build']);
82-
83-
expect(consola.error).toHaveBeenCalledWith(expect.any(Error));
84-
85-
cpModule.cp = originalCp;
86-
});
87-
88-
describe('createFilter', () => {
89-
const ROOT = '/my/project';
90-
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist']);
91-
92-
const filter = createFilter(ROOT, SKIP_DIRS);
93-
94-
test('allows files not in skip list', () => {
95-
expect(filter('/my/project/src/index.ts')).toBe(true);
96-
});
97-
98-
test('skips files inside a skipped directory', () => {
99-
expect(filter('/my/project/node_modules/lodash/index.js')).toBe(false);
100-
expect(filter('/my/project/.git/config')).toBe(false);
101-
expect(filter('/my/project/dist/main.js')).toBe(false);
102-
});
103-
104-
test('handles nested skipped folders', () => {
105-
expect(filter('/my/project/src/node_modules/whatever.js')).toBe(false);
106-
});
107-
});

0 commit comments

Comments
 (0)