From 649118cbc27cac5d50d57a358f3eb19abd36afe4 Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 6 Feb 2024 19:26:02 +0100 Subject: [PATCH 1/9] feat: add Svelte 5 runes compiler --- src/core/compilers/index.ts | 2 ++ src/core/compilers/svelte-runes.ts | 4 ++++ src/core/compilers/svelte.ts | 8 +++++--- src/types.ts | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 src/core/compilers/svelte-runes.ts diff --git a/src/core/compilers/index.ts b/src/core/compilers/index.ts index 64fc175d..ae8b160d 100644 --- a/src/core/compilers/index.ts +++ b/src/core/compilers/index.ts @@ -11,6 +11,7 @@ import type { Compiler, CustomCompiler } from './types' import { Vue2Compiler } from './vue2' import { Vue3Compiler } from './vue3' import { WebComponentsCompiler } from './web-components' +import { SvelteRunesCompiler } from './svelte-runes' export const compilers: Record, Compiler> = { 'astro': AstroCompiler, @@ -20,6 +21,7 @@ export const compilers: Record compileSvelte(svg, true)) as Compiler diff --git a/src/core/compilers/svelte.ts b/src/core/compilers/svelte.ts index f82160b3..9008f766 100644 --- a/src/core/compilers/svelte.ts +++ b/src/core/compilers/svelte.ts @@ -1,13 +1,15 @@ import type { Compiler } from './types' -export const SvelteCompiler = ((svg: string) => { +export const SvelteCompiler = ((svg: string) => compileSvelte(svg)) as Compiler + +export function compileSvelte(svg: string, runes = false) { const openTagEnd = svg.indexOf('>', svg.indexOf('` + const openTag = `${svg.slice(0, openTagEnd)} {...${runes ? '' : '$'}$props}>` const content = `{@html \`${escapeSvelte(svg.slice(openTagEnd + 1, closeTagStart))}\`}` const closeTag = svg.slice(closeTagStart) return `${openTag}${content}${closeTag}` -}) as Compiler +} // escape curlies, backtick, \t, \r, \n to avoid breaking output of {@html `here`} in .svelte export function escapeSvelte(str: string): string { diff --git a/src/types.ts b/src/types.ts index d4ff3767..da5d05aa 100644 --- a/src/types.ts +++ b/src/types.ts @@ -70,7 +70,7 @@ export interface Options { * * @default (detect automatically, fallback to 'vue3') */ - compiler?: 'astro' | 'jsx' | 'marko' | 'none' | 'solid' | 'svelte' | 'raw' | 'vue2' | 'vue3' | 'web-components' | 'qwik' | CustomCompiler + compiler?: 'astro' | 'jsx' | 'marko' | 'none' | 'solid' | 'svelte' | 'svelte-runes' | 'raw' | 'vue2' | 'vue3' | 'web-components' | 'qwik' | CustomCompiler /** * JSX style, works only when compiler set to `jsx` From 7b91149513a4ce93281a93716b52f861a2d0d5f5 Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 6 Feb 2024 19:53:04 +0100 Subject: [PATCH 2/9] chore: include svelte extension for new compiler --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index 7567ca06..182e5eac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,6 +36,7 @@ const unplugin = createUnplugin((options = {}) => { case 'marko': return `${res}.marko` case 'svelte': + case 'svelte-runes': return `${res}.svelte` case 'solid': return `${res}.tsx` From 5752370656961c7d6e324c364ae0eaa5cb94c293 Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 6 Feb 2024 20:23:46 +0100 Subject: [PATCH 3/9] chore: include script for runes --- src/core/compilers/svelte.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/compilers/svelte.ts b/src/core/compilers/svelte.ts index 9008f766..d8c63962 100644 --- a/src/core/compilers/svelte.ts +++ b/src/core/compilers/svelte.ts @@ -5,10 +5,11 @@ export const SvelteCompiler = ((svg: string) => compileSvelte(svg)) as Compiler export function compileSvelte(svg: string, runes = false) { const openTagEnd = svg.indexOf('>', svg.indexOf('` + const openTag = `${svg.slice(0, openTagEnd)} {...${runes ? '' : '$$'}props}>` const content = `{@html \`${escapeSvelte(svg.slice(openTagEnd + 1, closeTagStart))}\`}` const closeTag = svg.slice(closeTagStart) - return `${openTag}${content}${closeTag}` + const sfc = `${openTag}${content}${closeTag}` + return runes ? `\n${sfc}` : sfc } // escape curlies, backtick, \t, \r, \n to avoid breaking output of {@html `here`} in .svelte From c6a0a3664d56af6f8f1520b4b2ee164d3da4e29a Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 6 Feb 2024 20:36:04 +0100 Subject: [PATCH 4/9] chore: simpley runes code --- src/core/compilers/svelte.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/compilers/svelte.ts b/src/core/compilers/svelte.ts index d8c63962..c64ae524 100644 --- a/src/core/compilers/svelte.ts +++ b/src/core/compilers/svelte.ts @@ -5,11 +5,11 @@ export const SvelteCompiler = ((svg: string) => compileSvelte(svg)) as Compiler export function compileSvelte(svg: string, runes = false) { const openTagEnd = svg.indexOf('>', svg.indexOf('` + const openTag = `${svg.slice(0, openTagEnd)} {...${runes ? 'p' : '$$props'}}>` const content = `{@html \`${escapeSvelte(svg.slice(openTagEnd + 1, closeTagStart))}\`}` const closeTag = svg.slice(closeTagStart) const sfc = `${openTag}${content}${closeTag}` - return runes ? `\n${sfc}` : sfc + return runes ? `${sfc}` : sfc } // escape curlies, backtick, \t, \r, \n to avoid breaking output of {@html `here`} in .svelte From 93b3096456f7b93e120e2cff4aece70809248191 Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 6 Feb 2024 20:37:45 +0100 Subject: [PATCH 5/9] chore: minify runes code --- src/core/compilers/svelte.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/compilers/svelte.ts b/src/core/compilers/svelte.ts index c64ae524..5fd25473 100644 --- a/src/core/compilers/svelte.ts +++ b/src/core/compilers/svelte.ts @@ -9,7 +9,7 @@ export function compileSvelte(svg: string, runes = false) { const content = `{@html \`${escapeSvelte(svg.slice(openTagEnd + 1, closeTagStart))}\`}` const closeTag = svg.slice(closeTagStart) const sfc = `${openTag}${content}${closeTag}` - return runes ? `${sfc}` : sfc + return runes ? `${sfc}` : sfc } // escape curlies, backtick, \t, \r, \n to avoid breaking output of {@html `here`} in .svelte From b7641b9840502c0b20c67dccf6b8767c78a039ed Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 6 Feb 2024 22:09:19 +0100 Subject: [PATCH 6/9] chore: remove svelte-runes compiler (will be auto) --- src/core/compilers/index.ts | 2 -- src/core/compilers/svelte-runes.ts | 4 ---- src/core/compilers/svelte.ts | 11 +++++++---- src/index.ts | 1 - src/types.ts | 2 +- 5 files changed, 8 insertions(+), 12 deletions(-) delete mode 100644 src/core/compilers/svelte-runes.ts diff --git a/src/core/compilers/index.ts b/src/core/compilers/index.ts index ae8b160d..64fc175d 100644 --- a/src/core/compilers/index.ts +++ b/src/core/compilers/index.ts @@ -11,7 +11,6 @@ import type { Compiler, CustomCompiler } from './types' import { Vue2Compiler } from './vue2' import { Vue3Compiler } from './vue3' import { WebComponentsCompiler } from './web-components' -import { SvelteRunesCompiler } from './svelte-runes' export const compilers: Record, Compiler> = { 'astro': AstroCompiler, @@ -21,7 +20,6 @@ export const compilers: Record compileSvelte(svg, true)) as Compiler diff --git a/src/core/compilers/svelte.ts b/src/core/compilers/svelte.ts index 5fd25473..79973575 100644 --- a/src/core/compilers/svelte.ts +++ b/src/core/compilers/svelte.ts @@ -1,8 +1,11 @@ import type { Compiler } from './types' -export const SvelteCompiler = ((svg: string) => compileSvelte(svg)) as Compiler - -export function compileSvelte(svg: string, runes = false) { +export const SvelteCompiler = (async (svg: string) => { + // @ts-expect-error we don't have svelte as dependency + const runes = await import('svelte/compiler').then((pkg) => { + const major = 'VERSION' in pkg ? Number.parseInt(pkg.VERSION.split('.')[0]) : undefined + return major && !Number.isNaN(major) && major >= 5 + }).catch(() => false) const openTagEnd = svg.indexOf('>', svg.indexOf('` @@ -10,7 +13,7 @@ export function compileSvelte(svg: string, runes = false) { const closeTag = svg.slice(closeTagStart) const sfc = `${openTag}${content}${closeTag}` return runes ? `${sfc}` : sfc -} +}) as Compiler // escape curlies, backtick, \t, \r, \n to avoid breaking output of {@html `here`} in .svelte export function escapeSvelte(str: string): string { diff --git a/src/index.ts b/src/index.ts index 182e5eac..7567ca06 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,7 +36,6 @@ const unplugin = createUnplugin((options = {}) => { case 'marko': return `${res}.marko` case 'svelte': - case 'svelte-runes': return `${res}.svelte` case 'solid': return `${res}.tsx` diff --git a/src/types.ts b/src/types.ts index da5d05aa..d4ff3767 100644 --- a/src/types.ts +++ b/src/types.ts @@ -70,7 +70,7 @@ export interface Options { * * @default (detect automatically, fallback to 'vue3') */ - compiler?: 'astro' | 'jsx' | 'marko' | 'none' | 'solid' | 'svelte' | 'svelte-runes' | 'raw' | 'vue2' | 'vue3' | 'web-components' | 'qwik' | CustomCompiler + compiler?: 'astro' | 'jsx' | 'marko' | 'none' | 'solid' | 'svelte' | 'raw' | 'vue2' | 'vue3' | 'web-components' | 'qwik' | CustomCompiler /** * JSX style, works only when compiler set to `jsx` From 9d6d706fbdc37f293392165c9d64256831efa3e7 Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 6 Feb 2024 22:24:15 +0100 Subject: [PATCH 7/9] perf: memoize svelte runes --- src/core/compilers/svelte.ts | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/core/compilers/svelte.ts b/src/core/compilers/svelte.ts index 79973575..37b3c004 100644 --- a/src/core/compilers/svelte.ts +++ b/src/core/compilers/svelte.ts @@ -1,18 +1,25 @@ import type { Compiler } from './types' +let svelteRunes: boolean | undefined + export const SvelteCompiler = (async (svg: string) => { - // @ts-expect-error we don't have svelte as dependency - const runes = await import('svelte/compiler').then((pkg) => { - const major = 'VERSION' in pkg ? Number.parseInt(pkg.VERSION.split('.')[0]) : undefined - return major && !Number.isNaN(major) && major >= 5 - }).catch(() => false) + if (typeof svelteRunes === 'undefined') { + try { + // @ts-expect-error we don't have svelte as dependency + const { VERSION } = await import('svelte/compiler') + svelteRunes = Number(VERSION.split('.')[0]) >= 5 + } + catch { + svelteRunes = false + } + } const openTagEnd = svg.indexOf('>', svg.indexOf('` + const openTag = `${svg.slice(0, openTagEnd)} {...${svelteRunes ? 'p' : '$$props'}}>` const content = `{@html \`${escapeSvelte(svg.slice(openTagEnd + 1, closeTagStart))}\`}` const closeTag = svg.slice(closeTagStart) const sfc = `${openTag}${content}${closeTag}` - return runes ? `${sfc}` : sfc + return svelteRunes ? `${sfc}` : sfc }) as Compiler // escape curlies, backtick, \t, \r, \n to avoid breaking output of {@html `here`} in .svelte From b2f095c55c01ad216758984a15f5546519bd4e23 Mon Sep 17 00:00:00 2001 From: userquin Date: Tue, 6 Feb 2024 22:50:01 +0100 Subject: [PATCH 8/9] perf: use null check --- src/core/compilers/svelte.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/compilers/svelte.ts b/src/core/compilers/svelte.ts index 37b3c004..9d766494 100644 --- a/src/core/compilers/svelte.ts +++ b/src/core/compilers/svelte.ts @@ -1,9 +1,9 @@ import type { Compiler } from './types' -let svelteRunes: boolean | undefined +let svelteRunes: boolean | null export const SvelteCompiler = (async (svg: string) => { - if (typeof svelteRunes === 'undefined') { + if (svelteRunes == null) { try { // @ts-expect-error we don't have svelte as dependency const { VERSION } = await import('svelte/compiler') From 3fc1d3dac0380ef9c21b6652115e148d7fd79d48 Mon Sep 17 00:00:00 2001 From: userquin Date: Wed, 7 Feb 2024 00:04:47 +0100 Subject: [PATCH 9/9] perf: include runes optimization --- src/core/compilers/svelte.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core/compilers/svelte.ts b/src/core/compilers/svelte.ts index 9d766494..411c3d20 100644 --- a/src/core/compilers/svelte.ts +++ b/src/core/compilers/svelte.ts @@ -15,10 +15,13 @@ export const SvelteCompiler = (async (svg: string) => { } const openTagEnd = svg.indexOf('>', svg.indexOf('` - const content = `{@html \`${escapeSvelte(svg.slice(openTagEnd + 1, closeTagStart))}\`}` - const closeTag = svg.slice(closeTagStart) - const sfc = `${openTag}${content}${closeTag}` + let sfc = `${svg.slice(0, openTagEnd)} {...${svelteRunes ? 'p' : '$$props'}}>` + if (svelteRunes) + sfc += svg.slice(openTagEnd + 1, closeTagStart) + else + sfc += `{@html \`${escapeSvelte(svg.slice(openTagEnd + 1, closeTagStart))}\`}` + + sfc += svg.slice(closeTagStart) return svelteRunes ? `${sfc}` : sfc }) as Compiler