Skip to content

westhide/swc-plugin-vue-jsx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SWC Plugin for Vue JSX

npm package

Effective,Flexible,Intelligent Vue JSX

Install

pnpm

pnpm install @westhide/swc-plugin-vue-jsx -D

Usage

SWC

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]],
    },
  },
});

Vite

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;
  },
});

Syntax

Tag

native

const vnode = <div></div>;
explore
import { createElementVNode } from "vue";

const _hoisted_ = createElementVNode("div", null, null, -1);

const vnode = _hoisted_;

componet

import { A } from "./componets";

const vnode = <A></A>;
explore
import { A } from "./componets";
import { createVNode } from "vue";

const vnode = createVNode(A, null, null);

resolveComponet

const vnode = <A></A>;
explore
import { resolveComponent, createVNode } from "vue";

const vnode = (() => {
  const _v = resolveComponent("A");
  return createVNode(_v, null, null);
})();

member

const vnode = <A.b></A.b>;
explore
import { createVNode } from "vue";

const vnode = createVNode(A.b, null, null);

custom

// customElementPatterns: ["custom-tag"]

const vnode = <custom-tag></custom-tag>;
explore
import { createVNode } from "vue";

const vnode = createVNode("custom-tag", null, null);

Attribute / Prop

literal

const vnode = <div class="box"></div>;
explore
import { createElementVNode } from "vue";

const _hoisted_ = createElementVNode("div", { class: "box" }, null, -1);

const vnode = _hoisted_;

boolean attribute

const vnode = <input autofocus />;
explore
import { createElementVNode } from "vue";

const _hoisted_ = createElementVNode("input", { autofocus: "" }, null, -1);

const vnode = _hoisted_;

binding

const vnode = <div class={a}></div>;
explore
import { createVNode } from "vue";

const vnode = createVNode("div", { class: a }, null, 2);

spread / mergeProps

const vnode = <div {...a} class="box"></div>;
explore
import { mergeProps, createVNode } from "vue";

const vnode = createVNode("div", mergeProps(a, { class: "box" }), null, 16);

Directive

v-text

const vnode = <div v-text="msg"></div>;
explore
import { createVNode } from "vue";

const vnode = createVNode("div", { textContent: "msg" }, null);

v-html

const vnode = <div v-html="<span>hello</span>"></div>;
explore
import { createVNode } from "vue";

const vnode = createVNode("div", { innerHTML: "<span>hello</span>" }, null);

v-show

const vnode = <div v-show={isShow}></div>;
explore
import { createVNode, vShow, withDirectives } from "vue";

const vnode = withDirectives(createVNode("div", null, null, 512), [
  [vShow, isShow],
]);

v-modelwip

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"]
  );
})();

custom

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]]);
})();

Slotwip

v-slots

// 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);
})();

Features

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

Motive

About

SWC Plugin for Vue JSX

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published