svelte(lang='ts'
) template to react component converter (PoC)
$ npm install svelte2tsx-component -D
# default css generator is @emotion/css
$ npm install react react-dom @types/react @types/react-dom @emotion/css -D
Concepts
- Generate Component Props Type from
script lang="ts"
, leaving TypeScript type information - Convert svelte’s built-in functionality into an idiom on React with similar results
- Import
.svelte
transparently as React Component - Support only svelte template subset
API
with vite
// vite.config.ts import { defineConfig } from "vite"; import { plugin as svelteToTsx } from "svelte-to-tsx"; import ts from "typescript"; export default defineConfig({ plugins: [svelteToTsx({ extensions: [".svelte"], tsCompilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ESNext, jsx: ts.JsxEmit.ReactJSX, } })], });
Examples
svelte template
const x: number = 1; let mut = 2; onMount(() => { console.log(“mounted”); mut = 4; });
const onClick = () => { console.log(“clicked”); mut = mut + 1; }
Nest
hello, {x}
” dir=”auto”>
<script lang="ts"> import { onMount } from "svelte"; export let foo: number; export let bar: number = 1; const x: number = 1; let mut = 2; onMount(() => { console.log("mounted"); mut = 4; }); const onClick = () => { console.log("clicked"); mut = mut + 1; } script> <div id="x" class="red"> <h1>Nesth1> hello, {x} div> <button on:click={onClick}>clickbutton> <style> .red { color: red; } style>
to tsx component (react
)
Nest
hello, {x}
> ); };
const selector$red = css` color: red; `;” dir=”auto”>
import { useEffect, useState } from "react"; import { css } from "@emotion/css"; export default ({ foo, bar = 1 }: { foo: number; bar?: number }) => { const x: number = 1; const [mut, set$mut] = useState(2); useEffect(() => { console.log("mounted"); set$mut(4); }, []); const onClick = () => { console.log("clicked"); set$mut(mut + 1); }; return ( <> <div id="x" className={selector$red}> <h1>Nest</h1> hello, {x} </div> <button onClick={onClick}>click</button> </> ); }; const selector$red = css` color: red; `;
So you can use like this.
import React from "react"; import App from "./App.svelte"; import { createRoot } from "react-dom/client"; const root = document.getElementById("root")!; createRoot(root).render(<App name="svelte-app" onMessage={(data) => { console.log("message received", data) } } />);
(put App.svelte.d.ts
manually yet)
Transform Convensions
PropsType with export let
svelte
<script lang="ts"> export let foo: number; export let bar: number = 1; script>
tsx
createEventDispatcher<{}>()
svelte
” dir=”auto”>
<script lang="ts"> import {createEventDispatcher} from "svelte"; // Only support ObjectTypeLiteral (TypeReference not supported) const dispatch = createEventDispatcher<{ message: { text: string; }; }>(); const onClick = () => { dispatch('message', { text: 'Hello!' }); } script> <div on:click={onClick}> hello div>
tsx
Expression in svelte template
” dir=”auto”>
<div id="myid">div> <div id={expr}>div> <div id="{expr}">div> <div id="head{expr}tail">div> <div {id}>div> <div {...params}>div>
Slot (default)
svelte
tsx
import { type ReactNode } from "react"; export default ({children}, { children: ReactNode }) => { return <> {children} </>; }
(Named slot not supported)
onMount / onDestroy / beforeUpdate / afterUpdate
Convert to react’s useEffect
style property to object
” dir=”auto”>
<span class="red">textspan> <style> .red: { color: red; } style>
to
const selector$red = css` color: red; `;” dir=”auto”>
// Auto import with style block import { css } from "@emotion/css"; // in tsx <span className={style$red}>text</span> const selector$red = css` color: red; `;
Only support single class selector like .red
.
Not Supported these patterns.
-
style
property with expression- ex.
- ex.
- ex.
-
class
property with expression- ex.
- ex.
- ex.
- Await Block
- Property Bindings
svelte
‘ssetContext
/getContext
/tick
/getAllContexts
svelte/motion
svelte/store
svelte/animation
svelte/transition
svelte/action
- css:
:global()
(Checkboxed item may be supportted latter)
Currently, the scope is not parsed, so unintended variable conflicts may occur.
Basic Features
- Module:
- Props Type:
export let foo: number
to{foo}: {foo: number}
- Props Type:
export let bar: number = 1
to{bar = 1}: {bar?: number}
- svelte:
onMount(() => ...)
=>useEffect(() => ..., [])
- svelte:
onDestroy(() => ...)
=>useEffect(() => { return () => ... }, [])
- svelte:
dispatch('foo', data)
=>onFoo?.(data)
- svelte:
beforeUpdate()
=>useEffect
- svelte:
>>{
>>>>>
Read More