Skip to content

Commit d47d37e

Browse files
fix(preview-server): default imports of node modules breaking templates (#2936)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
1 parent a9a9401 commit d47d37e

File tree

3 files changed

+26
-8
lines changed

3 files changed

+26
-8
lines changed

.changeset/olive-walls-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-email/preview-server": patch
3+
---
4+
5+
fix default imports of node modules breaking

packages/preview-server/src/utils/run-bundled-code.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import path from 'node:path';
12
import { z } from 'zod';
23
import { isErr, isOk } from './result';
34
import { runBundledCode } from './run-bundled-code';
@@ -51,6 +52,24 @@ describe('runBundledCode()', () => {
5152
).toEqual(42);
5253
});
5354

55+
// see https://github.com/resend/react-email/issues/2930
56+
it('works when using default imports for node:path', async () => {
57+
const result = await runBundledCode(
58+
`
59+
import path from 'node:path';
60+
61+
export default path.join('a', 'b', 'c');
62+
`,
63+
'test-path.js',
64+
);
65+
if (!isOk(result)) {
66+
expect(isOk(result), 'there should be no errors').toBe(true);
67+
console.log(result.error);
68+
return;
69+
}
70+
expect(result.value).toEqual({ default: path.join('a', 'b', 'c') });
71+
});
72+
5473
it('returns an error if the code throws', async () => {
5574
const result = await runBundledCode(
5675
'throw new Error("Test error");',

packages/preview-server/src/utils/run-bundled-code.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,17 @@ export async function runBundledCode(
117117

118118
if (m in staticNodeModulesForVM) {
119119
const moduleExports = staticNodeModulesForVM[m];
120-
// Get all own property keys (including symbols and non-enumerable)
121120
const exportKeys = Reflect.ownKeys(moduleExports).filter(
122121
(key) => typeof key === 'string',
123122
) as string[];
124123

125-
// Create a SyntheticModule that exports the static module
126124
const syntheticModule = new vm.SyntheticModule(
127-
exportKeys,
125+
[...exportKeys.filter((k) => k !== 'default'), 'default'],
128126
function () {
129-
// Set all exports from the static module
130127
for (const key of exportKeys) {
131128
this.setExport(key, moduleExports[key]);
132129
}
130+
this.setExport('default', moduleExports);
133131
},
134132
{
135133
context,
@@ -139,21 +137,17 @@ export async function runBundledCode(
139137
return syntheticModule;
140138
}
141139

142-
// For external modules, import them and create a SyntheticModule
143140
const importedModule = await import(specifier, {
144141
with: extra.attributes as ImportAttributes,
145142
});
146143

147-
// Get all own property keys (including symbols and non-enumerable)
148-
// Filter to only string keys as SyntheticModule only supports string export names
149144
const exportKeys = Reflect.ownKeys(importedModule).filter(
150145
(key) => typeof key === 'string',
151146
) as string[];
152147

153148
const syntheticModule = new vm.SyntheticModule(
154149
exportKeys,
155150
function () {
156-
// Set all exports from the imported module
157151
for (const key of exportKeys) {
158152
this.setExport(key, importedModule[key]);
159153
}

0 commit comments

Comments
 (0)