diff --git a/.eslintrc.js b/.eslintrc.js index c2e3591..c5e7efa 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -22,6 +22,7 @@ module.exports = { 'no-nested-ternary': [0], 'no-param-reassign': [0], 'no-use-before-define': [0], + 'no-restricted-syntax': [0], 'no-plusplus': [0], 'import/no-extraneous-dependencies': [0], 'consistent-return': [0], diff --git a/packages/babel-plugin-jsx/README-zh_CN.md b/packages/babel-plugin-jsx/README-zh_CN.md index 56a0bba..3039d4f 100644 --- a/packages/babel-plugin-jsx/README-zh_CN.md +++ b/packages/babel-plugin-jsx/README-zh_CN.md @@ -62,6 +62,14 @@ Default: `true` 使用 `enableObjectSlots` (文档下面会提到)。虽然在 JSX 中比较好使,但是会增加一些 `_isSlot` 的运行时条件判断,这会增加你的项目体积。即使你关闭了 `enableObjectSlots`,`v-slots` 还是可以使用 +#### pragma + +Type: `string` + +Default: `createVNode` + +替换编译JSX表达式的时候使用的函数 + ## 表达式 ### 内容 diff --git a/packages/babel-plugin-jsx/README.md b/packages/babel-plugin-jsx/README.md index aef7dc5..6d52307 100644 --- a/packages/babel-plugin-jsx/README.md +++ b/packages/babel-plugin-jsx/README.md @@ -66,6 +66,14 @@ Default: `true` 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. +#### pragma + +Type: `string` + +Default: `createVNode` + +Replace the function used when compiling JSX expressions. + ## Syntax ### Content diff --git a/packages/babel-plugin-jsx/src/index.ts b/packages/babel-plugin-jsx/src/index.ts index db707b9..2e3822f 100644 --- a/packages/babel-plugin-jsx/src/index.ts +++ b/packages/babel-plugin-jsx/src/index.ts @@ -11,6 +11,7 @@ export type State = { get: (name: string) => any; set: (name: string, value: any) => any; opts: VueJSXPluginOptions; + file: BabelCore.BabelFile } export interface VueJSXPluginOptions { @@ -24,6 +25,8 @@ export interface VueJSXPluginOptions { isCustomElement?: (tag: string) => boolean; /** enable object slots syntax */ enableObjectSlots?: boolean; + /** Replace the function used when compiling JSX expressions */ + pragma?: string; } export type ExcludesBoolean = (x: T | false | true) => x is T; @@ -44,6 +47,8 @@ const hasJSX = (parentPath: NodePath) => { return fileHasJSX; }; +const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/; + export default ({ types }: typeof BabelCore) => ({ name: 'babel-plugin-jsx', inherits: syntaxJsx, @@ -129,6 +134,21 @@ export default ({ types }: typeof BabelCore) => ({ }); }); } + + const { opts: { pragma = '' }, file } = state; + + if (pragma) { + state.set('createVNode', () => t.identifier(pragma)); + } + + if (file.ast.comments) { + for (const comment of file.ast.comments) { + const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value); + if (jsxMatches) { + state.set('createVNode', () => t.identifier(jsxMatches[1])); + } + } + } } }, exit(path: NodePath) { diff --git a/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap b/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap index e4303fb..9782784 100644 --- a/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap +++ b/packages/babel-plugin-jsx/test/__snapshots__/snapshot.test.ts.snap @@ -210,6 +210,11 @@ _withDirectives(_createVNode(\\"select\\", { }, [_createTextVNode(\\"c\\")])], 8, [\\"onUpdate:modelValue\\"]), [[_vModelSelect, test]]);" `; +exports[`set pragma to custom: custom 1`] = ` +"import { createTextVNode as _createTextVNode } from \\"vue\\"; +custom(\\"div\\", null, [_createTextVNode(\\"pragma\\")]);" +`; + exports[`should keep \`import * as Vue from "vue"\`: should keep \`import * as Vue from "vue"\` 1`] = ` "import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\"; import * as Vue from 'vue'; @@ -239,6 +244,15 @@ _withDirectives(_createVNode(\\"textarea\\", { }, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);" `; +exports[`use "@jsx" comment specify pragma: use "@jsx" comment specify pragma 1`] = ` +"import { createTextVNode as _createTextVNode } from \\"vue\\"; + +/* @jsx custom */ +custom(\\"div\\", { + \\"id\\": \\"custom\\" +}, [_createTextVNode(\\"Hello\\")]);" +`; + exports[`use "model" as the prop name: use "model" as the prop name 1`] = ` "import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\"; diff --git a/packages/babel-plugin-jsx/test/snapshot.test.ts b/packages/babel-plugin-jsx/test/snapshot.test.ts index d4c7ccc..19d1a7c 100644 --- a/packages/babel-plugin-jsx/test/snapshot.test.ts +++ b/packages/babel-plugin-jsx/test/snapshot.test.ts @@ -163,6 +163,13 @@ const tests: Test[] = [ 123 `, }, + { + name: 'use "@jsx" comment specify pragma', + from: ` + /* @jsx custom */ +
Hello
+ `, + }, ]; tests.forEach(( @@ -244,3 +251,22 @@ objectSlotsTests.forEach(({ }, ); }); + +const pragmaTests = [ + { + name: 'custom', + from: '
pragma
', + }, +]; + +pragmaTests.forEach(({ + name, from, +}) => { + test( + `set pragma to ${name}`, + async () => { + expect(await transpile(from, { pragma: 'custom' })) + .toMatchSnapshot(name); + }, + ); +});