Skip to content

Commit 7a49c8b

Browse files
committed
rewrite build system to not have to run npm install
1 parent e3fc0c9 commit 7a49c8b

File tree

3 files changed

+56
-72
lines changed

3 files changed

+56
-72
lines changed

packages/react-email/src/commands/build.ts

Lines changed: 54 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { registerSpinnerAutostopping } from '../utils/register-spinner-autostopp
1212

1313
interface Args {
1414
dir: string;
15-
packageManager: string;
15+
packageManager?: string;
1616
}
1717

1818
const buildPreviewApp = (absoluteDirectory: string) => {
@@ -38,47 +38,15 @@ const buildPreviewApp = (absoluteDirectory: string) => {
3838
});
3939
};
4040

41-
const npmInstall = async (
42-
builtPreviewAppPath: string,
43-
packageManager: string,
44-
) => {
45-
return new Promise<void>((resolve, reject) => {
46-
const childProc = spawn(
47-
packageManager,
48-
[
49-
'install',
50-
packageManager === 'deno' ? '' : '--include=dev',
51-
packageManager === 'deno' ? '--quiet' : '--silent',
52-
],
53-
{
54-
cwd: builtPreviewAppPath,
55-
shell: true,
56-
},
57-
);
58-
childProc.stdout.pipe(process.stdout);
59-
childProc.stderr.pipe(process.stderr);
60-
childProc.on('close', (code) => {
61-
if (code === 0) {
62-
resolve();
63-
} else {
64-
reject(
65-
new Error(
66-
`Unable to install the dependencies and it exited with code: ${code}`,
67-
),
68-
);
69-
}
70-
});
71-
});
72-
};
73-
7441
const setNextEnvironmentVariablesForBuild = async (
7542
emailsDirRelativePath: string,
76-
builtPreviewAppPath: string,
43+
userProjectPath: string,
44+
modifiedPreviewAppPath: string,
7745
) => {
7846
const nextConfigContents = `
7947
const path = require('path');
8048
const emailsDirRelativePath = path.normalize('${emailsDirRelativePath}');
81-
const userProjectLocation = '${process.cwd()}';
49+
const userProjectLocation = '${userProjectPath}';
8250
/** @type {import('next').NextConfig} */
8351
module.exports = {
8452
env: {
@@ -111,7 +79,7 @@ module.exports = {
11179
}`;
11280

11381
await fs.promises.writeFile(
114-
path.resolve(builtPreviewAppPath, './next.config.js'),
82+
path.resolve(modifiedPreviewAppPath, './next.config.js'),
11583
nextConfigContents,
11684
'utf8',
11785
);
@@ -203,19 +171,9 @@ const updatePackageJson = async (builtPreviewAppPath: string) => {
203171
};
204172
packageJson.scripts.build = 'next build';
205173
packageJson.scripts.start = 'next start';
206-
delete packageJson.scripts.postbuild;
207174

208175
packageJson.name = 'preview-server';
209176

210-
// We remove this one to avoid having resolve issues on our demo build process.
211-
// This is only used in the `export` command so it's irrelevant to have it here.
212-
//
213-
// See `src/actions/render-email-by-path` for more info on how we render the
214-
// email templates without `@react-email/render` being installed.
215-
delete packageJson.devDependencies['@react-email/render'];
216-
delete packageJson.devDependencies['@react-email/components'];
217-
delete packageJson.scripts.prepare;
218-
219177
await fs.promises.writeFile(
220178
packageJsonPath,
221179
JSON.stringify(packageJson),
@@ -227,6 +185,12 @@ export const build = async ({
227185
dir: emailsDirRelativePath,
228186
packageManager,
229187
}: Args) => {
188+
if (packageManager !== undefined) {
189+
console.warn(
190+
'The --packageManager flag is deprecated and is currently ignored. It will be removed in the next major version',
191+
);
192+
}
193+
230194
try {
231195
const previewServerLocation = await getPreviewServerLocation();
232196

@@ -244,61 +208,81 @@ export const build = async ({
244208
const emailsDirPath = path.join(process.cwd(), emailsDirRelativePath);
245209
const staticPath = path.join(emailsDirPath, 'static');
246210

211+
const modifiedPreviewAppPath = path.resolve(
212+
previewServerLocation,
213+
'../.react-email',
214+
);
215+
if (fs.existsSync(modifiedPreviewAppPath)) {
216+
spinner.text = 'Deleting pre-existing modified preview app folder';
217+
await fs.promises.rm(modifiedPreviewAppPath, { recursive: true });
218+
}
247219
const builtPreviewAppPath = path.join(process.cwd(), '.react-email');
248-
249220
if (fs.existsSync(builtPreviewAppPath)) {
250-
spinner.text = 'Deleting pre-existing `.react-email` folder';
221+
spinner.text = 'Deleting pre-existing .react-email folder';
251222
await fs.promises.rm(builtPreviewAppPath, { recursive: true });
252223
}
253224

254-
spinner.text = 'Copying preview app from CLI to `.react-email`';
255-
await fs.promises.cp(previewServerLocation, builtPreviewAppPath, {
225+
spinner.text = 'Copying preview app from CLI to modify it';
226+
await fs.promises.cp(previewServerLocation, modifiedPreviewAppPath, {
256227
recursive: true,
257228
filter: (source: string) => {
258-
// do not copy the CLI files
259229
return (
260230
!/(\/|\\)cli(\/|\\)?/.test(source) &&
261231
!/(\/|\\)\.next(\/|\\)?/.test(source) &&
262-
!/(\/|\\)\.turbo(\/|\\)?/.test(source) &&
263-
!/(\/|\\)node_modules(\/|\\)?$/.test(source)
232+
!/(\/|\\)\.turbo(\/|\\)?/.test(source)
264233
);
265234
},
266235
});
267236

268237
if (fs.existsSync(staticPath)) {
269-
spinner.text =
270-
'Copying `static` folder into `.react-email/public/static`';
271-
const builtStaticDirectory = path.resolve(
272-
builtPreviewAppPath,
238+
spinner.text = 'Copying static directory';
239+
const modifiedPreviewAppStaticDirectory = path.resolve(
240+
modifiedPreviewAppPath,
273241
'./public/static',
274242
);
275-
await fs.promises.cp(staticPath, builtStaticDirectory, {
243+
await fs.promises.cp(staticPath, modifiedPreviewAppStaticDirectory, {
276244
recursive: true,
277245
});
278246
}
279247

280-
spinner.text =
281-
'Setting Next environment variables for preview app to work properly';
248+
spinner.text = 'Setting Next environment variables';
282249
await setNextEnvironmentVariablesForBuild(
283250
emailsDirRelativePath,
284-
builtPreviewAppPath,
251+
process.cwd(),
252+
modifiedPreviewAppPath,
285253
);
286254

287-
spinner.text = 'Setting server side generation for the email preview pages';
288-
await forceSSGForEmailPreviews(emailsDirPath, builtPreviewAppPath);
255+
spinner.text = 'Setting up server side generation';
256+
await forceSSGForEmailPreviews(emailsDirPath, modifiedPreviewAppPath);
289257

290258
spinner.text = "Updating package.json's build and start scripts";
291-
await updatePackageJson(builtPreviewAppPath);
292-
293-
spinner.text = 'Installing dependencies on `.react-email`';
294-
await npmInstall(builtPreviewAppPath, packageManager);
259+
await updatePackageJson(modifiedPreviewAppPath);
295260

296261
spinner.stopAndPersist({
297-
text: 'Successfully prepared `.react-email` for `next build`',
262+
text: 'Ready for next build',
298263
symbol: logSymbols.success,
299264
});
265+
await buildPreviewApp(modifiedPreviewAppPath);
300266

301-
await buildPreviewApp(builtPreviewAppPath);
267+
await fs.promises.mkdir(builtPreviewAppPath);
268+
await fs.promises.cp(
269+
path.join(modifiedPreviewAppPath, '.next'),
270+
path.join(builtPreviewAppPath, '.next'),
271+
{
272+
recursive: true,
273+
},
274+
);
275+
await fs.promises.cp(
276+
path.join(modifiedPreviewAppPath, 'public'),
277+
path.join(builtPreviewAppPath, 'public'),
278+
{
279+
recursive: true,
280+
},
281+
);
282+
283+
await fs.promises.rm(modifiedPreviewAppPath, {
284+
recursive: true,
285+
});
302286
} catch (error) {
303287
console.log(error);
304288
process.exit(1);

packages/react-email/src/commands/start.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const start = async () => {
2121

2222
const nextStart = spawn('npx', ['next', 'start', builtPreviewPath], {
2323
cwd: previewServerLocation,
24+
shell: true,
2425
stdio: 'inherit',
2526
});
2627

packages/react-email/src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ program
2626
.option('-d, --dir <path>', 'Directory with your email templates', './emails')
2727
.option(
2828
'-p --packageManager <name>',
29-
'Package name to use on installation on `.react-email`',
30-
'npm',
29+
'Package manager to use when installing in .react-email (deprecated)',
3130
)
3231
.action(build);
3332

0 commit comments

Comments
 (0)