Effective
,Flexible
,Intelligent
Vue JSX
pnpm
pnpm install @westhide/swc-plugin-vue-jsx -D
import { transform } from "@swc/core";
export type PluginOptions = {
// staticVNodes above threshold will compile to html
staticThreshold?: number /* default=5 */;
// regexs match custom element tag
customElementPatterns?: string[];
};
transform(src, {
isModule: true,
jsc: {
target: "es2022",
parser: {
syntax: "typescript",
tsx: true,
},
experimental: {
plugins: [["@westhide/swc-plugin-vue-jsx", {} as PluginOptions]],
},
},
});
pnpm install @westhide/vite-plugin-vue-jsx-swc -D
e.g.
import { type Plugin, createFilter } from "vite";
import { transform } from "@swc/core";
export default function () {
const filter = createFilter(/\.[jt]sx$/);
return {
name: "vite-plugin-vue-jsx",
config() {
return {
esbuild: {
include: /\.ts$/,
},
define: {
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false,
},
};
},
async transform(src, id) {
if (filter(id)) {
return transform(src, {
isModule: true,
jsc: {
target: "es2022",
parser: {
syntax: "typescript",
tsx: true,
},
experimental: {
plugins: [["@westhide/swc-plugin-vue-jsx", {}]],
},
},
});
} else {
return null;
}
},
} as Plugin;
}
Now you can use JSX in Vue Component !
import { defineComponent } from "vue";
export const App = defineComponent({
setup() {
return () => <h1>SWC Plugin Vue JSX</h1>;
},
});
explore
import { defineComponent } from "vue";
import { createTextVNode, createElementVNode } from "vue";
const _hoisted_ = createTextVNode("SWC Plugin Vue JSX"),
_hoisted_1 = createElementVNode("h1", null, [_hoisted_], -1);
export const App = defineComponent({
setup() {
return () => _hoisted_1;
},
});
const vnode = <div></div>;
explore
import { createElementVNode } from "vue";
const _hoisted_ = createElementVNode("div", null, null, -1);
const vnode = _hoisted_;
import { A } from "./componets";
const vnode = <A></A>;
explore
import { A } from "./componets";
import { createVNode } from "vue";
const vnode = createVNode(A, null, null);
const vnode = <A></A>;
explore
import { resolveComponent, createVNode } from "vue";
const vnode = (() => {
const _v = resolveComponent("A");
return createVNode(_v, null, null);
})();
const vnode = <A.b></A.b>;
explore
import { createVNode } from "vue";
const vnode = createVNode(A.b, null, null);
// customElementPatterns: ["custom-tag"]
const vnode = <custom-tag></custom-tag>;
explore
import { createVNode } from "vue";
const vnode = createVNode("custom-tag", null, null);
const vnode = <div class="box"></div>;
explore
import { createElementVNode } from "vue";
const _hoisted_ = createElementVNode("div", { class: "box" }, null, -1);
const vnode = _hoisted_;
const vnode = <input autofocus />;
explore
import { createElementVNode } from "vue";
const _hoisted_ = createElementVNode("input", { autofocus: "" }, null, -1);
const vnode = _hoisted_;
const vnode = <div class={a}></div>;
explore
import { createVNode } from "vue";
const vnode = createVNode("div", { class: a }, null, 2);
const vnode = <div {...a} class="box"></div>;
explore
import { mergeProps, createVNode } from "vue";
const vnode = createVNode("div", mergeProps(a, { class: "box" }), null, 16);
const vnode = <div v-text="msg"></div>;
explore
import { createVNode } from "vue";
const vnode = createVNode("div", { textContent: "msg" }, null);
const vnode = <div v-html="<span>hello</span>"></div>;
explore
import { createVNode } from "vue";
const vnode = createVNode("div", { innerHTML: "<span>hello</span>" }, null);
const vnode = <div v-show={isShow}></div>;
explore
import { createVNode, vShow, withDirectives } from "vue";
const vnode = withDirectives(createVNode("div", null, null, 512), [
[vShow, isShow],
]);
const vnode = <input v-model={val} />;
explore
import { createVNode, vModelText, withDirectives } from "vue";
const vnode = withDirectives(
createVNode(
"input",
{ "onUpdate:modelValue": ($v) => (val = $v) },
null,
512
),
[[vModelText, val]]
);
v-model with arguments
const vnode = <A v-model:title={val}></A>;
explore
import { resolveComponent, createVNode } from "vue";
const vnode = (() => {
const _v = resolveComponent("A");
return createVNode(
_v,
{ title: val, "onUpdate:title": ($v) => (val = $v) },
null,
8,
["title"]
);
})();
const vnode = <div v-custom={val}></div>;
explore
import { createVNode, resolveDirective, withDirectives } from "vue";
const vnode = (() => {
const _v = resolveDirective("custom");
return withDirectives(createVNode("div", null, null, 512), [[_v, val]]);
})();
// const A = (_props, { slots }) => (
// <>
// <h1></h1>
// <h2>{slots.bar?.()}</h2>
// </>
// );
const vnode = <A v-slots={slots}></A>;
explore
import { resolveComponent, createVNode } from "vue";
const vnode = (() => {
const _v = resolveComponent("A");
return createVNode(_v, null, slots, 1024);
})();
mark dynamic VNode information at compile time
- hoist static VNode
- turn consecutive static VNode to html template
// staticThreshold = 5
const tmpl_vnode = (
<>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</>
);
explore
import { Fragment, createStaticVNode, createVNode } from "vue";
const _hoisted_ = createStaticVNode(
"<div >1</div><div >2</div><div >3</div><div >4</div><div >5</div>",
5
);
const tmpl_vnode = createVNode(Fragment, null, [_hoisted_]);
ElementBlock
TODO
- Refactor @vue/babel-plugin-jsx by SWC
- Build Compiler-Informed Virtual DOM with JSX