vuejs / babel-plugin-jsx Goto Github PK
View Code? Open in Web Editor NEWJSX for Vue 3
Home Page: https://vue-jsx-explorer.netlify.app
License: MIT License
JSX for Vue 3
Home Page: https://vue-jsx-explorer.netlify.app
License: MIT License
In vue2 with composition-api: I have the following (simplified) code:
export default defineComponent({
name: "c-item-description",
props: {
item: {
type: Object,
default: () => ({})
},
presentationComponent: String,
},
setup(props, context) {
const { dynamicComponentRef} = useItemDescriptionConfiguration(props);
return () => {
const DynamicComponent: any = dynamicComponentRef.value || "t-item-description";
return (
<keep-alive>
<DynamicComponent
item={props.item}
/>
</keep-alive>
);
};
}
});
I found a workaround. Is it supposed to be so?
import { defineComponent, computed, ref,getCurrentInstance } from 'vue';
export default defineComponent({
name: "tsx-world",
props: {
msg: String
},
setup(props, context) {
const dynamicComponent = ref("local-title"); // read from configuration
const myTitleRef = computed(()=>getCurrentInstance()?.appContext?.components[dynamicComponent.value]);
return () => {
const myTitle = myTitleRef.value;
return (
<myTitle
msg="dynamic component"
/>
);}
}
});
我用cli 新建了一个vue3.0的项目发现里面能够直接使用jsx
// Test Component
const Test = () => <div>Vue 3 JSX</div>
// Use Test
<test></test>
Cause Error: h is not a function
template
<div
v-model:expandedKeys="expandedKeys"
v-model:selectedKeys="selectedKeys"
v-model:checkedKeys="checkedKeys">
</div>
How to use it in JSX?
<div
v-model={[expandedKeys,'expandedKeys']}>
v-model={[selectedKeys,'selectedKeys']}>
</div>
JSX elements cannot have more than one attribute with the same name
https://v3.vuejs.org/guide/migration/v-model.html#v-model-arguments
<A
v-model={[value, 'value']}
v-model={[visible, 'visible']} />
JSX elements cannot have multiple attributes with the same name
Implementation Detail and new Design to discuss
I want use v-model:title like
<input v-model:title={state.title}>
<Comp>
{() => <span></span>}
</Comp>
By default slot will be parsed to function to be performent, but if we write it to a function, it should stay that instead of wrap it to another function.
I think () => <span></span>
is just what we called scopedSlot
in vue.
I'm actually working on a Vue3 project with rollup and babel (ES6).
The transition
is inserted as a dom node and is not recognized by VueJS.
That's my code.
export default {
// ...
render() {
return (
<transition name="fade" mode="out-in">
{this.title && <Title title={this.title} />}
</transition>
);
}
};
Turn into this.
e.createVNode(
e.resolveComponent("transition"),
{ name: "fade", mode:"out-in" },
{ default: () => [ this.game && e.createVNode(p, null, null) ] }
);
And looks like this in the DOM Tree.
<transition name="fade" mode="out-in"> <!-- Why this div exist ? -->
<div id="title">
You are <span class="secondary">Innocent</span>
</div>
</transition>
I don't understand where the issue could come from, maybe a JSX translation error or an issue relative to Vue3 ?
<compoentA>
<template slot="name"></template>
or
<template vSlot="name"></template>
or
<template v-slot="name"></template>
</componentA>
I can not get $slots.name
I may have missed the reasoning but I just noticed the usage of v-slots
which is quite odd.
A more straightforward syntax should be:
const slots = {
default: () => <div>default</div>,
foo: () => <div>bar</div>
}
<Comp>{slots}</Comp>
Or inline:
<Comp>{{
default: () => <div>default</div>,
foo: () => <div>bar</div>
}}</Comp>
vue template
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
How to use it in JSX?
开启optimize的影响会有什么,看起来诱惑很大,但是又不知道具体影响会是什么。跟vue3的什么有关系。
开启和关闭具体的优化提升又是多少
Some of my components are written in jsx (vue@2)
For example:
<script>
import isArray from 'lodash/isArray'
import isFunction from 'lodash/isFunction'
import map from 'lodash/map'
import { NewBsBox } from '@myComp'
export default {
name: 'Paragraph',
functional: true,
props: {
content: {
type: [String, Function, Array],
},
bs: {
type: Object,
default: () => ({}),
},
},
render(h, { props }) {
const { content, bs } = props
let lst = content
if (!isArray(lst)) {
lst = [lst]
}
return (
<NewBsBox bs={bs}>
{
map(lst, txt => {
let text = txt
if (isFunction(text)) {
text = text(h)
}
return <NewBsBox>{text}</NewBsBox>
})
}
</NewBsBox>
)
},
}
</script>
If migrate to vue@3. Do i have to rewrite all my jsx components?
there is error when setup with vue 3 , vue router next . and this plugin
Home.jsx
export default {
name: "Home",
setup() {
return () => (
<div class="home">
<img alte="Vue Logo" src="../assets/logo.png" />
</div>
);
}
};
router/index.js
import { createRouter, createWebHashHistory } from "vue-router";
import Home from "../views/Home.jsx";
const routes = [
{
path: "/",
name: "Home",
component: Home
}
];
const router = createRouter({
history: createWebHashHistory(),
routes
});
export default router;
babel.config.js
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: ["@ant-design-vue/babel-plugin-jsx"]
};
The Error when open home route in the console
TypeError: Cannot read property '$createElement' of undefined
at setup (Home.jsx?6389:3)
目前的写法是
return (
<div>
<RouterView>
{{
default: ({ Component, route }: { Component: any; route: RouteLocation }) => {
const name = route.meta.inTab ? 'fade' : null;
const Content = (
<KeepAlive max={max} include={cacheTabs}>
<Component />
</KeepAlive>);
return (
<Transition
name={name}
mode="out-in"
appear={true}
>
{Content}
</Transition>
);
},
}}
</RouterView>
</div>
异常:
Uncaught (in promise) TypeError: Cannot read property '_' of null
at initSlots (runtime-core.esm-bundler.js?5c40:2731)
at setupComponent (runtime-core.esm-bundler.js?5c40:6183)
at mountComponent (runtime-core.esm-bundler.js?5c40:3960)
at processComponent (runtime-core.esm-bundler.js?5c40:3936)
at patch (runtime-core.esm-bundler.js?5c40:3547)
at componentEffect (runtime-core.esm-bundler.js?5c40:4053)
at reactiveEffect (reactivity.esm-bundler.js?a1e9:42)
at effect (reactivity.esm-bundler.js?a1e9:17)
at setupRenderEffect (runtime-core.esm-bundler.js?5c40:4018)
at mountComponent (runtime-core.esm-bundler.js?5c40:3976)
单独使用 RouteView
+ KeepAlive
与 RouteView
+ Transition
都没有任何问题,就是 KeepAlive
+ Transition
一起就会出问题。
另外也尝试过使用 slots / defineAsyncComponent 等方式
<KeepAlive max={max} include={cacheTabs} v-slots={{default: ()=> <Component />}} />
// or
<KeepAlive max={max} include={cacheTabs} >
{defineAsyncComponent(Component)}
</KeepAlive>
... Transition 一致
const Content = (
<Transition
name={name}
mode="out-in"
appear={true}
>
<Component />
</Transition>
);
return (
<KeepAlive max={max} include={cacheTabs}>
<Content />
</KeepAlive>);
均只能 KeepAlive
与 Transition
不在一起使用时正常。
在 vite 中测试了一下是可以一起使用的。 似乎 children 在 vite 是个array,在这边是个 object ? 不太清楚。。。
edit:
在KeepAlive外层加入 <div></div>
就不会报错,但Transition失效,估计要调整一下。
I tried v-on
, on
, vOn
, none worked. What is the correct way to bind an event?
jsx: 1.0.0-beta.1
vue: 3.0.0-beta.20
return (
<>
<h1>test</h1>
{false && (
<h1>test</h1>
)}
</>
);
return (
<>
{false && (
<h1>test</h1>
)}
<h1>test</h1>
</>
);
Keeps failing with Invalid VNode type: undefined (undefined)
error.
return (
<>
{false && (
<h1>test</h1>
)}
</>
);
If you leave only the conditional, it works fine.
上级组件:
import { defineComponent, ref, reactive } from "vue";
import List from "@/components/List";
const Home = defineComponent(() => {
const list = ref([
5
]);
const flag = ref(
false
);
const list2 = reactive([
2, 3, 4, 5, 6
])
console.log(list);
const handleClick = () => {
list2[2] = 1003;
}
const handleClick2 = () => {
list2[2] = -10000;
}
return () => (
<>
// 使用list组件
{
list.value.map((item) =>
true
:false
{
list2.map((item) =>
<h1>{item}</h1>
)
}
</>
);
})
export default Home;
// list 组件
import { onMounted, ref } from "vue";
const List = {
setup() {
const num = ref(0);
onMounted(() => {
console.log('aaa')
});
return () =>
}
}
export default List;
组件定义Tag.tsx
import { defineComponent, PropType } from 'vue'
export default defineComponent({
name: 'Tag',
props: {
value: {
type: String as PropType<string>,
// !!! 下一行代码是导致出错的地方
required: true,
},
},
emits: ['update:value'],
setup(props, { emit }) {
// 这里用InputEvent 会出错
const handleInput = (e: any) => {
emit('update:value', e.target.value)
}
return () => {
const { value } = props
return <input type="text" value={value} onInput={handleInput} />
}
},
})
组件使用demo.tsx
import { defineComponent, ref } from 'vue'
import Tag from './Tag'
export default defineComponent({
setup() {
const modelValue = ref('')
return () => {
return (
<>
<h1>{modelValue.value}</h1>
{/* 这样写不出错,但太麻烦了 */}
<Tag
value={modelValue.value}
{...{
'onUpdate:value': ($event: string) => (modelValue.value = $event),
}}
/>
{/* !!!!! 下一行代码ts会出错 */}
<Tag v-model={[modelValue.value, 'value']} />
</>
)
}
},
})
must declarative import from JS
import Logo from '@/assets/logo.png'
const App = defineComponent({
setup() {
return () => (<img alt="Vue logo" src={Logo} />)
},
})
directly import local img by absolute path string
const App = defineComponent({
setup() {
return () => (<img alt="Vue logo" src="./assets/logo.png" />)
},
})
I'm using the compiled file in the browser (Chromium only), and I need to specify the path like this (otherwise it throws an error):
import { createApp, createVNode, createTextVNode } from "./vue-files/vue.esm-browser.js";
Even if I add this line manually, the plugin still adds
import { createVNode, createTextVNode } from "vue";
which causes an error.
P.S. I've found https://github.com/FollowmeTech/babel-plugin-replace-import-path
which replaces the path automatically. Leaving it here in case someone finds it helpful, or if someone knows a better solution.
Since Vue 3 allows for custom renderers as an alternative to @vue/runtime-dom, A custom runtime might have it's own collection of 'native' elements. See Vugel for a good example. It supports built-in tags like <shader>
and <container>
.
At the moment @vue/babel-plugin-jsx
will flag unknown native elements as a callExpression
(https://github.com/vuejs/jsx-next/blob/dev/packages/babel-plugin-jsx/src/utils.ts#L111) if they are not matched in the catalog of known svg or html tags. How can we allow new native elements to be compatible JSX in Vue?
Hi, there is a problom when I use jsx-next。I try [email protected] with jsx-next. here.
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": [
"@vue/babel-plugin-jsx",
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": false,
"helpers": true,
"regenerator": true,
"useESModules": false,
"version": "7.0.0-beta.0"
}
]
]
}
{
// ...
"dependencies": {
"axios": "^0.20.0",
"classnames": "^2.2.6",
"lodash": "^4.17.20",
"vue": "^3.0.0-rc.10",
"vue-cookies": "^1.7.4",
"vue-i18n": "^8.21.0",
"vue-router": "^4.0.0-beta.9",
"vuex": "^4.0.0-beta.4"
}
// ...
}
import Layout from 'layout/Layout';
import Hello from 'views/Hello';
import Book from 'views/Book';
const routes = [
{
path: '/',
component: Layout,
children: [
{
path: '/',
redirect: '/home',
},
{
path: '/home',
component: Hello,
},
{
path: '/book',
component: Book,
},
],
},
];
export default routes;
const Book = () => <div>this is Book component!</div>;
export default Book;
but, I got a error info.
runtime-core.esm-bundler.js:153 [Vue warn]: Component "default" in record with path "/book" is a function that does not return a Promise. If you were passing a functional component, make sure to add a "displayName" to the component. This will break in production if not fixed.
help me, thanks
when this plugin stable version will be released?
is there any thing not finished in the RC to consider it not stable ?
I could not find the usage of Multiple v-model bindings
in the documentation.
在slot中使用template标签不显示
const slots = { default: () => { <template> <NavMenuItem /> <NavMenuItem /> </template> } }
jsx: 1.0.0-beta.3
vue: 3.0.0-beta.23
import { h, Transition } from 'vue';
function MyTransition(props, ctx) {
return h(Transition, ctx.slots.default);
}
setup() {
const isOpen = ref(false);
setInterval(() => { isOpen.value = !isOpen.value }, 1000);
return () => <MyTransition>{isOpen.value && <h1>Visible</h1>}</MyTransition>;
}
does not seem to trigger an update on isOpen
change. Converting it to an h
function:
return () => h(MyTransition, isOpen.value ? <h1>Visible</h1> : null);
// or recommended
return () => h(MyTransition, () => isOpen.value ? <h1>Visible</h1> : null);
works fine though. I tried converting functional component to a normal component but the problem persists.
version
vue: 3.0.0
rollup:2.28.2
@vue/babel-plugin-jsx: 1.0.0-rc.3
babel.config
{
"plugins": ["@vue/babel-plugin-jsx"]
}
const bar: any = {
name: "BBar",
render() {
return (
<div class="bar">
<div class="bar_text">aaa</div>
</div>
);
},
};
bar.install = (app) => {
app.component(bar.name, bar);
};
export default bar;
var bar = {
name: "BBar",
render: function () {
return vue.createVNode("div", {
"class": "bar"
}, [vue.createVNode("div", {
"class": "bar_text"
}, [vue.createTextVNode("aaa")])]);
}
};
bar.install = function (app) {
app.component(bar.name, bar);
};
When the page is displayed, the 'AAA' is not displayed, but the class name exists.
import bar from "../../lib/bar";
import App from "./App.vue";
const app = createApp(App);
app.use(bar );
app.mount("#app");
import { provide } from 'vue';
cosnt Component =(props,{slots})=>{
provide('a',233);
return <div>slots.default()</div>
}
it produces [Vue warn]: provide() can only be used inside setup().
so it's my problem?
const Slots = {
default: (router) => (
<KeepAlive>
<component is={router.Component}></component>
</KeepAlive>
)
}
return () => (
<KeepAlive>
<router-view v-slots={Slots}></router-view>
</KeepAlive>
)
[Vue warn]: Component is missing template or render function.
at <Anonymous is= {__v_isVNode: true, __v_skip: true, type: {…}, props: {…}, key: null, …}anchor: nullappContext: nullchildren: nullcomponent: nulldirs: nulldynamicChildren: nulldynamicProps: nullel: nullkey: nullpatchFlag: 0props: {ref: RefImpl, onVnodeUnmounted: ƒ}ref: {i: {…}, r: RefImpl}scopeId: nullshapeFlag: 4ssContent: nullssFallback: nullstaticCount: 0suspense: nulltarget: nulltargetAnchor: nulltransition: nulltype: {name: "XXXXXX", render: ƒ}__v_isVNode: true__v_skip: true__proto__: Object >
at <KeepAlive>
at <RouterView>
Hello team,
I am currently developing new library that would output JSX template, so this output could be used in Vue and React projects.
Unfortunately, I found this library does not adhere DOM API same way as React do. My issue is caused by using className
instead of just class
, because I am using object destructing I cannot use class
keyword. Same situation would happen by using htmlFor
instead of just for
. Both class
and for
are reserved keywords and cannot be used in object destructing.
So I want to ask, if there is possibility to introduce new option to convert those two attributes.
Thanks
isCustomElement只能在编译环境进行配置
index.js
import { h } from 'vue'
import Button from 'button.ts.vue' // button.ts
I quote the vue file, but the compiled ts file
const App = {
data() {
return { visible:false};
},
render() {
return <input v-show={this.visible} />;
},
};
Browser display:
<input v-show="false">
Directives did not parse properly
custom directive did not parse properly
import { SearchOutlined } from '@ant-design/icons-vue';
vite
runtime-dom.esm-bundler-4d575bf8.js:1180 [Vue warn]: SyntaxError: The requested module '/@modules/tinycolor2/tinycolor.js' does not provide an export named 'default'
I am using vue js, without cli, since I need to configure webpack myself. I couldn't make jsx (vuejs 3) hot update by webpack HMR, and documentation about it is really poor and I spent several hours searching and trying to make it work.
Is there any package, which provides need loader?
<Button loading={true} {...otherProps}></Button>
loading will override otherProps.loading
When creating a project with the latest version of the vue cli (4.5.7), you can select jsx, typescript, or vue-class-component to create the project together, but errors are generated in the project.
<script lang="ts">
import { Options, Vue } from "vue-class-component";
@Options({})
export default class Home extends Vue {
render(){
return (
<div>456</div>
)
}
}
</script>
const Child = defineComponent({
props: {
label: String
},
setup(_, ctx) {
return () => [
<div>{_.label}</div>,
<input {...ctx.attrs}/>
];
}
});
const Parent = defineComponent(() => {
return () => <Child label="test" placeholder="please input"/>;
});
This code will show a error as following.
Type '{ label: string; placeholder: string; }' is not assignable to type 'IntrinsicAttributes & Partial<{}> & Pick<Readonly<{} & { label?: string | undefined; }> & VNodeProps & AllowedComponentProps & ComponentCustomProps, "label" | ... 9 more ... | "class">'.
Property 'placeholder' does not exist on type 'IntrinsicAttributes & Partial<{}> & Pick<Readonly<{} & { label?: string | undefined; }> & VNodeProps & AllowedComponentProps & ComponentCustomProps, "label" | ... 9 more ... | "class">'
<script lang="ts">
...
render() {
return <div></div> // Cannot find name 'div'.Vetur(2304)
}
</script>
在js状态下正常
like <Menu.Item />
Is there any way to use this jsx plugin via cdn? Just like babel.min.js do with react.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.