Skip to content

Commit 923f437

Browse files
committed
feat: add experimental support for Svelte 5
1 parent a48cc4e commit 923f437

File tree

5 files changed

+80
-60
lines changed

5 files changed

+80
-60
lines changed

CONTRIBUTING.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Contributing
2+
3+
PRs for issues are welcome. Before pushing the code, make sure that linting and tests pass.
4+
5+
Commit pattern: conventional commit (`docs/feat/fix/chore: ..`) (https://www.conventionalcommits.org/en/v1.0.0/)
6+
Changelog pattern: conventional-changelog tool to generate the changelog (https://github.com/conventional-changelog/conventional-changelog)
7+
8+
The publishing process is manual right now, so the current workflow is:
9+
10+
- Merge to main
11+
- Checkout to main
12+
- run npm run patch | minor | major - this will update the changelog, bump the package.json and create the release tag
13+
- run npm publish (maybe 2fa will be asked here)

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
"sass": "^1.26.8",
105105
"stylus": "^0.55.0",
106106
"sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0",
107-
"svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0",
107+
"svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0",
108108
"typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0"
109109
},
110110
"peerDependenciesMeta": {

src/transformers/typescript.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,13 @@ function injectVarsToCode({
150150
}): string {
151151
if (!markup) return content;
152152

153+
// @ts-ignore different in Svelte 5
153154
const { vars } = compile(stripTags(markup), {
154155
generate: false,
155156
varsReport: 'full',
156157
errorMode: 'warn',
157158
filename,
158-
});
159+
}) as { vars: any[] };
159160

160161
const sep = `\n${injectedCodeSeparator}\n`;
161162
const varnames = vars.map((v) =>
@@ -552,11 +553,13 @@ const transformer: Transformer<Options.Typescript> = async ({
552553
const compilerOptions = getCompilerOptions({ filename, options, basePath });
553554
const versionParts = pkg.version.split('.');
554555
const canUseMixedImportsTranspiler =
555-
+versionParts[0] > 3 || (+versionParts[0] === 3 && +versionParts[1] >= 39);
556+
+versionParts[0] === 4 ||
557+
(+versionParts[0] === 3 && +versionParts[1] >= 39);
556558

557559
if (!canUseMixedImportsTranspiler && options.handleMixedImports) {
558560
throw new Error(
559-
'You need at least Svelte 3.39 to use the handleMixedImports option',
561+
'You need at least Svelte 3.39 and at most Svelte 4.x to use the handleMixedImports option. ' +
562+
'The option is no longer available for Svelte 5 and beyond. Use the verbatimModuleSyntax TypeScript option instead.',
560563
);
561564
}
562565

test/transformers/typescript.test.ts

+59-55
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { resolve } from 'path';
22

3-
import { compile } from 'svelte/compiler';
3+
import { compile, VERSION } from 'svelte/compiler';
44

55
import sveltePreprocess from '../../src';
66
import { loadTsconfig } from '../../src/transformers/typescript';
@@ -16,6 +16,8 @@ import type { Diagnostic } from 'typescript';
1616

1717
spyConsole({ silent: true });
1818

19+
const IS_SVELTE_5_PLUS = Number(VERSION.split('.')[0]) >= 5;
20+
1921
const EXPECTED_SCRIPT = getFixtureContent('script.js');
2022

2123
const autoProcessTS = (content: string, compilerOptions?: any) => {
@@ -113,34 +115,6 @@ describe('transformer - typescript', () => {
113115
expect(code).toContain(getFixtureContent('script.js'));
114116
});
115117

116-
it('should strip unused and type imports', async () => {
117-
const tpl = getFixtureContent('TypeScriptImports.svelte');
118-
119-
const opts = sveltePreprocess({
120-
typescript: { tsconfigFile: false },
121-
});
122-
123-
const { code } = await preprocess(tpl, opts);
124-
125-
// Test that imports are properly preserved
126-
expect(code).toContain(`import { fly } from "svelte/transition"`);
127-
expect(code).toContain(`import { flip } from "svelte/animate"`);
128-
expect(code).toContain(`import Nested from "./Nested.svelte"`);
129-
expect(code).toContain(`import { hello } from "./script"`);
130-
expect(code).toContain(`import { AValue } from "./types"`);
131-
expect(code).toContain(
132-
`import { storeTemplateOnly, storeScriptOnly, store0 } from "./store"`,
133-
);
134-
expect(code).toContain(
135-
`import { onlyUsedInModuleScript } from "./modulescript";`,
136-
);
137-
expect(code).toContain(
138-
`import { storeModuleTemplateOnly, storeModuleScriptOnly } from "./store";`,
139-
);
140-
// Test that comments are properly preserved
141-
expect(code).toContain('<!-- Some comment -->');
142-
});
143-
144118
it('should keep all value imports with verbatimModuleSyntax', async () => {
145119
const tpl = getFixtureContent('PreserveValueImports.svelte');
146120

@@ -192,18 +166,6 @@ describe('transformer - typescript', () => {
192166
expect(code).toBe(`<script lang="ts" context="module"></script>`);
193167
});
194168

195-
it('should strip unused and type imports in context="module" tags', async () => {
196-
const tpl = getFixtureContent('TypeScriptImportsModule.svelte');
197-
198-
const opts = sveltePreprocess({
199-
typescript: { tsconfigFile: false },
200-
});
201-
202-
const { code } = await preprocess(tpl, opts);
203-
204-
expect(code).toContain(`import { AValue } from "./types";`);
205-
});
206-
207169
it('should produce sourcemap', async () => {
208170
const tpl = getFixtureContent('TypeScriptImportsModule.svelte');
209171

@@ -217,20 +179,6 @@ describe('transformer - typescript', () => {
217179
expect(map).toHaveProperty('sources', ['App.svelte']);
218180
});
219181

220-
it('should work when tsconfig contains outDir', async () => {
221-
const opts = sveltePreprocess({
222-
typescript: {
223-
tsconfigFile: './test/fixtures/tsconfig.outdir.json',
224-
handleMixedImports: true,
225-
},
226-
sourceMap: true,
227-
});
228-
229-
const preprocessed = await preprocess(template, opts);
230-
231-
expect(preprocessed.toString?.()).toContain(EXPECTED_SCRIPT);
232-
});
233-
234182
it('supports extends field', () => {
235183
const { options } = loadTsconfig({}, getTestAppFilename(), {
236184
tsconfigFile: './test/fixtures/tsconfig.extends1.json',
@@ -280,4 +228,60 @@ describe('transformer - typescript', () => {
280228
expect(code).not.toContain('||=');
281229
});
282230
});
231+
232+
(IS_SVELTE_5_PLUS ? describe.skip : describe)('mixed imports', () => {
233+
it('should strip unused and type imports', async () => {
234+
const tpl = getFixtureContent('TypeScriptImports.svelte');
235+
236+
const opts = sveltePreprocess({
237+
typescript: { tsconfigFile: false },
238+
});
239+
240+
const { code } = await preprocess(tpl, opts);
241+
242+
// Test that imports are properly preserved
243+
expect(code).toContain(`import { fly } from "svelte/transition"`);
244+
expect(code).toContain(`import { flip } from "svelte/animate"`);
245+
expect(code).toContain(`import Nested from "./Nested.svelte"`);
246+
expect(code).toContain(`import { hello } from "./script"`);
247+
expect(code).toContain(`import { AValue } from "./types"`);
248+
expect(code).toContain(
249+
`import { storeTemplateOnly, storeScriptOnly, store0 } from "./store"`,
250+
);
251+
expect(code).toContain(
252+
`import { onlyUsedInModuleScript } from "./modulescript";`,
253+
);
254+
expect(code).toContain(
255+
`import { storeModuleTemplateOnly, storeModuleScriptOnly } from "./store";`,
256+
);
257+
// Test that comments are properly preserved
258+
expect(code).toContain('<!-- Some comment -->');
259+
});
260+
261+
it('should strip unused and type imports in context="module" tags', async () => {
262+
const tpl = getFixtureContent('TypeScriptImportsModule.svelte');
263+
264+
const opts = sveltePreprocess({
265+
typescript: { tsconfigFile: false },
266+
});
267+
268+
const { code } = await preprocess(tpl, opts);
269+
270+
expect(code).toContain(`import { AValue } from "./types";`);
271+
});
272+
273+
it('should work when tsconfig contains outDir', async () => {
274+
const opts = sveltePreprocess({
275+
typescript: {
276+
tsconfigFile: './test/fixtures/tsconfig.outdir.json',
277+
handleMixedImports: true,
278+
},
279+
sourceMap: true,
280+
});
281+
282+
const preprocessed = await preprocess(template, opts);
283+
284+
expect(preprocessed.toString?.()).toContain(EXPECTED_SCRIPT);
285+
});
286+
});
283287
});

test/utils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const preprocess = async (input: string, opts: any) =>
1717
const compile = async (input: string, opts: any) => {
1818
const preprocessed = await exports.preprocess(input, opts);
1919
const { js, css } = svelteCompile(preprocessed.toString?.(), {
20-
css: true,
20+
css: 'injected',
2121
});
2222

2323
return { js, css };

0 commit comments

Comments
 (0)