Skip to content

Commit ec50fdd

Browse files
authored
feat: add pragma option and support @jsx annotation (#322)
* add pragma option and support @jsx annotation * update syntax and remove useless eslint rule * use BabelCore.BabelFile as type definition of state.file * update chinese doc
1 parent 57f6707 commit ec50fdd

6 files changed

Lines changed: 77 additions & 0 deletions

File tree

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ module.exports = {
2222
'no-nested-ternary': [0],
2323
'no-param-reassign': [0],
2424
'no-use-before-define': [0],
25+
'no-restricted-syntax': [0],
2526
'no-plusplus': [0],
2627
'import/no-extraneous-dependencies': [0],
2728
'consistent-return': [0],

packages/babel-plugin-jsx/README-zh_CN.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ Default: `true`
6262

6363
使用 `enableObjectSlots` (文档下面会提到)。虽然在 JSX 中比较好使,但是会增加一些 `_isSlot` 的运行时条件判断,这会增加你的项目体积。即使你关闭了 `enableObjectSlots``v-slots` 还是可以使用
6464

65+
#### pragma
66+
67+
Type: `string`
68+
69+
Default: `createVNode`
70+
71+
替换编译JSX表达式的时候使用的函数
72+
6573
## 表达式
6674

6775
### 内容

packages/babel-plugin-jsx/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ Default: `true`
6666

6767
Whether to enable `object slots` (mentioned below the document) syntax". It might be useful in JSX, but it will add a lot of `_isSlot` condition expressions which increase your bundle size. And `v-slots` is still available even if `enableObjectSlots` is turned off.
6868

69+
#### pragma
70+
71+
Type: `string`
72+
73+
Default: `createVNode`
74+
75+
Replace the function used when compiling JSX expressions.
76+
6977
## Syntax
7078

7179
### Content

packages/babel-plugin-jsx/src/index.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type State = {
1111
get: (name: string) => any;
1212
set: (name: string, value: any) => any;
1313
opts: VueJSXPluginOptions;
14+
file: BabelCore.BabelFile
1415
}
1516

1617
export interface VueJSXPluginOptions {
@@ -24,6 +25,8 @@ export interface VueJSXPluginOptions {
2425
isCustomElement?: (tag: string) => boolean;
2526
/** enable object slots syntax */
2627
enableObjectSlots?: boolean;
28+
/** Replace the function used when compiling JSX expressions */
29+
pragma?: string;
2730
}
2831

2932
export type ExcludesBoolean = <T>(x: T | false | true) => x is T;
@@ -44,6 +47,8 @@ const hasJSX = (parentPath: NodePath<t.Program>) => {
4447
return fileHasJSX;
4548
};
4649

50+
const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/;
51+
4752
export default ({ types }: typeof BabelCore) => ({
4853
name: 'babel-plugin-jsx',
4954
inherits: syntaxJsx,
@@ -129,6 +134,21 @@ export default ({ types }: typeof BabelCore) => ({
129134
});
130135
});
131136
}
137+
138+
const { opts: { pragma = '' }, file } = state;
139+
140+
if (pragma) {
141+
state.set('createVNode', () => t.identifier(pragma));
142+
}
143+
144+
if (file.ast.comments) {
145+
for (const comment of file.ast.comments) {
146+
const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value);
147+
if (jsxMatches) {
148+
state.set('createVNode', () => t.identifier(jsxMatches[1]));
149+
}
150+
}
151+
}
132152
}
133153
},
134154
exit(path: NodePath<t.Program>) {

packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@ _withDirectives(_createVNode(\\"select\\", {
210210
}, [_createTextVNode(\\"c\\")])], 8, [\\"onUpdate:modelValue\\"]), [[_vModelSelect, test]]);"
211211
`;
212212

213+
exports[`set pragma to custom: custom 1`] = `
214+
"import { createTextVNode as _createTextVNode } from \\"vue\\";
215+
custom(\\"div\\", null, [_createTextVNode(\\"pragma\\")]);"
216+
`;
217+
213218
exports[`should keep \`import * as Vue from "vue"\`: should keep \`import * as Vue from "vue"\` 1`] = `
214219
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
215220
import * as Vue from 'vue';
@@ -239,6 +244,15 @@ _withDirectives(_createVNode(\\"textarea\\", {
239244
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);"
240245
`;
241246

247+
exports[`use "@jsx" comment specify pragma: use "@jsx" comment specify pragma 1`] = `
248+
"import { createTextVNode as _createTextVNode } from \\"vue\\";
249+
250+
/* @jsx custom */
251+
custom(\\"div\\", {
252+
\\"id\\": \\"custom\\"
253+
}, [_createTextVNode(\\"Hello\\")]);"
254+
`;
255+
242256
exports[`use "model" as the prop name: use "model" as the prop name 1`] = `
243257
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
244258

packages/babel-plugin-jsx/test/snapshot.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,13 @@ const tests: Test[] = [
163163
<Vue.KeepAlive>123</Vue.KeepAlive>
164164
`,
165165
},
166+
{
167+
name: 'use "@jsx" comment specify pragma',
168+
from: `
169+
/* @jsx custom */
170+
<div id="custom">Hello</div>
171+
`,
172+
},
166173
];
167174

168175
tests.forEach((
@@ -244,3 +251,22 @@ objectSlotsTests.forEach(({
244251
},
245252
);
246253
});
254+
255+
const pragmaTests = [
256+
{
257+
name: 'custom',
258+
from: '<div>pragma</div>',
259+
},
260+
];
261+
262+
pragmaTests.forEach(({
263+
name, from,
264+
}) => {
265+
test(
266+
`set pragma to ${name}`,
267+
async () => {
268+
expect(await transpile(from, { pragma: 'custom' }))
269+
.toMatchSnapshot(name);
270+
},
271+
);
272+
});

0 commit comments

Comments
 (0)