-
Notifications
You must be signed in to change notification settings - Fork 27
/
vite-plugin-react-displayname.ts
101 lines (95 loc) · 2.78 KB
/
vite-plugin-react-displayname.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import type { Plugin } from 'vite';
import * as babel from '@babel/core';
import { declare } from '@babel/helper-plugin-utils';
// Babel plugin to add display names
const babelDisplayNamePlugin = declare((api) => {
api.assertVersion(7);
const addDisplayName = (path, componentName) => {
path.insertAfter(
api.types.expressionStatement(
api.types.assignmentExpression(
'=',
api.types.memberExpression(
api.types.identifier(componentName),
api.types.identifier('displayName'),
),
api.types.stringLiteral(componentName),
),
),
);
};
return {
name: 'transform-react-display-name',
visitor: {
FunctionDeclaration(path) {
const componentName = path.node.id?.name;
if (componentName && /^[A-Z]/.test(componentName)) {
addDisplayName(path, componentName);
}
},
VariableDeclarator(path) {
const componentName =
path.node.id.type === 'Identifier' && path.node.id.name;
if (
componentName &&
/^[A-Z]/.test(componentName) &&
path.node.init &&
(path.node.init.type === 'ArrowFunctionExpression' ||
path.node.init.type === 'FunctionExpression')
) {
addDisplayName(path.parentPath, componentName);
}
},
ClassDeclaration(path) {
const componentName = path.node.id?.name;
if (
componentName &&
/^[A-Z]/.test(componentName) &&
path.node.superClass
) {
const displayNameProperty = api.types.classProperty(
api.types.identifier('displayName'),
api.types.stringLiteral(componentName),
null,
null,
false,
true,
);
path.get('body').unshiftContainer('body', displayNameProperty);
}
},
},
};
});
export default function reactDisplayNamePlugin(): Plugin {
return {
name: 'vite-plugin-react-displayname',
async transform(code: string, id: string) {
// Check if file should be processed
if (!id.endsWith('.tsx') || id.includes('node_modules')) {
return null;
}
try {
const result = await babel.transformAsync(code, {
filename: id,
plugins: [
['@babel/plugin-syntax-typescript', { isTSX: true }],
'@babel/plugin-syntax-jsx',
babelDisplayNamePlugin,
],
ast: true,
sourceMaps: true,
configFile: false,
babelrc: false,
});
return {
code: result?.code || code,
map: result?.map,
};
} catch (error) {
console.error('Error transforming component:', error);
return null;
}
},
};
}