vue官方推荐的是单文件 .vue 编写组件,简单易学但没有jsx灵活性,很多知名的UI库最终选择了使用jsx,例如:ant-desing-vue, vant。但是在 vue 中使用 jsx 也存在一些问题。比如:大部分 vue 指令无法使用或者很难使用。在 vue3 中专门开了个 issue 讨论解决方案,至今没有优雅的解决方案。 jsv 而不是 jsx 可能是更好的解决方案。
// Scope.vue
<template>
<div>{{ state.count }}</div>
<button @click="handleClick">点击加1</button>
</template>
<script>
import { reactive } from "vue";
export default {
setup() {
let state = reactive({ count: 0 });
function handleClick() {
state.count++;
}
return { state, handleClick };
},
};
</script>
// Scope.jsx
import { reactive } from "vue";
export default {
setup() {
let state = reactive({
count: 0
});
function handleClick() {
state.count++;
}
return ()=>(
<div>
<div >{ state.count }</div>
<button onClick={handleClick}>点击加1</button>
</div>
)
},
};
// NoMulti.vue
<template>
<Title :title="state.title" />
</template>
<script>
import { reactive } from "vue";
import Title from "./Title.vue";
export default {
components: { Title },
setup() {
let state = reactive({ title: "jsv-compiler" });
return { state };
},
};
</script>
// Title.vue
<template>
<h1>hello {{title}}</h1>
</template>
<script>
export default {
props: {
title: String
}
}
</script>
// Multi.jsx
import { reactive } from "vue";
export default {
setup() {
let state = reactive({
title: 'jsv-compiler'
});
let Title = ()=><h1>hello {state.title}</h1>
return ()=>(
<div>
<Title />
</div>
)
},
};
<A v-model:argument.modifer="val" />
<A v-model={[val, 'argument', ['modifier']]} />
// 编译前
<div>
<div>静态节点</div>
<div >{{state.count }}</div>
</div>
// 编译后
const { createVNode: _createVNode, toDisplayString: _toDisplayString, openBlock: _openBlock, createBlock: _createBlock } = Vue
const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "静态节点", -1 /* HOISTED */)
return function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_hoisted_1,
_createVNode("div", null, _toDisplayString(_ctx.state.count), 1 /* TEXT */)
]))
}
// Check the console for the AST
// 编译前
<div>
<div >static node</div>
<div >{ state.count }</div>
</div>
// 编译后 (使用 vite 工具编译)
jsx(
"div",
null /* @__PURE__ */,
jsx("div", null, "static node") /* @__PURE__ */,
jsx("div", null, state.count)
)
那有没有一种解决方案,既有 jsx 的灵活性,又有原生支持vue指令和运行时高性能,在 .js 中直接使用 vue 模板语法?就像这样
import { reactive } from "vue";
export default {
name: "App",
setup() {
let state = reactive({
title: 'jsv-compiler',
count: 0
});
function handleClick() {
state.count++;
}
let Title = <template><h1>hello {{state.title}}</h1></template>
return (
<template>
<Title />
<div>{{ state.count }}</div>
<button v-on:Click="handleClick">点击加1</button>
</template>
)
},
};
目标有了那就开始魔改吧。我写了个编译器集成了vite插件实现:jsv-compiler
npx create-vite-app <your projectname>
npm i -D jsv-compiler
文件: vite.config.js
import {jsvPlugin} from 'jsv-compiler'
export default {
configureServer: [jsvPlugin]
}
// App.js
import { reactive } from "vue";
export default {
name: "App",
setup() {
let state = reactive({
title: 'jsv-compiler',
count: 0
});
function handleClick() {
state.count++;
}
let Title = `<template><h1>hello {{state.title}}</h1></template>`
return (`
<template>
<Title />
<div>{{ state.count }}</div>
<button v-on:Click="handleClick">点击加1</button>
</template>
`)
},
};
在vscode的插件市场中下载插件: jsv
因为是第一个版本,所以需要在 <template></template>
旁边加上反引号 才能在vscode中实现语法高亮,实际在编译层面是不需要加反引号的。
还是用上面那个例子
// 编译前
<div>
<div>静态节点</div>
<div >{{state.count }}</div>
</div>
// 编译后
(() => {
const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "静态节点", -1 /* HOISTED */)
return function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", null, [
_hoisted_1,
_createVNode("div", null, _toDisplayString(
(() => {
try {
return state
} catch {
return _ctx.state
}
})().count), 1 /* TEXT */)
]))
}
})()
(() => {
try {
return state
} catch {
return _ctx.state
}
})()
在 .js 中使用 vue 模板语法 (简称 jsv)
vue3 模板 | jsv | jsx | |
---|---|---|---|
灵活性 | 不灵活 | 灵活 | 灵活 |
文件中组件数量 | 1个文件1个组件 | 1个文件多个组件 | 1个文件多个组件 |
能否使用当前作用域变量 | 不能,需在setup()方法中return后才能使用 | 可以使用 | 可以使用 |
是否很好支持指令 | 原生支持 | 原生支持 | 不支持或支持不友好 |
运行时性能 | 支持hoist,createBlock,patchProps | 支持hoist,createBlock,patchProps | 不支持 |
自动热更新 | 支持 | 不支持 | 不支持 |
值得一提的是 jsv 保持了原本 vue 的高性能,支持hoist,createBlock,patchProps等在 jsx 中难以实现的特性,比 jsx快了近3倍。
可能有人会说为什么要折腾这些?我想说的是 人类对效率的追求总是无止境的,正是像这样的折腾铸就了人类宏伟的科技蓝图。也希望我的一点贡献能抛砖引玉激发起大家的兴趣尝试一下
备注: jsv-compiler