mirror of
https://github.com/vuejs/babel-plugin-jsx.git
synced 2025-01-27 00:29:10 +08:00
support Fragment
This commit is contained in:
parent
9608e0afca
commit
68da671c5a
@ -24,7 +24,7 @@ const App = defineComponent(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div>
|
<>
|
||||||
Foo {count.value}
|
Foo {count.value}
|
||||||
<SuperButton
|
<SuperButton
|
||||||
buttonText="VueComponent"
|
buttonText="VueComponent"
|
||||||
@ -33,7 +33,7 @@ const App = defineComponent(() => {
|
|||||||
click: inc,
|
click: inc,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
"@babel/helper-module-imports": "^7.8.3",
|
"@babel/helper-module-imports": "^7.8.3",
|
||||||
"@babel/plugin-syntax-jsx": "^7.8.3",
|
"@babel/plugin-syntax-jsx": "^7.8.3",
|
||||||
"@babel/types": "^7.9.6",
|
"@babel/types": "^7.9.6",
|
||||||
"@vue/babel-preset-jsx": "^1.1.2",
|
|
||||||
"html-tags": "^3.1.0",
|
"html-tags": "^3.1.0",
|
||||||
"svg-tags": "^1.0.0"
|
"svg-tags": "^1.0.0"
|
||||||
},
|
},
|
||||||
|
28
src/babel-sugar-fragment.js
Normal file
28
src/babel-sugar-fragment.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const syntaxJsx = require('@babel/plugin-syntax-jsx').default;
|
||||||
|
const t = require('@babel/types');
|
||||||
|
const helperModuleImports = require('@babel/helper-module-imports');
|
||||||
|
|
||||||
|
const transformFragment = (path, { name }) => {
|
||||||
|
const children = path.get('children') || [];
|
||||||
|
return t.jsxElement(
|
||||||
|
t.jsxOpeningElement(t.jsxIdentifier(name), []),
|
||||||
|
t.jsxClosingElement(t.jsxIdentifier(name)),
|
||||||
|
children.map(({ node }) => node),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = () => ({
|
||||||
|
name: 'babel-sugar-fragment',
|
||||||
|
inherits: syntaxJsx,
|
||||||
|
visitor: {
|
||||||
|
JSXFragment: {
|
||||||
|
enter(path, state) {
|
||||||
|
if (!state.vueFragment) {
|
||||||
|
state.vueFragment = helperModuleImports.addNamed(path, 'Fragment', 'vue');
|
||||||
|
}
|
||||||
|
path.replaceWith(transformFragment(path, state.vueFragment));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
@ -1,7 +1,9 @@
|
|||||||
const babelPluginTransformVueJsx = require('./babel-plugin-transform-vue-jsx');
|
const babelPluginTransformVueJsx = require('./babel-plugin-transform-vue-jsx');
|
||||||
|
const babelSugarFragment = require('./babel-sugar-fragment');
|
||||||
|
|
||||||
module.exports = () => ({
|
module.exports = () => ({
|
||||||
plugins: [
|
plugins: [
|
||||||
babelPluginTransformVueJsx,
|
babelPluginTransformVueJsx,
|
||||||
|
babelSugarFragment,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
|
||||||
|
test('should render with render function', () => {
|
||||||
|
const wrapper = shallowMount({
|
||||||
|
render() {
|
||||||
|
return <div>123</div>;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.text()).toBe('123');
|
||||||
|
});
|
||||||
|
|
||||||
test('should render with setup', () => {
|
test('should render with setup', () => {
|
||||||
const wrapper = shallowMount({
|
const wrapper = shallowMount({
|
||||||
setup() {
|
setup() {
|
||||||
@ -44,17 +53,26 @@ test('should not fallthrough with inheritAttrs: false', () => {
|
|||||||
expect(wrapper.text()).toBe('1');
|
expect(wrapper.text()).toBe('1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Fragment', () => {
|
||||||
|
const Child = () => <div>123</div>;
|
||||||
|
|
||||||
test('should render', () => {
|
Child.inheritAttrs = false;
|
||||||
const App = {
|
|
||||||
render() {
|
const wrapper = shallowMount({
|
||||||
return <div>1234</div>;
|
setup() {
|
||||||
|
return () => (
|
||||||
|
<>
|
||||||
|
<Child />
|
||||||
|
<div>456</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
const wrapper = shallowMount(App);
|
|
||||||
expect(wrapper.html()).toBe('<div>1234</div>');
|
expect(wrapper.html()).toBe('<div>123</div><div>456</div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('xlink:href', () => {
|
test('xlink:href', () => {
|
||||||
const wrapper = shallowMount({
|
const wrapper = shallowMount({
|
||||||
setup() {
|
setup() {
|
||||||
@ -119,6 +137,27 @@ test('domProps input[value]', () => {
|
|||||||
expect(wrapper.html()).toBe('<input type="text">');
|
expect(wrapper.html()).toBe('<input type="text">');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('domProps input[checked]', () => {
|
||||||
|
const val = 'foo';
|
||||||
|
const wrapper = shallowMount({
|
||||||
|
setup() {
|
||||||
|
return () => <input checked={val} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.componentVM);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('domProps option[selected]', () => {
|
||||||
|
const val = 'foo';
|
||||||
|
const wrapper = shallowMount({
|
||||||
|
render() {
|
||||||
|
return <option selected={val} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper);
|
||||||
|
});
|
||||||
|
|
||||||
test('Spread (single object expression)', () => {
|
test('Spread (single object expression)', () => {
|
||||||
const props = {
|
const props = {
|
||||||
innerHTML: 123,
|
innerHTML: 123,
|
||||||
@ -132,7 +171,7 @@ test('Spread (single object expression)', () => {
|
|||||||
expect(wrapper.html()).toBe('<div other="1">123</div>');
|
expect(wrapper.html()).toBe('<div other="1">123</div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Spread (mixed)', () => {
|
test('Spread (mixed)', async () => {
|
||||||
const calls = [];
|
const calls = [];
|
||||||
const data = {
|
const data = {
|
||||||
id: 'hehe',
|
id: 'hehe',
|
||||||
@ -143,7 +182,7 @@ test('Spread (mixed)', () => {
|
|||||||
class: ['a', 'b'],
|
class: ['a', 'b'],
|
||||||
};
|
};
|
||||||
|
|
||||||
shallowMount({
|
const wrapper = shallowMount({
|
||||||
setup() {
|
setup() {
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
@ -151,9 +190,17 @@ test('Spread (mixed)', () => {
|
|||||||
{...data}
|
{...data}
|
||||||
class={{ c: true }}
|
class={{ c: true }}
|
||||||
onClick={() => calls.push(4)}
|
onClick={() => calls.push(4)}
|
||||||
hook-insert={() => calls.push(2)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(wrapper.attributes('id')).toBe('hehe');
|
||||||
|
expect(wrapper.attributes('href')).toBe('huhu');
|
||||||
|
expect(wrapper.text()).toBe('2');
|
||||||
|
expect(wrapper.classes()).toEqual(expect.arrayContaining(['a', 'b', 'c']));
|
||||||
|
|
||||||
|
await wrapper.trigger('click');
|
||||||
|
|
||||||
|
expect(calls).toEqual(expect.arrayContaining([3, 4]));
|
||||||
});
|
});
|
||||||
|
1
test/setup.js
Normal file
1
test/setup.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'regenerator-runtime/runtime';
|
Loading…
Reference in New Issue
Block a user