Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/large-frogs-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/vite-plugin-svelte': minor
---

Use transformWithEsbuild for vite script preprocessor
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getColor, getText } from 'testUtils';

test('should render App', async () => {
expect(await getText('h1.foo')).toBe(`Hello world`);
expect(await getColor('#app-scss')).toBe('rgb(0, 0, 153)'); // darken($blue, 20)
expect(await getText('#foo-title')).toBe('Styles with stylus blub');
expect(await getColor('#foo-title')).toBe('magenta');
expect(await getColor('p.note')).toBe('rgb(255, 62, 0)');
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
<title>Svelte App</title>
</head>
<body>
<script type="module" src="/src/index.js"></script>
<script type="module" src="/src/index.ts"></script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "playground-preprocess-with-vite",
"name": "e2e-tests-preprocess-with-vite",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
"preview": "vite preview"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<script lang="ts">
import Foo from './Foo.svelte';
import Bar from './Bar.svelte';
export let hello: string;
const world: string = 'world'; // edit world and save to see hmr update
</script>

<h1 class="foo">Hello {world}</h1>
<p>This is styled with scss using darken fn</p>
<h1 class="foo">{hello} {world}</h1>
<p id="app-scss">This is styled with scss using darken fn</p>
<Foo />
<Bar />

Expand Down
15 changes: 15 additions & 0 deletions packages/e2e-tests/preprocess-with-vite/src/Bar.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script>
import BarChild from './BarChild.svelte';
</script>

<BarChild />

<style>
/*
should warn because style tag only contains unscoped styles
(code smell & affects css hmr)
*/
:global(.note) {
background-color: lightblue;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>Bar child</p>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
export let bla: string = 'blub';
</script>

<h1>Styles with {foo} {bla}</h1>
<h1 id="foo-title">Styles with {foo} {bla}</h1>
<p class="note">cool, huh?</p>

<style lang="stylus">
Expand Down
13 changes: 13 additions & 0 deletions packages/e2e-tests/preprocess-with-vite/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import App from './App.svelte';
import { Hello } from './types';

const hello: Hello = 'Hello';

const app = new App({
target: document.body,
props: {
hello
}
});

export default app;
1 change: 1 addition & 0 deletions packages/e2e-tests/preprocess-with-vite/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type Hello = 'Hello';
11 changes: 0 additions & 11 deletions packages/playground/preprocess-with-vite/src/Bar.svelte

This file was deleted.

7 changes: 0 additions & 7 deletions packages/playground/preprocess-with-vite/src/index.js

This file was deleted.

11 changes: 0 additions & 11 deletions packages/vite-plugin-svelte/src/utils/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,17 +207,6 @@ export function buildExtraViteConfig(
// @ts-ignore
extraViteConfig.ssr = buildSSROptionsForSvelte(svelteDeps, options, config);

if (options.experimental?.useVitePreprocess) {
// needed to transform svelte files with component imports
// can cause issues with other typescript files, see https://github.com/sveltejs/vite-plugin-svelte/pull/20
extraViteConfig.esbuild = {
tsconfigRaw: {
compilerOptions: {
importsNotUsedAsValues: 'preserve'
}
}
};
}
return extraViteConfig;
}

Expand Down
72 changes: 43 additions & 29 deletions packages/vite-plugin-svelte/src/utils/preprocess.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { ResolvedConfig, TransformResult, Plugin } from 'vite';
import {
transformWithEsbuild,
ESBuildOptions,
ResolvedConfig,
TransformResult,
Plugin
} from 'vite';
import MagicString from 'magic-string';
import { Preprocessor, PreprocessorGroup, Processed, ResolvedOptions } from './options';
import { TransformPluginContext } from 'rollup';
Expand All @@ -9,12 +15,29 @@ const supportedStyleLangs = ['css', 'less', 'sass', 'scss', 'styl', 'stylus', 'p

const supportedScriptLangs = ['ts'];

function createPreprocessorFromVitePlugin(
config: ResolvedConfig,
options: ResolvedOptions,
pluginName: string,
supportedLangs: string[]
): Preprocessor {
function createViteScriptPreprocessor(): Preprocessor {
// @ts-expect-error - allow return void
return async ({ attributes, content, filename = '' }) => {
const lang = attributes.lang as string;
if (!supportedScriptLangs.includes(lang)) return;
const transformResult = await transformWithEsbuild(content, filename, {
loader: lang as ESBuildOptions['loader'],
tsconfigRaw: {
compilerOptions: {
// svelte typescript needs this flag to work with type imports
importsNotUsedAsValues: 'preserve'
}
}
});
return {
code: transformResult.code,
map: transformResult.map
};
};
}

function createViteStylePreprocessor(config: ResolvedConfig): Preprocessor {
const pluginName = 'vite:css';
const plugin = config.plugins.find((p) => p.name === pluginName);
if (!plugin) {
throw new Error(`failed to find plugin ${pluginName}`);
Expand All @@ -23,41 +46,32 @@ function createPreprocessorFromVitePlugin(
throw new Error(`plugin ${pluginName} has no transform`);
}
const pluginTransform = plugin.transform!.bind(null as unknown as TransformPluginContext);
// @ts-ignore
return async ({ attributes, content, filename }) => {
// @ts-expect-error - allow return void
return async ({ attributes, content, filename = '' }) => {
const lang = attributes.lang as string;
if (!supportedLangs.includes(lang)) {
return { code: content };
}
if (!supportedStyleLangs.includes(lang)) return;
const moduleId = `${filename}.${lang}`;
const moduleGraph = options.server?.moduleGraph;
if (moduleGraph && !moduleGraph.getModuleById(moduleId)) {
await moduleGraph.ensureEntryFromUrl(moduleId);
}
const transformResult: TransformResult = (await pluginTransform(
content,
moduleId
)) as TransformResult;
// TODO vite:css transform currently returns an empty mapping that would kill svelte compiler.
const hasMap = transformResult.map && transformResult.map?.mappings !== '';
if (transformResult.map?.sources?.[0] === moduleId) {
transformResult.map.sources[0] = filename as string;
// vite returns empty mappings that would kill svelte compiler before 3.43.0
const hasMap = transformResult.map && transformResult.map.mappings !== '';
// patch sourcemap source to point back to original filename
if (hasMap && transformResult.map?.sources?.[0] === moduleId) {
transformResult.map.sources[0] = filename;
}
return {
code: transformResult.code,
map: hasMap ? (transformResult.map as object) : undefined,
dependencies: transformResult.deps
map: hasMap ? transformResult.map : undefined
};
};
}

export function createVitePreprocessorGroup(
config: ResolvedConfig,
options: ResolvedOptions
): PreprocessorGroup {
export function createVitePreprocessorGroup(config: ResolvedConfig): PreprocessorGroup {
return {
script: createPreprocessorFromVitePlugin(config, options, 'vite:esbuild', supportedScriptLangs),
style: createPreprocessorFromVitePlugin(config, options, 'vite:css', supportedStyleLangs)
script: createViteScriptPreprocessor(),
style: createViteStylePreprocessor(config)
} as PreprocessorGroup;
}

Expand All @@ -84,7 +98,7 @@ function buildExtraPreprocessors(options: ResolvedOptions, config: ResolvedConfi
const extraPreprocessors = [];
if (options.experimental?.useVitePreprocess) {
log.debug('adding vite preprocessor');
extraPreprocessors.push(createVitePreprocessorGroup(config, options));
extraPreprocessors.push(createVitePreprocessorGroup(config));
}

// @ts-ignore
Expand Down
31 changes: 17 additions & 14 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.