Skip to content

Commit 1698603

Browse files
authored
feat: should merge generated imports (#274)
1 parent 0358677 commit 1698603

File tree

3 files changed

+52
-60
lines changed

3 files changed

+52
-60
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ module.exports = {
3232
'@typescript-eslint/explicit-module-boundary-types': [0],
3333
'@typescript-eslint/no-explicit-any': [0],
3434
'@typescript-eslint/no-non-null-assertion': [0],
35+
'max-len': [0],
3536
},
3637
settings: {
3738
'import/resolver': {

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export interface VueJSXPluginOptions {
2828

2929
export type ExcludesBoolean = <T>(x: T | false | true) => x is T;
3030

31-
const hasJSX = (parentPath: NodePath) => {
31+
const hasJSX = (parentPath: NodePath<t.Program>) => {
3232
let fileHasJSX = false;
3333
parentPath.traverse({
3434
JSXElement(path) { // skip ts error
@@ -51,7 +51,7 @@ export default ({ types }: typeof BabelCore) => ({
5151
...tranformVueJSX,
5252
...sugarFragment,
5353
Program: {
54-
enter(path: NodePath, state: State) {
54+
enter(path: NodePath<t.Program>, state: State) {
5555
if (hasJSX(path)) {
5656
const importNames = [
5757
'createVNode',
@@ -131,6 +131,33 @@ export default ({ types }: typeof BabelCore) => ({
131131
}
132132
}
133133
},
134+
exit(path: NodePath<t.Program>) {
135+
const body = path.get('body') as NodePath[];
136+
const specifiersMap = new Map<string, t.ImportSpecifier>();
137+
138+
body.filter((nodePath) => t.isImportDeclaration(nodePath.node)
139+
&& nodePath.node.source.value === 'vue')
140+
.forEach((nodePath) => {
141+
const { specifiers } = nodePath.node as t.ImportDeclaration;
142+
let shouldRemove = false;
143+
specifiers.forEach((specifier) => {
144+
if (!specifier.loc && t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) {
145+
specifiersMap.set(specifier.imported.name, specifier);
146+
shouldRemove = true;
147+
}
148+
});
149+
if (shouldRemove) {
150+
nodePath.remove();
151+
}
152+
});
153+
154+
const specifiers = [...specifiersMap.keys()].map(
155+
(imported) => specifiersMap.get(imported)!,
156+
);
157+
if (specifiers.length) {
158+
path.unshiftContainer('body', t.importDeclaration(specifiers, t.stringLiteral('vue')));
159+
}
160+
},
134161
},
135162
},
136163
});

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

Lines changed: 22 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`MereProps Order: MereProps Order 1`] = `
4-
"import { createVNode as _createVNode } from \\"vue\\";
5-
import { mergeProps as _mergeProps } from \\"vue\\";
6-
import { createTextVNode as _createTextVNode } from \\"vue\\";
4+
"import { createVNode as _createVNode, mergeProps as _mergeProps, createTextVNode as _createTextVNode } from \\"vue\\";
75
86
_createVNode(\\"button\\", _mergeProps({
97
\\"loading\\": true
@@ -27,24 +25,19 @@ createVNode('div', null, ['Without JSX should work']);"
2725
`;
2826

2927
exports[`Without props: Without props 1`] = `
30-
"import { createVNode as _createVNode } from \\"vue\\";
31-
import { createTextVNode as _createTextVNode } from \\"vue\\";
28+
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
3229
3330
_createVNode(\\"a\\", null, [_createTextVNode(\\"a\\")]);"
3431
`;
3532

3633
exports[`custom directive: custom directive 1`] = `
37-
"import { withDirectives as _withDirectives } from \\"vue\\";
38-
import { createVNode as _createVNode } from \\"vue\\";
39-
import { resolveDirective as _resolveDirective } from \\"vue\\";
40-
import { resolveComponent as _resolveComponent } from \\"vue\\";
34+
"import { withDirectives as _withDirectives, createVNode as _createVNode, resolveDirective as _resolveDirective, resolveComponent as _resolveComponent } from \\"vue\\";
4135
4236
_withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"cus\\"), x]]);"
4337
`;
4438

4539
exports[`disable object slot syntax with defaultSlot: defaultSlot 1`] = `
46-
"import { createVNode as _createVNode } from \\"vue\\";
47-
import { resolveComponent as _resolveComponent } from \\"vue\\";
40+
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
4841
4942
_createVNode(_resolveComponent(\\"Badge\\"), null, {
5043
default: () => [slots.default()],
@@ -53,9 +46,7 @@ _createVNode(_resolveComponent(\\"Badge\\"), null, {
5346
`;
5447

5548
exports[`dynamic type in input: dynamic type in input 1`] = `
56-
"import { withDirectives as _withDirectives } from \\"vue\\";
57-
import { createVNode as _createVNode } from \\"vue\\";
58-
import { vModelDynamic as _vModelDynamic } from \\"vue\\";
49+
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelDynamic as _vModelDynamic } from \\"vue\\";
5950
6051
_withDirectives(_createVNode(\\"input\\", {
6152
\\"type\\": type,
@@ -64,9 +55,7 @@ _withDirectives(_createVNode(\\"input\\", {
6455
`;
6556

6657
exports[`input[type="checkbox"]: input[type="checkbox"] 1`] = `
67-
"import { withDirectives as _withDirectives } from \\"vue\\";
68-
import { createVNode as _createVNode } from \\"vue\\";
69-
import { vModelCheckbox as _vModelCheckbox } from \\"vue\\";
58+
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelCheckbox as _vModelCheckbox } from \\"vue\\";
7059
7160
_withDirectives(_createVNode(\\"input\\", {
7261
\\"type\\": \\"checkbox\\",
@@ -75,10 +64,7 @@ _withDirectives(_createVNode(\\"input\\", {
7564
`;
7665

7766
exports[`input[type="radio"]: input[type="radio"] 1`] = `
78-
"import { withDirectives as _withDirectives } from \\"vue\\";
79-
import { createVNode as _createVNode } from \\"vue\\";
80-
import { vModelRadio as _vModelRadio } from \\"vue\\";
81-
import { Fragment as _Fragment } from \\"vue\\";
67+
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelRadio as _vModelRadio, Fragment as _Fragment } from \\"vue\\";
8268
8369
_createVNode(_Fragment, null, [_withDirectives(_createVNode(\\"input\\", {
8470
\\"type\\": \\"radio\\",
@@ -94,9 +80,7 @@ _createVNode(_Fragment, null, [_withDirectives(_createVNode(\\"input\\", {
9480
`;
9581

9682
exports[`input[type="text"] .lazy modifier: input[type="text"] .lazy modifier 1`] = `
97-
"import { withDirectives as _withDirectives } from \\"vue\\";
98-
import { createVNode as _createVNode } from \\"vue\\";
99-
import { vModelText as _vModelText } from \\"vue\\";
83+
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";
10084
10185
_withDirectives(_createVNode(\\"input\\", {
10286
\\"onUpdate:modelValue\\": $event => test = $event
@@ -106,18 +90,15 @@ _withDirectives(_createVNode(\\"input\\", {
10690
`;
10791

10892
exports[`input[type="text"]: input[type="text"] 1`] = `
109-
"import { withDirectives as _withDirectives } from \\"vue\\";
110-
import { createVNode as _createVNode } from \\"vue\\";
111-
import { vModelText as _vModelText } from \\"vue\\";
93+
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";
11294
11395
_withDirectives(_createVNode(\\"input\\", {
11496
\\"onUpdate:modelValue\\": $event => test = $event
11597
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);"
11698
`;
11799

118100
exports[`override props multiple: multiple 1`] = `
119-
"import { createVNode as _createVNode } from \\"vue\\";
120-
import { resolveComponent as _resolveComponent } from \\"vue\\";
101+
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
121102
122103
_createVNode(_resolveComponent(\\"A\\"), {
123104
\\"loading\\": true,
@@ -138,8 +119,7 @@ _createVNode(\\"div\\", a, null);"
138119
`;
139120

140121
exports[`passing object slots via JSX children multiple expressions: multiple expressions 1`] = `
141-
"import { createVNode as _createVNode } from \\"vue\\";
142-
import { resolveComponent as _resolveComponent } from \\"vue\\";
122+
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
143123
144124
_createVNode(_resolveComponent(\\"A\\"), null, {
145125
default: () => [foo, bar],
@@ -148,20 +128,17 @@ _createVNode(_resolveComponent(\\"A\\"), null, {
148128
`;
149129

150130
exports[`passing object slots via JSX children single expression, function expression: single expression, function expression 1`] = `
151-
"import { createVNode as _createVNode } from \\"vue\\";
152-
import { resolveComponent as _resolveComponent } from \\"vue\\";
131+
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
153132
154133
_createVNode(_resolveComponent(\\"A\\"), null, {
155134
default: () => \\"foo\\"
156135
});"
157136
`;
158137

159138
exports[`passing object slots via JSX children single expression, non-literal value: runtime check: single expression, non-literal value: runtime check 1`] = `
160-
"import { createVNode as _createVNode } from \\"vue\\";
161-
import { isVNode as _isVNode } from \\"vue\\";
162-
import { resolveComponent as _resolveComponent } from \\"vue\\";
139+
"let _slot;
163140
164-
let _slot;
141+
import { createVNode as _createVNode, isVNode as _isVNode, resolveComponent as _resolveComponent } from \\"vue\\";
165142
166143
function _isSlot(s) {
167144
return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !_isVNode(s);
@@ -176,8 +153,7 @@ _createVNode(_resolveComponent(\\"A\\"), null, _isSlot(_slot = foo()) ? _slot :
176153
`;
177154

178155
exports[`reassign variable as component: reassign variable as component 1`] = `
179-
"import { isVNode as _isVNode } from \\"vue\\";
180-
import { createVNode as _createVNode } from \\"vue\\";
156+
"import { isVNode as _isVNode, createVNode as _createVNode } from \\"vue\\";
181157
import { defineComponent } from 'vue';
182158
183159
function _isSlot(s) {
@@ -207,10 +183,7 @@ a = _createVNode(A, null, _isSlot(a) ? a : {
207183
`;
208184

209185
exports[`select: select 1`] = `
210-
"import { withDirectives as _withDirectives } from \\"vue\\";
211-
import { vModelSelect as _vModelSelect } from \\"vue\\";
212-
import { createVNode as _createVNode } from \\"vue\\";
213-
import { createTextVNode as _createTextVNode } from \\"vue\\";
186+
"import { withDirectives as _withDirectives, vModelSelect as _vModelSelect, createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
214187
215188
_withDirectives(_createVNode(\\"select\\", {
216189
\\"onUpdate:modelValue\\": $event => test = $event
@@ -224,16 +197,14 @@ _withDirectives(_createVNode(\\"select\\", {
224197
`;
225198

226199
exports[`should keep \`import * as Vue from "vue"\`: should keep \`import * as Vue from "vue"\` 1`] = `
227-
"import { createVNode as _createVNode } from \\"vue\\";
228-
import { createTextVNode as _createTextVNode } from \\"vue\\";
200+
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
229201
import * as Vue from 'vue';
230202
231203
_createVNode(\\"div\\", null, [_createTextVNode(\\"Vue\\")]);"
232204
`;
233205

234206
exports[`single no need for a mergeProps call: single no need for a mergeProps call 1`] = `
235-
"import { createVNode as _createVNode } from \\"vue\\";
236-
import { createTextVNode as _createTextVNode } from \\"vue\\";
207+
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
237208
238209
_createVNode(\\"div\\", x, [_createTextVNode(\\"single\\")], 16);"
239210
`;
@@ -247,18 +218,15 @@ _createVNode(_Fragment, null, null);"
247218
`;
248219

249220
exports[`textarea: textarea 1`] = `
250-
"import { withDirectives as _withDirectives } from \\"vue\\";
251-
import { createVNode as _createVNode } from \\"vue\\";
252-
import { vModelText as _vModelText } from \\"vue\\";
221+
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";
253222
254223
_withDirectives(_createVNode(\\"textarea\\", {
255224
\\"onUpdate:modelValue\\": $event => test = $event
256225
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);"
257226
`;
258227

259228
exports[`use "model" as the prop name: use "model" as the prop name 1`] = `
260-
"import { createVNode as _createVNode } from \\"vue\\";
261-
import { resolveComponent as _resolveComponent } from \\"vue\\";
229+
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
262230
263231
_createVNode(_resolveComponent(\\"C\\"), {
264232
\\"model\\": foo,
@@ -267,10 +235,7 @@ _createVNode(_resolveComponent(\\"C\\"), {
267235
`;
268236

269237
exports[`v-show: v-show 1`] = `
270-
"import { withDirectives as _withDirectives } from \\"vue\\";
271-
import { createVNode as _createVNode } from \\"vue\\";
272-
import { vShow as _vShow } from \\"vue\\";
273-
import { createTextVNode as _createTextVNode } from \\"vue\\";
238+
"import { withDirectives as _withDirectives, createVNode as _createVNode, vShow as _vShow, createTextVNode as _createTextVNode } from \\"vue\\";
274239
275240
_withDirectives(_createVNode(\\"div\\", null, [_createTextVNode(\\"vShow\\")], 512), [[_vShow, x]]);"
276241
`;
@@ -284,8 +249,7 @@ _createVNode(\\"h1\\", {
284249
`;
285250

286251
exports[`vModels: vModels 1`] = `
287-
"import { createVNode as _createVNode } from \\"vue\\";
288-
import { resolveComponent as _resolveComponent } from \\"vue\\";
252+
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
289253
290254
_createVNode(_resolveComponent(\\"C\\"), {
291255
\\"modelValue\\": foo,

0 commit comments

Comments
 (0)