vite-plugin-enter-dev 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +19 -0
- package/dist/index.js +182 -0
- package/package.json +48 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PluginOption } from 'vite';
|
|
2
|
+
|
|
3
|
+
interface Options {
|
|
4
|
+
/**
|
|
5
|
+
* 是否注入消息监听器脚本(默认:true)
|
|
6
|
+
*/
|
|
7
|
+
injectMessageListener?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* 是否注入 Google Fonts(默认:true)
|
|
10
|
+
*/
|
|
11
|
+
injectGoogleFonts?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Google Fonts 链接(可自定义)
|
|
14
|
+
*/
|
|
15
|
+
googleFontsUrl?: string;
|
|
16
|
+
}
|
|
17
|
+
declare function enterDevPlugin(options?: Options): PluginOption[];
|
|
18
|
+
|
|
19
|
+
export { enterDevPlugin as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import react from '@vitejs/plugin-react';
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
|
|
5
|
+
// src/sourceInfoInjectPlugin.ts
|
|
6
|
+
function injectSourcePlugin({ types: t }) {
|
|
7
|
+
return {
|
|
8
|
+
name: "inject-source-location-enhanced",
|
|
9
|
+
visitor: {
|
|
10
|
+
JSXElement(path, state) {
|
|
11
|
+
const { node } = path;
|
|
12
|
+
const filename = state.filename || state.file.opts.filename || "unknown";
|
|
13
|
+
const start = node.loc?.start;
|
|
14
|
+
const end = node.loc?.end;
|
|
15
|
+
if (!start) return;
|
|
16
|
+
const relativePath = filename.replace(/^.*\/src\//, "src/").replace(/\\/g, "/");
|
|
17
|
+
const sourceLocation = `${relativePath}:${start.line}:${start.column + 1}`;
|
|
18
|
+
const elementType = getElementType(node.openingElement.name);
|
|
19
|
+
const elementInfo = {
|
|
20
|
+
fileName: relativePath,
|
|
21
|
+
lineNumber: start.line,
|
|
22
|
+
columnNumber: start.column + 1,
|
|
23
|
+
endLine: end?.line || start.line,
|
|
24
|
+
endColumn: end?.column ? end.column + 1 : start.column + 1,
|
|
25
|
+
elementType,
|
|
26
|
+
tagName: elementType.toLowerCase(),
|
|
27
|
+
// 获取元素的属性信息
|
|
28
|
+
attributes: node.openingElement.attributes.map((attr) => {
|
|
29
|
+
if (attr.type === "JSXAttribute" && attr.name) {
|
|
30
|
+
return {
|
|
31
|
+
name: attr.name.name,
|
|
32
|
+
hasValue: !!attr.value,
|
|
33
|
+
line: attr.loc?.start?.line,
|
|
34
|
+
column: attr.loc?.start?.column
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}).filter(Boolean),
|
|
39
|
+
// 记录是否有子元素
|
|
40
|
+
hasChildren: node.children && node.children.length > 0,
|
|
41
|
+
// 记录父元素信息(如果可获得)
|
|
42
|
+
parentElement: getParentElementType(path.parent)
|
|
43
|
+
};
|
|
44
|
+
const sourceLocationAttr = t.jsxAttribute(
|
|
45
|
+
t.jsxIdentifier("data-source-location"),
|
|
46
|
+
t.stringLiteral(sourceLocation)
|
|
47
|
+
);
|
|
48
|
+
const sourceStackAttr = t.jsxAttribute(
|
|
49
|
+
t.jsxIdentifier("data-source-stack"),
|
|
50
|
+
t.stringLiteral(JSON.stringify(elementInfo))
|
|
51
|
+
);
|
|
52
|
+
const elementTypeAttr = t.jsxAttribute(
|
|
53
|
+
t.jsxIdentifier("data-element-type"),
|
|
54
|
+
t.stringLiteral(elementType)
|
|
55
|
+
);
|
|
56
|
+
const lineNumberAttr = t.jsxAttribute(
|
|
57
|
+
t.jsxIdentifier("data-line-number"),
|
|
58
|
+
t.stringLiteral(start.line.toString())
|
|
59
|
+
);
|
|
60
|
+
const runtimeFileAttr = t.jsxAttribute(
|
|
61
|
+
t.jsxIdentifier("data-real-file"),
|
|
62
|
+
t.stringLiteral(relativePath)
|
|
63
|
+
);
|
|
64
|
+
const runtimeLineAttr = t.jsxAttribute(
|
|
65
|
+
t.jsxIdentifier("data-real-line"),
|
|
66
|
+
t.stringLiteral(start.line.toString())
|
|
67
|
+
);
|
|
68
|
+
const runtimeColumnAttr = t.jsxAttribute(
|
|
69
|
+
t.jsxIdentifier("data-real-column"),
|
|
70
|
+
t.stringLiteral((start.column + 1).toString())
|
|
71
|
+
);
|
|
72
|
+
const injectionMethodAttr = t.jsxAttribute(
|
|
73
|
+
t.jsxIdentifier("data-injected-source"),
|
|
74
|
+
t.stringLiteral("babel")
|
|
75
|
+
);
|
|
76
|
+
node.openingElement.attributes.push(
|
|
77
|
+
sourceLocationAttr,
|
|
78
|
+
sourceStackAttr,
|
|
79
|
+
elementTypeAttr,
|
|
80
|
+
lineNumberAttr,
|
|
81
|
+
runtimeFileAttr,
|
|
82
|
+
runtimeLineAttr,
|
|
83
|
+
runtimeColumnAttr,
|
|
84
|
+
injectionMethodAttr
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function getElementType(nameNode) {
|
|
91
|
+
if (nameNode.type === "JSXIdentifier") {
|
|
92
|
+
return nameNode.name;
|
|
93
|
+
} else if (nameNode.type === "JSXMemberExpression") {
|
|
94
|
+
return `${nameNode.object.name}.${nameNode.property.name}`;
|
|
95
|
+
}
|
|
96
|
+
return "unknown";
|
|
97
|
+
}
|
|
98
|
+
function getParentElementType(parentNode) {
|
|
99
|
+
if (parentNode && parentNode.type === "JSXElement" && parentNode.openingElement) {
|
|
100
|
+
return getElementType(parentNode.openingElement.name);
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/index.ts
|
|
106
|
+
function enterDevPlugin(options = {}) {
|
|
107
|
+
const {
|
|
108
|
+
injectMessageListener = true,
|
|
109
|
+
injectGoogleFonts = true,
|
|
110
|
+
googleFontsUrl = "https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900;950&family=Poppins:wght@100;200;300;400;500;600;700;800;900;950&family=Roboto:wght@100;200;300;400;500;600;700;800;900;950&display=swap"
|
|
111
|
+
} = options;
|
|
112
|
+
const reactPlugin = react({
|
|
113
|
+
// 确保在开发模式下启用JSX源码映射
|
|
114
|
+
jsxImportSource: void 0,
|
|
115
|
+
jsxRuntime: "automatic",
|
|
116
|
+
// 启用构建时注入源码位置信息
|
|
117
|
+
babel: {
|
|
118
|
+
plugins: [
|
|
119
|
+
// 我们的自定义插件:在构建时注入源码位置
|
|
120
|
+
[injectSourcePlugin],
|
|
121
|
+
// 标准的React JSX转换
|
|
122
|
+
[
|
|
123
|
+
"@babel/plugin-transform-react-jsx",
|
|
124
|
+
{
|
|
125
|
+
runtime: "automatic",
|
|
126
|
+
importSource: "react",
|
|
127
|
+
development: true
|
|
128
|
+
// 保持开发模式以获得更好的调试体验
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
const htmlInjectPlugin = {
|
|
135
|
+
name: "enter-dev-custom-html-inject",
|
|
136
|
+
enforce: "pre",
|
|
137
|
+
transformIndexHtml(html) {
|
|
138
|
+
let transformedHtml = html;
|
|
139
|
+
if (injectMessageListener) {
|
|
140
|
+
const messageListenerScript = `
|
|
141
|
+
<script>
|
|
142
|
+
// \u6DFB\u52A0\u6D88\u606F\u76D1\u542C\u5668\uFF0C\u63A5\u6536\u6765\u81EA\u4E3B\u5DE5\u7A0B\u7684\u6CE8\u5165\u811A\u672C
|
|
143
|
+
window.addEventListener('message', (event) => {
|
|
144
|
+
if (event.data.type === 'inject-script') {
|
|
145
|
+
try {
|
|
146
|
+
console.log('Executing injector script in sandbox...');
|
|
147
|
+
|
|
148
|
+
// \u521B\u5EFAscript\u5143\u7D20\u5E76\u6267\u884C
|
|
149
|
+
const script = document.createElement('script');
|
|
150
|
+
script.textContent = event.data.script;
|
|
151
|
+
document.head.appendChild(script);
|
|
152
|
+
console.log('Injector script executed successfully');
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error('Failed to execute injector script:', error);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
</script>`;
|
|
160
|
+
if (html.includes("</head>")) {
|
|
161
|
+
transformedHtml = transformedHtml.replace("</head>", `${messageListenerScript}
|
|
162
|
+
</head>`);
|
|
163
|
+
} else if (html.includes("</title>")) {
|
|
164
|
+
transformedHtml = transformedHtml.replace("</title>", `</title>${messageListenerScript}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (injectGoogleFonts) {
|
|
168
|
+
const googleFontsLink = `<link href="${googleFontsUrl}" rel="stylesheet">`;
|
|
169
|
+
if (!transformedHtml.includes(googleFontsUrl)) {
|
|
170
|
+
if (transformedHtml.includes("</head>")) {
|
|
171
|
+
transformedHtml = transformedHtml.replace("</head>", ` ${googleFontsLink}
|
|
172
|
+
</head>`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return transformedHtml;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
return [...reactPlugin, htmlInjectPlugin];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export { enterDevPlugin as default };
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vite-plugin-enter-dev",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"private": false,
|
|
6
|
+
"description": "A Vite plugin for development enhancements",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"dev": "tsup --watch",
|
|
22
|
+
"lint": "eslint . --max-warnings 0"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"vite",
|
|
26
|
+
"vite-plugin",
|
|
27
|
+
"development",
|
|
28
|
+
"enter",
|
|
29
|
+
"enter.pro"
|
|
30
|
+
],
|
|
31
|
+
"author": "",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"packageManager": "pnpm@10.15.0",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^20.19.9",
|
|
36
|
+
"@workspace/eslint-config": "workspace:*",
|
|
37
|
+
"@workspace/typescript-config": "workspace:*",
|
|
38
|
+
"tsup": "^8.5.1",
|
|
39
|
+
"typescript": "^5.9.2",
|
|
40
|
+
"vite": "^6.0.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"vite": "^5.0.0 || ^6.0.0"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@vitejs/plugin-react": "^5.1.1"
|
|
47
|
+
}
|
|
48
|
+
}
|