Skip to content

Commit d6b02ed

Browse files
authored
chore(test): use esm output for Svelte files (#8614)
1 parent c2cec95 commit d6b02ed

File tree

7 files changed

+88
-45
lines changed

7 files changed

+88
-45
lines changed

test/css/css.test.js

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,9 @@ describe('css', () => {
3434

3535
const expected_warnings = (config.warnings || []).map(normalize_warning);
3636

37-
const dom = svelte.compile(
38-
input,
39-
Object.assign({}, config.compileOptions || {}, { format: 'cjs' })
40-
);
37+
const dom = svelte.compile(input, Object.assign({}, config.compileOptions || {}));
4138

42-
const ssr = svelte.compile(
43-
input,
44-
Object.assign({}, config.compileOptions || {}, { format: 'cjs', generate: 'ssr' })
45-
);
39+
const ssr = svelte.compile(input, Object.assign({}, config.compileOptions || {}));
4640

4741
assert.equal(dom.css.code, ssr.css.code);
4842

@@ -75,18 +69,15 @@ describe('css', () => {
7569

7670
// we do this here, rather than in the expected.html !== null
7771
// block, to verify that valid code was generated
78-
const load = create_loader({ ...(config.compileOptions || {}), format: 'cjs' }, cwd);
72+
const load = create_loader({ ...(config.compileOptions || {}) }, cwd);
7973
try {
8074
ClientComponent = (await load('input.svelte')).default;
8175
} catch (err) {
8276
console.log(dom.js.code);
8377
throw err;
8478
}
8579

86-
const load_ssr = create_loader(
87-
{ ...(config.compileOptions || {}), generate: 'ssr', format: 'cjs' },
88-
cwd
89-
);
80+
const load_ssr = create_loader({ ...(config.compileOptions || {}), generate: 'ssr' }, cwd);
9081
try {
9182
ServerComponent = (await load_ssr('input.svelte')).default;
9283
} catch (err) {

test/helpers.js

Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -103,53 +103,109 @@ export function show_output(cwd, options = {}) {
103103

104104
const svelte_path = fileURLToPath(new URL('..', import.meta.url)).replace(/\\/g, '/');
105105

106+
const AsyncFunction = /** @type {typeof Function} */ (async function () {}.constructor);
107+
106108
export function create_loader(compileOptions, cwd) {
107109
const cache = new Map();
108110

109111
async function load(file) {
110112
if (cache.has(file)) return cache.get(file);
111113

112114
if (file.endsWith('.svelte')) {
115+
const options = {
116+
...compileOptions,
117+
filename: file
118+
};
119+
113120
const compiled = compile(
114121
// Windows/Linux newline conversion
115122
fs.readFileSync(file, 'utf-8').replace(/\r\n/g, '\n'),
116-
{
117-
...compileOptions,
118-
filename: file
119-
}
123+
options
120124
);
121125

122-
const imports = new Map();
126+
const __import = (id) => {
127+
let resolved = id;
123128

124-
for (const match of compiled.js.code.matchAll(/require\("(.+?)"\)/g)) {
125-
const source = match[1];
126-
let resolved = source;
127-
128-
if (source.startsWith('.')) {
129-
resolved = path.resolve(path.dirname(file), source);
129+
if (id.startsWith('.')) {
130+
resolved = path.resolve(path.dirname(file), id);
130131
}
131132

132-
if (source === 'svelte') {
133+
if (id === 'svelte') {
133134
resolved = `${svelte_path}src/runtime/index.js`;
134135
}
135136

136-
if (source.startsWith('svelte/')) {
137-
resolved = `${svelte_path}src/runtime/${source.slice(7)}/index.js`;
137+
if (id.startsWith('svelte/')) {
138+
resolved = `${svelte_path}src/runtime/${id.slice(7)}/index.js`;
138139
}
139140

140-
imports.set(source, await load(resolved));
141-
}
142-
143-
function require(id) {
144-
return imports.get(id);
141+
return load(resolved);
142+
};
143+
144+
const exports = [];
145+
146+
// We can't use Node's or Vitest's loaders cause we compile with different options.
147+
// We need to rewrite the imports into function calls that we can intercept to transform
148+
// any imported Svelte components as well. A few edge cases aren't handled but also
149+
// currently unused in the tests, for example `export * from`and live bindings.
150+
let transformed = compiled.js.code
151+
.replace(
152+
/^import \* as (\w+) from ['"]([^'"]+)['"];?/gm,
153+
'const $1 = await __import("$2");'
154+
)
155+
.replace(
156+
/^import (\w+) from ['"]([^'"]+)['"];?/gm,
157+
'const {default: $1} = await __import("$2");'
158+
)
159+
.replace(
160+
/^import (\w+, )?{([^}]+)} from ['"](.+)['"];?/gm,
161+
(_, default_, names, source) => {
162+
const d = default_ ? `default: ${default_}` : '';
163+
return `const { ${d} ${names.replaceAll(
164+
' as ',
165+
': '
166+
)} } = await __import("${source}");`;
167+
}
168+
)
169+
.replace(/^export default /gm, '__exports.default = ')
170+
.replace(
171+
/^export (const|let|var|class|function|async\s+function) (\w+)/gm,
172+
(_, type, name) => {
173+
exports.push(name);
174+
return `${type} ${name}`;
175+
}
176+
)
177+
.replace(/^export \{([^}]+)\}(?: from ['"]([^'"]+)['"];?)?/gm, (_, names, source) => {
178+
const entries = names.split(',').map((name) => {
179+
const match = name.trim().match(/^(\w+)( as (\w+))?$/);
180+
const i = match[1];
181+
const o = match[3] || i;
182+
183+
return [o, i];
184+
});
185+
return source
186+
? `{ const __mod = await __import("${source}"); ${entries
187+
.map(([o, i]) => `__exports.${o} = __mod.${i};`)
188+
.join('\n')}}`
189+
: `{ ${entries.map(([o, i]) => `__exports.${o} = ${i};`).join('\n')} }`;
190+
});
191+
192+
exports.forEach((name) => {
193+
transformed += `\n__exports.${name} = ${name};`;
194+
});
195+
196+
const __exports = {
197+
[Symbol.toStringTag]: 'Module'
198+
};
199+
try {
200+
const fn = new AsyncFunction('__import', '__exports', transformed);
201+
await fn(__import, __exports);
202+
} catch (err) {
203+
console.error({ transformed }); // eslint-disable-line no-console
204+
throw err;
145205
}
146206

147-
const fn = new Function('require', 'exports', 'module', compiled.js.code);
148-
const module = { exports: {} };
149-
fn(require, module.exports, module);
150-
151-
cache.set(file, module.exports);
152-
return module.exports;
207+
cache.set(file, __exports);
208+
return __exports;
153209
} else {
154210
return import(file);
155211
}

test/hydration/hydration.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ describe('hydration', async () => {
2121

2222
const compileOptions = Object.assign({}, config.compileOptions, {
2323
accessors: 'accessors' in config ? config.accessors : true,
24-
format: 'cjs',
2524
hydratable: true
2625
});
2726

test/runtime/runtime.shared.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ async function run_test(dir) {
5656
const cwd = path.resolve(`${__dirname}/samples/${dir}`);
5757

5858
const compileOptions = Object.assign({}, config.compileOptions || {}, {
59-
format: 'cjs',
6059
hydratable: hydrate,
6160
immutable: config.immutable,
6261
accessors: 'accessors' in config ? config.accessors : true

test/runtime/runtime_base.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { create_loader } from '../helpers';
44
import { assert, it } from 'vitest';
55

6-
const load = create_loader({ generate: 'dom', dev: true, format: 'cjs' }, __dirname);
6+
const load = create_loader({ generate: 'dom', dev: true }, __dirname);
77
const { default: App } = await load('App.svelte');
88

99
it('fails if options.target is missing in dev mode', async () => {

test/server-side-rendering/ssr-1.test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ describe('ssr', async () => {
3030

3131
const compileOptions = {
3232
...config.compileOptions,
33-
generate: 'ssr',
34-
format: 'cjs'
33+
generate: 'ssr'
3534
};
3635

3736
const load = create_loader(compileOptions, dir);

test/server-side-rendering/ssr-2.test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ function run_runtime_samples(suite) {
3333
it_fn(dir, async () => {
3434
const compileOptions = {
3535
...config.compileOptions,
36-
generate: 'ssr',
37-
format: 'cjs'
36+
generate: 'ssr'
3837
};
3938

4039
const load = create_loader(compileOptions, cwd);

0 commit comments

Comments
 (0)