Skip to content

Commit dda938d

Browse files
fix(react-email): Detection of files with various export patterns (#1951)
Co-authored-by: gabriel miranda <[email protected]>
1 parent 8dfb96a commit dda938d

File tree

6 files changed

+206
-2
lines changed

6 files changed

+206
-2
lines changed

.changeset/shy-fans-allow.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-email": patch
3+
---
4+
5+
Fix detection of files with various export patterns

packages/react-email/src/utils/get-emails-directory-metadata.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,21 @@ const isFileAnEmail = (fullPath: string): boolean => {
1919
}
2020

2121
// check with a heuristic to see if the file has at least
22-
// a default export
22+
// a default export (ES6) or module.exports (CommonJS) or named exports (MDX)
2323
const fileContents = fs.readFileSync(fullPath, 'utf8');
2424

25-
return /\bexport\s+default\b/gm.test(fileContents);
25+
// Check for ES6 export default syntax
26+
const hasES6DefaultExport = /\bexport\s+default\b/gm.test(fileContents);
27+
28+
// Check for CommonJS module.exports syntax
29+
const hasCommonJSExport = /\bmodule\.exports\s*=/gm.test(fileContents);
30+
31+
// Check for named exports (used in MDX files) and ensure at least one is marked as default
32+
const hasNamedExport = /\bexport\s+\{[^}]*\bdefault\b[^}]*\}/gm.test(
33+
fileContents,
34+
);
35+
36+
return hasES6DefaultExport || hasCommonJSExport || hasNamedExport;
2637
};
2738

2839
export interface EmailsDirectory {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import path from 'node:path';
2+
import { getEmailsDirectoryMetadata } from './get-emails-directory-metadata';
3+
4+
describe('JavaScript Email Detection', async () => {
5+
const testingDir = path.resolve(__dirname, 'testing');
6+
const emailsMetadata = await getEmailsDirectoryMetadata(testingDir, true);
7+
8+
it('should detect JavaScript files with ES6 export default syntax', async () => {
9+
expect(emailsMetadata).toBeDefined();
10+
expect(emailsMetadata?.emailFilenames).toContain(
11+
'js-email-export-default.js',
12+
);
13+
});
14+
15+
it('should detect JavaScript files with CommonJS module.exports', async () => {
16+
expect(emailsMetadata).toBeDefined();
17+
expect(emailsMetadata?.emailFilenames).toContain('js-email-test.js');
18+
});
19+
20+
it('should detect MDX-style JavaScript files with named exports', async () => {
21+
expect(emailsMetadata).toBeDefined();
22+
expect(emailsMetadata?.emailFilenames).toContain('mdx-email-test.js');
23+
});
24+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// A JavaScript email component with ES6 export default
2+
import { Button, Html } from '@react-email/components';
3+
import React from 'react';
4+
5+
function Email() {
6+
return (
7+
<Html>
8+
<Button
9+
href="https://example.com"
10+
style={{ background: '#000', color: '#fff', padding: '12px 20px' }}
11+
>
12+
Click me
13+
</Button>
14+
</Html>
15+
);
16+
}
17+
18+
export default Email;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// A simple JavaScript email component
2+
const React = require('react');
3+
const { Html, Button } = require('@react-email/components');
4+
5+
function Email() {
6+
return (
7+
<Html>
8+
<Button
9+
href="https://example.com"
10+
style={{ background: '#000', color: '#fff', padding: '12px 20px' }}
11+
>
12+
Click me
13+
</Button>
14+
</Html>
15+
);
16+
}
17+
18+
module.exports = Email;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { Button, Html } from '@react-email/components';
2+
import { useMDXComponents as _provideComponents } from 'react';
3+
import {
4+
Fragment as _Fragment,
5+
jsxDEV as _jsxDEV,
6+
} from 'react/jsx-dev-runtime';
7+
8+
const MDXLayout = function Email2() {
9+
return _jsxDEV(
10+
Html,
11+
{
12+
children: _jsxDEV(
13+
Button,
14+
{
15+
href: 'https://example.com',
16+
style: {
17+
background: '#000',
18+
color: '#fff',
19+
padding: '12px 20px',
20+
},
21+
children: 'Click me',
22+
},
23+
void 0,
24+
false,
25+
{
26+
fileName:
27+
'/Users/david/src/silencia-ai/silencia/proto/emails-raw/em1.mdx',
28+
lineNumber: 7,
29+
columnNumber: 7,
30+
},
31+
this,
32+
),
33+
},
34+
void 0,
35+
false,
36+
{
37+
fileName:
38+
'/Users/david/src/silencia-ai/silencia/proto/emails-raw/em1.mdx',
39+
lineNumber: 6,
40+
columnNumber: 5,
41+
},
42+
this,
43+
);
44+
};
45+
46+
function _createMdxContent(props) {
47+
const _components = {
48+
h1: 'h1',
49+
..._provideComponents(),
50+
...props.components,
51+
};
52+
return _jsxDEV(
53+
_Fragment,
54+
{
55+
children: [
56+
_jsxDEV(
57+
_components.h1,
58+
{
59+
children: 'Hello!',
60+
},
61+
void 0,
62+
false,
63+
{
64+
fileName:
65+
'/Users/david/src/silencia-ai/silencia/proto/emails-raw/em1.mdx',
66+
lineNumber: 17,
67+
columnNumber: 1,
68+
},
69+
this,
70+
),
71+
'\n',
72+
_jsxDEV(
73+
Email,
74+
{},
75+
void 0,
76+
false,
77+
{
78+
fileName:
79+
'/Users/david/src/silencia-ai/silencia/proto/emails-raw/em1.mdx',
80+
lineNumber: 19,
81+
columnNumber: 1,
82+
},
83+
this,
84+
),
85+
],
86+
},
87+
void 0,
88+
true,
89+
{
90+
fileName:
91+
'/Users/david/src/silencia-ai/silencia/proto/emails-raw/em1.mdx',
92+
lineNumber: 1,
93+
columnNumber: 1,
94+
},
95+
this,
96+
);
97+
}
98+
99+
function MDXContent(props = {}) {
100+
return _jsxDEV(
101+
MDXLayout,
102+
{
103+
...props,
104+
children: _jsxDEV(
105+
_createMdxContent,
106+
{
107+
...props,
108+
},
109+
void 0,
110+
false,
111+
{
112+
fileName:
113+
'/Users/david/src/silencia-ai/silencia/proto/emails-raw/em1.mdx',
114+
},
115+
this,
116+
),
117+
},
118+
void 0,
119+
false,
120+
{
121+
fileName:
122+
'/Users/david/src/silencia-ai/silencia/proto/emails-raw/em1.mdx',
123+
},
124+
this,
125+
);
126+
}
127+
128+
export { MDXContent as default };

0 commit comments

Comments
 (0)