Skip to content

Commit a0023b3

Browse files
committed
fix(jsx-email): rollback the watcher to only watch entrypoint directories
1 parent 4f0fac9 commit a0023b3

File tree

3 files changed

+243
-55
lines changed

3 files changed

+243
-55
lines changed

packages/jsx-email/src/cli/watcher.mts

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -33,62 +33,96 @@ const removeChildPaths = (paths: string[]): string[] =>
3333
(p1) => !paths.some((p2) => p1 !== p2 && relative(p2, p1) && !relative(p2, p1).startsWith('..'))
3434
);
3535

36-
const mapDeps = async (files: BuildTempatesResult[]) => {
37-
const depPaths: string[] = [];
38-
const metaReads = files.map(async ({ metaPath }) => {
36+
const getEntrypoints = async (files: BuildTempatesResult[]) => {
37+
const entrypoints: Set<string> = new Set();
38+
const promises = files.map(async ({ metaPath }) => {
3939
log.debug({ exists: await exists(metaPath ?? ''), metaPath });
4040

4141
if (!metaPath || !(await exists(metaPath))) return null;
4242
const contents = await readFile(metaPath, 'utf-8');
4343
const metafile = JSON.parse(contents) as Metafile;
44-
const { outputs } = metafile;
45-
const result = new Map<string, Set<string>>();
46-
47-
Object.entries(outputs).forEach(([_, meat]) => {
48-
const { entryPoint, inputs } = meat;
49-
const resolvedEntry = resolve(originalCwd, entryPoint!);
50-
depPaths.push(resolvedEntry);
51-
52-
for (const dep of Object.keys(inputs)) {
53-
const resolvedDepPath = resolve(originalCwd, dep);
54-
const set = result.get(resolvedDepPath) ?? new Set();
55-
56-
depPaths.push(resolvedDepPath);
57-
set.add(resolvedEntry);
58-
result.set(resolvedDepPath, set);
59-
}
44+
45+
Object.entries(metafile.outputs).forEach(([_, { entryPoint }]) => {
46+
entrypoints.add(resolve(originalCwd, entryPoint!));
6047
});
6148

62-
return result;
49+
return null;
6350
});
64-
const deps = (await Promise.all(metaReads)).filter(Boolean);
6551

66-
return { depPaths, deps };
52+
await Promise.all(promises);
53+
54+
log.debug({ entrypoints });
55+
56+
return Array.from(entrypoints).filter(Boolean);
57+
};
58+
59+
const getWatchPaths = async (files: BuildTempatesResult[]) => {
60+
const entrypoints = await getEntrypoints(files);
61+
const paths = entrypoints.map((path) => dirname(path));
62+
const uniquePaths = Array.from(new Set(paths));
63+
const watchPaths = removeChildPaths(uniquePaths);
64+
65+
log.debug({ watchPaths });
66+
67+
return watchPaths;
6768
};
6869

70+
// const mapDeps = async (files: BuildTempatesResult[]) => {
71+
// const depPaths: string[] = [];
72+
// const metaReads = files.map(async ({ metaPath }) => {
73+
// log.debug({ exists: await exists(metaPath ?? ''), metaPath });
74+
75+
// if (!metaPath || !(await exists(metaPath))) return null;
76+
// const contents = await readFile(metaPath, 'utf-8');
77+
// const metafile = JSON.parse(contents) as Metafile;
78+
// const { outputs } = metafile;
79+
// const result = new Map<string, Set<string>>();
80+
81+
// Object.entries(outputs).forEach(([_, meat]) => {
82+
// const { entryPoint, inputs } = meat;
83+
// const resolvedEntry = resolve(originalCwd, entryPoint!);
84+
// depPaths.push(resolvedEntry);
85+
86+
// for (const dep of Object.keys(inputs)) {
87+
// const resolvedDepPath = resolve(originalCwd, dep);
88+
// const set = result.get(resolvedDepPath) ?? new Set();
89+
90+
// depPaths.push(resolvedDepPath);
91+
// set.add(resolvedEntry);
92+
// result.set(resolvedDepPath, set);
93+
// }
94+
// });
95+
96+
// return result;
97+
// });
98+
// const deps = (await Promise.all(metaReads)).filter(Boolean);
99+
100+
// return { depPaths, deps };
101+
// };
102+
69103
export const watch = async (args: WatchArgs) => {
70104
newline();
71105
log.info(chalk`{blue Starting watcher...}\n`);
72106

73107
const { common, files, server } = args;
74108
const { argv } = common;
75109
const extensions = ['.css', '.js', '.jsx', '.ts', '.tsx'];
110+
const watchPaths = await getWatchPaths(files);
76111

77-
const { depPaths, deps: metaDeps } = await mapDeps(files);
78-
const templateDeps = new Map<string, Set<string>>();
112+
// const { depPaths, deps: metaDeps } = await mapDeps(files);
113+
// const templateDeps = new Map<string, Set<string>>();
79114

80-
for (const map of metaDeps) {
81-
map!.forEach((value, key) => templateDeps.set(key, value));
82-
}
115+
// for (const map of metaDeps) {
116+
// map!.forEach((value, key) => templateDeps.set(key, value));
117+
// }
83118

84119
const handler: watcher.SubscribeCallback = async (_, events) => {
85120
const changedFiles = events
86121
.filter((event) => event.type !== 'create' && event.type !== 'delete')
87122
.map((e) => e.path)
88123
.filter((path) => extensions.includes(extname(path)));
89-
const changedTemplates = changedFiles
90-
.flatMap((file) => [...(templateDeps.get(file) || [])])
91-
.filter(Boolean);
124+
const templateFileNames = files.map((file) => file.fileName);
125+
const changedTemplates = changedFiles.filter((file) => templateFileNames.includes(file));
92126
const createdFiles = events
93127
.filter((event) => event.type === 'create')
94128
.map((e) => e.path)
@@ -129,7 +163,7 @@ export const watch = async (args: WatchArgs) => {
129163
log.info(
130164
chalk`{cyan Building}`,
131165
createdFiles.length,
132-
`file${changedTemplates.length === 1 ? '' : 's'}:\n `,
166+
`file${createdFiles.length === 1 ? '' : 's'}:\n `,
133167
createdFiles.join('\n '),
134168
'\n'
135169
);
@@ -166,10 +200,10 @@ export const watch = async (args: WatchArgs) => {
166200
});
167201
};
168202

169-
const watchPathSet = new Set([
170-
...depPaths.filter((path) => !path.includes('/node_modules/')).map((path) => dirname(path))
171-
]);
172-
const watchPaths = removeChildPaths([...watchPathSet]);
203+
// const watchPathSet = new Set([
204+
// ...depPaths.filter((path) => !path.includes('/node_modules/')).map((path) => dirname(path))
205+
// ]);
206+
// const watchPaths = removeChildPaths([...watchPathSet]);
173207

174208
log.debug('Watching Paths:', watchPaths.sort());
175209

test/smoke/tests/.snapshots/smoke.test.ts-watcher-chromium.snap

Lines changed: 169 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,178 @@
55
xmlns:v="urn:schemas-microsoft-com:vml"
66
>
77
<head>
8+
<meta
9+
name="color-scheme"
10+
content="normal"
11+
>
12+
<meta
13+
name="supported-color-schemes"
14+
content="normal"
15+
>
16+
<style>
17+
:root {
18+
color-scheme: normal;
19+
supported-color-schemes: normal;
20+
}
21+
</style>
22+
<meta
23+
http-equiv="Content-Type"
24+
content="text/html; charset=UTF-8"
25+
>
26+
<meta
27+
name="viewport"
28+
content="width=device-width, initial-scale=1, user-scalable=yes"
29+
>
30+
<meta name="x-apple-disable-message-reformatting">
31+
<meta
32+
name="format-detection"
33+
content="telephone=no, date=no, address=no, email=no, url=no"
34+
>
35+
<meta
36+
name="viewport"
37+
content="width=device-width, initial-scale=1, user-scalable=yes"
38+
>
39+
<meta name="x-apple-disable-message-reformatting">
40+
<meta
41+
name="format-detection"
42+
content="telephone=no, date=no, address=no, email=no, url=no"
43+
>
44+
<style>
45+
@font-face {
46+
font-family: 'Roboto';
47+
font-style: normal;
48+
font-weight: 400;
49+
mso-font-alt: 'Verdana';
50+
src: url(https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2) format('woff2');
51+
}
52+
53+
* {
54+
font-family: 'Roboto', Verdana;
55+
}
56+
</style>
857
</head>
958
<body>
59+
<!--[if mso]><meta content="batman"/><![endif]-->
60+
<!--[if mso]><xml><o:OfficeDocumentSettings><o:AllowPNG></o:AllowPNG><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]-->
61+
<div
62+
data-skip="true"
63+
style="display:none;line-height:1px;max-height:0;max-width:0;opacity:0;overflow:hidden"
64+
>
65+
Preview Content
66+
<div>
67+
&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏&nbsp;‌​‍‎‏
68+
</div>
69+
</div>
1070
<p style="font-size:14px;line-height:24px;margin:16px 0">
11-
component batman
71+
component test
1272
</p>
13-
<img
14-
id="image"
15-
alt="Cat"
16-
src="/static/cat.jpeg"
17-
width="200"
18-
height="200"
19-
style="border:none;display:block;outline:none;text-decoration:none"
20-
>
21-
<a
22-
href="/static/cat.jpeg"
23-
style="color:#067df7;text-decoration:none"
24-
>
25-
/static/cat.jpeg
26-
</a>
73+
<div style="table-layout:fixed;width:100%">
74+
<div style="margin:0 auto;max-width:600px">
75+
<span>
76+
<!--[if mso]><table align="center" width="600" style="border-spacing: 0; width:600px;" role="presentation"><tr><td><![endif]-->
77+
</span>
78+
<table
79+
align="center"
80+
width="100%"
81+
role="presentation"
82+
cellspacing="0"
83+
cellpadding="0"
84+
border="0"
85+
style="max-width:600px"
86+
>
87+
<tbody>
88+
<tr style="width:100%">
89+
<td align="center">
90+
<table
91+
align="center"
92+
width="100%"
93+
border="0"
94+
cellpadding="0"
95+
cellspacing="0"
96+
role="presentation"
97+
>
98+
<tbody>
99+
<tr>
100+
<td>
101+
<table
102+
width="100%"
103+
border="0"
104+
cellpadding="0"
105+
cellspacing="0"
106+
style="border-collapse:collapse"
107+
role="presentation"
108+
>
109+
<tbody>
110+
<tr>
111+
<td align="left">
112+
<span>
113+
<!--[if mso]>
114+
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" style="height:40px;v-text-anchor:middle;width:200px;" arcsize="0%" strokeweight="1px" fillcolor=#FFFFFF>
115+
<w:anchorlock/>
116+
<center style="font-size:16px;color:#000000;">
117+
Button Content
118+
</center></v:roundrect>
119+
<![endif]-->
120+
</span>
121+
<a
122+
href="https://jsx.email"
123+
style="-webkit-text-size-adjust:none;border-radius:0;display:inline-block;font-size:16px;line-height:38px;max-width:200px;text-align:center;text-decoration:none;width:100%;background-color:#FFFFFF;color:#000000;mso-hide:all"
124+
>
125+
Button Content
126+
</a>
127+
</td>
128+
</tr>
129+
</tbody>
130+
</table>
131+
<h1 style>
132+
Heading Content
133+
</h1>
134+
<hr style="border:none;border-top:1px solid #eaeaea;width:100%">
135+
<img
136+
src="https://about.google/assets-main/img/glue-google-solid-logo.svg"
137+
style="border:none;display:block;outline:none;text-decoration:none"
138+
>
139+
<a
140+
href="https://jsx.email"
141+
style="color:#067df7;text-decoration:none"
142+
>
143+
</a>
144+
<div style="border:solid 1px black;padding:12px">
145+
<h1 style="color:red">
146+
Hello, World!
147+
</h1>
148+
</div>
149+
<table
150+
align="center"
151+
width="100%"
152+
role="presentation"
153+
cellspacing="0"
154+
cellpadding="0"
155+
border="0"
156+
>
157+
<tbody style="width:100%">
158+
<tr style="width:100%">
159+
<td>
160+
Column
161+
</td>
162+
</tr>
163+
</tbody>
164+
</table>
165+
<p style="font-size:14px;line-height:24px;margin:16px 0">
166+
Removed Content
167+
</p>
168+
</td>
169+
</tr>
170+
</tbody>
171+
</table>
172+
</td>
173+
</tr>
174+
</tbody>
175+
</table>
176+
<span>
177+
<!--[if mso]></td></tr></table><![endif]-->
178+
</span>
179+
</div>
180+
</div>
27181
</body>
28182
</html>

test/smoke/tests/smoke.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,29 +75,29 @@ test('watcher', async ({ page }) => {
7575

7676
const isLocal = process.env.CI !== 'true';
7777
const targetFilePath = isLocal
78-
? join(__dirname, '../fixtures/components/text.tsx')
79-
: '/home/runner/work/jsx-email/jsx-email/jsx-email-tests/smoke-test/fixtures/components/text.tsx';
78+
? join(__dirname, '../fixtures/templates/base.jsx')
79+
: '/home/runner/work/jsx-email/jsx-email/jsx-email-tests/smoke-test/fixtures/templates/base.jsx';
8080

8181
console.log({ isLocal, targetFilePath });
8282

8383
const contents = await readFile(targetFilePath, 'utf8');
8484

8585
console.log({ contents });
8686

87-
await writeFile(targetFilePath, contents.replace('test', 'batman'), 'utf8');
87+
await writeFile(targetFilePath, contents.replace('Text Content', 'Removed Content'), 'utf8');
8888

8989
console.log('after write:', await readFile(targetFilePath, 'utf8'));
9090

9191
await page.waitForTimeout(45e3);
9292
await page.waitForSelector('#link-Local-Assets', timeout);
9393

94-
page.locator('#link-Local-Assets').click();
94+
page.locator('#link-Base').click();
9595

9696
const iframe = await page.frameLocator('#preview-frame');
9797
const html = await getHTML(iframe.locator('html'), { deep: true });
9898

9999
expect(html).toMatchSnapshot({ name: `watcher.snap` });
100100

101101
// Note: so we don't have dirty files when running smoketest locally
102-
await writeFile(targetFilePath, contents.replace('batman', 'test'), 'utf8');
102+
await writeFile(targetFilePath, contents.replace('Removed Content', 'Text Content'), 'utf8');
103103
});

0 commit comments

Comments
 (0)