From 907e8106afcccbc9ca4f7ba18e1937cdccd93b6a Mon Sep 17 00:00:00 2001 From: dominikg Date: Fri, 15 Sep 2023 09:45:29 +0200 Subject: [PATCH 01/11] chore(release): point changesets at v2 --- .changeset/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/config.json b/.changeset/config.json index 5b775d360..baa9c722b 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -7,7 +7,7 @@ "commit": false, "linked": [], "access": "public", - "baseBranch": "main", + "baseBranch": "v2", "bumpVersionsWithWorkspaceProtocolOnly": true, "updateInternalDependencies": "minor", "ignore": ["!(@sveltejs/*)"] From 31ce52c2b1183eb3e5920eeecbe85b461aaec6b3 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:42:14 +0100 Subject: [PATCH 02/11] Chore/v2 cleanup (#782) * feat: add experimental support for Svelte 5 * add experimental note --- .changeset/poor-avocados-learn.md | 5 ++ packages/vite-plugin-svelte/package.json | 2 +- packages/vite-plugin-svelte/src/index.d.ts | 10 ++++ packages/vite-plugin-svelte/src/index.js | 46 +++++++++++++++++-- packages/vite-plugin-svelte/src/types/id.d.ts | 15 ++++++ .../vite-plugin-svelte/src/utils/compile.js | 9 ++-- .../vite-plugin-svelte/src/utils/esbuild.js | 28 +++++++++-- packages/vite-plugin-svelte/src/utils/id.js | 45 ++++++++++++++++++ packages/vite-plugin-svelte/src/utils/log.js | 2 +- .../vite-plugin-svelte/src/utils/options.js | 5 ++ .../src/utils/svelte-version.js | 5 ++ 11 files changed, 158 insertions(+), 14 deletions(-) create mode 100644 .changeset/poor-avocados-learn.md diff --git a/.changeset/poor-avocados-learn.md b/.changeset/poor-avocados-learn.md new file mode 100644 index 000000000..7c22ea721 --- /dev/null +++ b/.changeset/poor-avocados-learn.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/vite-plugin-svelte': minor +--- + +feat: add experimental support for Svelte 5 diff --git a/packages/vite-plugin-svelte/package.json b/packages/vite-plugin-svelte/package.json index 90b303b32..a59871809 100644 --- a/packages/vite-plugin-svelte/package.json +++ b/packages/vite-plugin-svelte/package.json @@ -47,7 +47,7 @@ "vitefu": "^0.2.4" }, "peerDependencies": { - "svelte": "^3.54.0 || ^4.0.0", + "svelte": "^3.54.0 || ^4.0.0 || ^5.0.0-next.0", "vite": "^4.0.0" }, "devDependencies": { diff --git a/packages/vite-plugin-svelte/src/index.d.ts b/packages/vite-plugin-svelte/src/index.d.ts index 52feb0a4b..e5aa5e588 100644 --- a/packages/vite-plugin-svelte/src/index.d.ts +++ b/packages/vite-plugin-svelte/src/index.d.ts @@ -170,6 +170,16 @@ interface ExperimentalOptions { * @default false */ disableSvelteResolveWarnings?: boolean; + /** + * Options for compiling Svelte JS/TS modules + */ + compileModule?: CompileModuleOptions; +} + +interface CompileModuleOptions { + extensions?: string[]; + include?: Arrayable; + exclude?: Arrayable; } type ModuleFormat = NonNullable<'esm'>; diff --git a/packages/vite-plugin-svelte/src/index.js b/packages/vite-plugin-svelte/src/index.js index a08be0ba3..9e54442cf 100644 --- a/packages/vite-plugin-svelte/src/index.js +++ b/packages/vite-plugin-svelte/src/index.js @@ -1,5 +1,6 @@ import fs from 'node:fs'; import { version as viteVersion } from 'vite'; +import * as svelteCompiler from 'svelte/compiler'; import { svelteInspector } from '@sveltejs/vite-plugin-svelte-inspector'; @@ -7,7 +8,7 @@ import { isDepExcluded } from 'vitefu'; import { handleHotUpdate } from './handle-hot-update.js'; import { log, logCompilerWarnings } from './utils/log.js'; import { createCompileSvelte } from './utils/compile.js'; -import { buildIdParser } from './utils/id.js'; +import { buildIdParser, buildModuleIdParser } from './utils/id.js'; import { buildExtraViteConfig, validateInlineOptions, @@ -24,7 +25,7 @@ import { saveSvelteMetadata } from './utils/optimizer.js'; import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache.js'; import { loadRaw } from './utils/load-raw.js'; import { FAQ_LINK_CONFLICTS_IN_SVELTE_RESOLVE } from './utils/constants.js'; -import { isSvelte3 } from './utils/svelte-version.js'; +import { isSvelte3, isSvelte5 } from './utils/svelte-version.js'; const isVite4_0 = viteVersion.startsWith('4.0'); @@ -38,6 +39,8 @@ export function svelte(inlineOptions) { // updated in configResolved hook /** @type {import('./types/id.d.ts').IdParser} */ let requestParser; + /** @type {import('./types/id.d.ts').ModuleIdParser} */ + let moduleRequestParser; /** @type {import('./types/options.d.ts').ResolvedOptions} */ let options; /** @type {import('vite').ResolvedConfig} */ @@ -268,9 +271,44 @@ export function svelte(inlineOptions) { ); } } - }, - svelteInspector() + } ]; + + if (!isSvelte5) { + plugins.push(svelteInspector()); // TODO reenable once svelte5 has support + } + if (isSvelte5) { + log.warn( + 'svelte 5 support in v-p-s is experimental, breaking changes can occur in any release until this notice is removed' + ); + log.warn('svelte 5 does not support svelte-inspector yet, disabling it'); + // TODO move to separate file + plugins.push({ + name: 'vite-plugin-svelte-module', + enforce: 'post', + async configResolved() { + moduleRequestParser = buildModuleIdParser(options); + }, + async transform(code, id, opts) { + const ssr = !!opts?.ssr; + const moduleRequest = moduleRequestParser(id, ssr); + if (!moduleRequest) { + return; + } + try { + const compileResult = await svelteCompiler.compileModule(code, { + generate: ssr ? 'ssr' : 'dom', + filename: moduleRequest.filename + }); + logCompilerWarnings(moduleRequest, compileResult.warnings, options); + return compileResult.js; + } catch (e) { + throw toRollupError(e, options); + } + } + }); + } + return plugins; } diff --git a/packages/vite-plugin-svelte/src/types/id.d.ts b/packages/vite-plugin-svelte/src/types/id.d.ts index 205afd832..c6b2e325e 100644 --- a/packages/vite-plugin-svelte/src/types/id.d.ts +++ b/packages/vite-plugin-svelte/src/types/id.d.ts @@ -28,4 +28,19 @@ export interface SvelteRequest { raw: boolean; } +export interface SvelteModuleRequest { + id: string; + filename: string; + normalizedFilename: string; + query: RequestQuery; + timestamp: number; + ssr: boolean; +} + export type IdParser = (id: string, ssr: boolean, timestamp?: number) => SvelteRequest | undefined; + +export type ModuleIdParser = ( + id: string, + ssr: boolean, + timestamp?: number +) => SvelteModuleRequest | undefined; diff --git a/packages/vite-plugin-svelte/src/utils/compile.js b/packages/vite-plugin-svelte/src/utils/compile.js index dc9dfd4de..11c975035 100644 --- a/packages/vite-plugin-svelte/src/utils/compile.js +++ b/packages/vite-plugin-svelte/src/utils/compile.js @@ -1,4 +1,4 @@ -import { compile, preprocess, walk } from 'svelte/compiler'; +import * as svelte from 'svelte/compiler'; // @ts-ignore import { createMakeHot } from 'svelte-hmr'; import { safeBase64Hash } from './hash.js'; @@ -86,7 +86,7 @@ export const _createCompileSvelte = (makeHot) => { } if (preprocessors) { try { - preprocessed = await preprocess(code, preprocessors, { filename }); // full filename here so postcss works + preprocessed = await svelte.preprocess(code, preprocessors, { filename }); // full filename here so postcss works } catch (e) { e.message = `Error while preprocessing ${filename}${e.message ? ` - ${e.message}` : ''}`; throw e; @@ -123,7 +123,7 @@ export const _createCompileSvelte = (makeHot) => { : compileOptions; const endStat = stats?.start(filename); - const compiled = compile(finalCode, finalCompileOptions); + const compiled = svelte.compile(finalCode, finalCompileOptions); if (isSvelte3) { // prevent dangling pure comments @@ -187,7 +187,8 @@ function buildMakeHot(options) { // @ts-ignore const adapter = options?.hot?.adapter; return createMakeHot({ - walk, + // TODO Svelte 5 doesn't expose walk anymore. If we decide to make v-p-s 2 work with Svelte 5 HMR, we need to import walk from estree-walker + walk: svelte.walk, hotApi, adapter, hotOptions: { noOverlay: true, .../** @type {object} */ (options.hot) } diff --git a/packages/vite-plugin-svelte/src/utils/esbuild.js b/packages/vite-plugin-svelte/src/utils/esbuild.js index ac49fd7bb..9623c1c42 100644 --- a/packages/vite-plugin-svelte/src/utils/esbuild.js +++ b/packages/vite-plugin-svelte/src/utils/esbuild.js @@ -1,8 +1,8 @@ import { readFileSync } from 'node:fs'; -import { compile, preprocess } from 'svelte/compiler'; +import * as svelte from 'svelte/compiler'; import { log } from './log.js'; import { toESBuildError } from './error.js'; -import { isSvelte3 } from './svelte-version.js'; +import { isSvelte3, isSvelte5 } from './svelte-version.js'; /** * @typedef {NonNullable} EsbuildOptions @@ -11,6 +11,8 @@ import { isSvelte3 } from './svelte-version.js'; export const facadeEsbuildSveltePluginName = 'vite-plugin-svelte:facade'; +const svelteModuleExtension = '.svelte.js'; + /** * @param {import('../types/options.d.ts').ResolvedOptions} options * @returns {EsbuildPlugin} @@ -24,6 +26,9 @@ export function esbuildSveltePlugin(options) { if (build.initialOptions.plugins?.some((v) => v.name === 'vite:dep-scan')) return; const svelteExtensions = (options.extensions ?? ['.svelte']).map((ext) => ext.slice(1)); + if (isSvelte5) { + svelteExtensions.push(svelteModuleExtension.slice(1)); + } const svelteFilter = new RegExp('\\.(' + svelteExtensions.join('|') + ')(\\?.*)?$'); /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */ let statsCollection; @@ -55,6 +60,21 @@ export function esbuildSveltePlugin(options) { * @returns {Promise} */ async function compileSvelte(options, { filename, code }, statsCollection) { + if (isSvelte5 && filename.endsWith(svelteModuleExtension)) { + const endStat = statsCollection?.start(filename); + const compiled = svelte.compileModule(code, { + filename, + generate: 'dom', + runes: true + }); + if (endStat) { + endStat(); + } + return compiled.js.map + ? compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl() + : compiled.js.code; + } + let css = options.compilerOptions.css; if (css !== 'none') { // TODO ideally we'd be able to externalize prebundled styles too, but for now always put them in the js @@ -75,7 +95,7 @@ async function compileSvelte(options, { filename, code }, statsCollection) { if (options.preprocess) { try { - preprocessed = await preprocess(code, options.preprocess, { filename }); + preprocessed = await svelte.preprocess(code, options.preprocess, { filename }); } catch (e) { e.message = `Error while preprocessing ${filename}${e.message ? ` - ${e.message}` : ''}`; throw e; @@ -102,7 +122,7 @@ async function compileSvelte(options, { filename, code }, statsCollection) { } : compileOptions; const endStat = statsCollection?.start(filename); - const compiled = compile(finalCode, finalCompileOptions); + const compiled = svelte.compile(finalCode, finalCompileOptions); if (endStat) { endStat(); } diff --git a/packages/vite-plugin-svelte/src/utils/id.js b/packages/vite-plugin-svelte/src/utils/id.js index ee7a719d3..332b1ea78 100644 --- a/packages/vite-plugin-svelte/src/utils/id.js +++ b/packages/vite-plugin-svelte/src/utils/id.js @@ -184,3 +184,48 @@ export function buildIdParser(options) { } }; } +/** + * @param {import('../types/options.d.ts').ResolvedOptions} options + * @returns {import('../types/id.d.ts').ModuleIdParser} + */ +export function buildModuleIdParser(options) { + const { include, exclude, extensions } = options?.experimental?.compileModule ?? {}; + const root = options.root; + const normalizedRoot = normalizePath(root); + const filter = buildFilter(include, exclude, extensions ?? ['.svelte.js', '.svelte.ts']); + return (id, ssr, timestamp = Date.now()) => { + const { filename, rawQuery } = splitId(id); + if (filter(filename)) { + return parseToSvelteModuleRequest(id, filename, rawQuery, normalizedRoot, timestamp, ssr); + } + }; +} + +/** + * @param {string} id + * @param {string} filename + * @param {string} rawQuery + * @param {string} root + * @param {number} timestamp + * @param {boolean} ssr + * @returns {import('../types/id.d.ts').SvelteModuleRequest | undefined} + */ +function parseToSvelteModuleRequest(id, filename, rawQuery, root, timestamp, ssr) { + const query = parseRequestQuery(rawQuery); + + if (query.url || query.raw || query.direct) { + // skip requests with special vite tags + return; + } + + const normalizedFilename = normalize(filename, root); + + return { + id, + filename, + normalizedFilename, + query, + timestamp, + ssr + }; +} diff --git a/packages/vite-plugin-svelte/src/utils/log.js b/packages/vite-plugin-svelte/src/utils/log.js index 47eea1b93..40ac9d3af 100644 --- a/packages/vite-plugin-svelte/src/utils/log.js +++ b/packages/vite-plugin-svelte/src/utils/log.js @@ -120,7 +120,7 @@ export const log = { }; /** - * @param {import('../types/id.d.ts').SvelteRequest} svelteRequest + * @param {import('../types/id.d.ts').SvelteRequest | import('../types/id.d.ts').SvelteModuleRequest} svelteRequest * @param {import('svelte/types/compiler/interfaces').Warning[]} warnings * @param {import('../types/options.d.ts').ResolvedOptions} options */ diff --git a/packages/vite-plugin-svelte/src/utils/options.js b/packages/vite-plugin-svelte/src/utils/options.js index e10a50c3c..25375876c 100644 --- a/packages/vite-plugin-svelte/src/utils/options.js +++ b/packages/vite-plugin-svelte/src/utils/options.js @@ -25,6 +25,7 @@ import { import { isCommonDepWithoutSvelteField } from './dependencies.js'; import { VitePluginSvelteStats } from './vite-plugin-svelte-stats.js'; import { VitePluginSvelteCache } from './vite-plugin-svelte-cache.js'; +import { isSvelte5 } from './svelte-version.js'; const allowedPluginOptions = new Set([ 'include', @@ -227,6 +228,10 @@ export function resolveOptions(preResolveOptions, viteConfig, cache) { * @param {import('../types/options.d.ts').ResolvedOptions} options */ function enforceOptionsForHmr(options) { + if (isSvelte5) { + log.warn('svelte 5 does not support hmr api yet, disabling it for now'); + options.hot = false; + } if (options.hot) { if (!options.compilerOptions.dev) { log.warn('hmr is enabled but compilerOptions.dev is false, forcing it to true'); diff --git a/packages/vite-plugin-svelte/src/utils/svelte-version.js b/packages/vite-plugin-svelte/src/utils/svelte-version.js index bc92d43f3..b3d6f7df1 100644 --- a/packages/vite-plugin-svelte/src/utils/svelte-version.js +++ b/packages/vite-plugin-svelte/src/utils/svelte-version.js @@ -4,3 +4,8 @@ import { VERSION } from 'svelte/compiler'; * @type {boolean} */ export const isSvelte3 = VERSION.startsWith('3.'); + +/** + * @type {boolean} + */ +export const isSvelte5 = VERSION.startsWith('5.'); From 61ae116e32cae42b0bc12162f5713984606e86a5 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Thu, 9 Nov 2023 11:12:45 +0100 Subject: [PATCH 03/11] Update ci.yml (#783) * Update ci.yml * seems to work --- .github/workflows/ci.yml | 2 ++ .github/workflows/release.yml | 1 + packages/vite-plugin-svelte/src/index.js | 1 + packages/vite-plugin-svelte/src/utils/esbuild.js | 1 + 4 files changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d10a6722..488dd80f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,10 +6,12 @@ on: branches: - main - v1 + - v2 pull_request: branches: - main - v1 + - v2 env: # we call `pnpm playwright install` instead PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9c9b16f5e..f7c701093 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,6 +5,7 @@ on: branches: - main - v1 + - v2 permissions: {} jobs: diff --git a/packages/vite-plugin-svelte/src/index.js b/packages/vite-plugin-svelte/src/index.js index 9e54442cf..04b484d4e 100644 --- a/packages/vite-plugin-svelte/src/index.js +++ b/packages/vite-plugin-svelte/src/index.js @@ -296,6 +296,7 @@ export function svelte(inlineOptions) { return; } try { + // @ts-ignore doesn't exist in Svelte 4 const compileResult = await svelteCompiler.compileModule(code, { generate: ssr ? 'ssr' : 'dom', filename: moduleRequest.filename diff --git a/packages/vite-plugin-svelte/src/utils/esbuild.js b/packages/vite-plugin-svelte/src/utils/esbuild.js index 9623c1c42..e6df83163 100644 --- a/packages/vite-plugin-svelte/src/utils/esbuild.js +++ b/packages/vite-plugin-svelte/src/utils/esbuild.js @@ -62,6 +62,7 @@ export function esbuildSveltePlugin(options) { async function compileSvelte(options, { filename, code }, statsCollection) { if (isSvelte5 && filename.endsWith(svelteModuleExtension)) { const endStat = statsCollection?.start(filename); + // @ts-ignore doesn't exist in Svelte 4 const compiled = svelte.compileModule(code, { filename, generate: 'dom', From cda2e30a9bd57bf59b7f66a11369de769d40d0b3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Nov 2023 11:13:44 +0100 Subject: [PATCH 04/11] Version Packages (#784) Co-authored-by: github-actions[bot] --- .changeset/poor-avocados-learn.md | 5 ----- packages/vite-plugin-svelte/CHANGELOG.md | 6 ++++++ packages/vite-plugin-svelte/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/poor-avocados-learn.md diff --git a/.changeset/poor-avocados-learn.md b/.changeset/poor-avocados-learn.md deleted file mode 100644 index 7c22ea721..000000000 --- a/.changeset/poor-avocados-learn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@sveltejs/vite-plugin-svelte': minor ---- - -feat: add experimental support for Svelte 5 diff --git a/packages/vite-plugin-svelte/CHANGELOG.md b/packages/vite-plugin-svelte/CHANGELOG.md index 7e5c51de4..ea2de17f5 100644 --- a/packages/vite-plugin-svelte/CHANGELOG.md +++ b/packages/vite-plugin-svelte/CHANGELOG.md @@ -1,5 +1,11 @@ # @sveltejs/vite-plugin-svelte +## 2.5.0 + +### Minor Changes + +- feat: add experimental support for Svelte 5 ([#782](https://github.com/sveltejs/vite-plugin-svelte/pull/782)) + ## 2.4.6 ### Patch Changes diff --git a/packages/vite-plugin-svelte/package.json b/packages/vite-plugin-svelte/package.json index a59871809..63bc865c2 100644 --- a/packages/vite-plugin-svelte/package.json +++ b/packages/vite-plugin-svelte/package.json @@ -1,6 +1,6 @@ { "name": "@sveltejs/vite-plugin-svelte", - "version": "2.4.6", + "version": "2.5.0", "license": "MIT", "author": "dominikg", "files": [ From 95090667d0049c3fe3f238f6d406aabce87f7f44 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 9 Nov 2023 17:03:12 -0500 Subject: [PATCH 05/11] generate: 'client' | 'server' (#785) * generate client/server * changeset * chore: ignore type error for now * chore: fix audit check --------- Co-authored-by: Rich Harris Co-authored-by: dominikg --- .changeset/eleven-hats-search.md | 5 + .../autoprefixer-browerslist/package.json | 2 +- packages/vite-plugin-svelte/src/index.js | 2 +- .../vite-plugin-svelte/src/utils/compile.js | 5 +- .../vite-plugin-svelte/src/utils/esbuild.js | 5 +- pnpm-lock.yaml | 96 +++++++++---------- 6 files changed, 61 insertions(+), 54 deletions(-) create mode 100644 .changeset/eleven-hats-search.md diff --git a/.changeset/eleven-hats-search.md b/.changeset/eleven-hats-search.md new file mode 100644 index 000000000..88d3a9934 --- /dev/null +++ b/.changeset/eleven-hats-search.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/vite-plugin-svelte': patch +--- + +feat: support Svelte 5 compiler API diff --git a/packages/e2e-tests/autoprefixer-browerslist/package.json b/packages/e2e-tests/autoprefixer-browerslist/package.json index 1935658d5..f6099b39c 100644 --- a/packages/e2e-tests/autoprefixer-browerslist/package.json +++ b/packages/e2e-tests/autoprefixer-browerslist/package.json @@ -13,7 +13,7 @@ "devDependencies": { "@sveltejs/vite-plugin-svelte": "workspace:^", "autoprefixer": "^10.4.15", - "postcss": "^8.4.29", + "postcss": "^8.4.31", "postcss-load-config": "^4.0.1", "svelte": "^4.2.0", "svelte-preprocess": "^5.0.4", diff --git a/packages/vite-plugin-svelte/src/index.js b/packages/vite-plugin-svelte/src/index.js index 04b484d4e..8020a09ca 100644 --- a/packages/vite-plugin-svelte/src/index.js +++ b/packages/vite-plugin-svelte/src/index.js @@ -298,7 +298,7 @@ export function svelte(inlineOptions) { try { // @ts-ignore doesn't exist in Svelte 4 const compileResult = await svelteCompiler.compileModule(code, { - generate: ssr ? 'ssr' : 'dom', + generate: isSvelte5 ? (ssr ? 'server' : 'client') : ssr ? 'ssr' : 'dom', filename: moduleRequest.filename }); logCompilerWarnings(moduleRequest, compileResult.warnings, options); diff --git a/packages/vite-plugin-svelte/src/utils/compile.js b/packages/vite-plugin-svelte/src/utils/compile.js index 11c975035..3ac308784 100644 --- a/packages/vite-plugin-svelte/src/utils/compile.js +++ b/packages/vite-plugin-svelte/src/utils/compile.js @@ -9,7 +9,7 @@ import { mapToRelative } from './sourcemaps.js'; const scriptLangRE = /