Skip to content

Commit 34dfa21

Browse files
antfuwebfansplz
andauthored
feat!: hide data-v-inspector in html (#81)
* feat: hide `data-v-inspector` in html * fix: unplugin * fix: only enable `cleanHtml` for Vue 3 * chore: fix typo --------- Co-authored-by: webfansplz <308241863@qq.com>
1 parent ddcfe1d commit 34dfa21

File tree

12 files changed

+2785
-2359
lines changed

12 files changed

+2785
-2359
lines changed

package.json

+13-11
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,19 @@
2020
"release": "pnpm build && changeset && changeset version && changeset publish"
2121
},
2222
"devDependencies": {
23-
"@antfu/eslint-config": "^0.36.0",
24-
"@changesets/cli": "^2.26.0",
25-
"@types/node": "^20.4.4",
26-
"eslint": "^8.36.0",
27-
"esmo": "^0.16.3",
28-
"fs-extra": "^11.1.0",
29-
"tsup": "^6.6.3",
30-
"tsx": "^3.12.5",
31-
"typescript": "^5.0.2",
32-
"vite": "^4.2.0",
33-
"vue": "^3.2.47"
23+
"@antfu/eslint-config": "^0.43.1",
24+
"@changesets/cli": "^2.26.2",
25+
"@types/node": "^20.8.0",
26+
"eslint": "^8.50.0",
27+
"esmo": "^0.17.0",
28+
"fs-extra": "^11.1.1",
29+
"nodemon": "^3.0.1",
30+
"tsup": "^7.2.0",
31+
"tsx": "^3.13.0",
32+
"typescript": "^5.2.2",
33+
"vite": "^4.4.9",
34+
"vite-plugin-inspect": "^0.7.40",
35+
"vue": "^3.3.4"
3436
},
3537
"pnpm": {
3638
"packageExtensions": {

packages/core/package.json

+8-8
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,18 @@
4545
"vite": "^3.0.0-0 || ^4.0.0-0"
4646
},
4747
"dependencies": {
48-
"@babel/core": "^7.22.17",
49-
"@babel/plugin-proposal-decorators": "^7.22.15",
48+
"@babel/core": "^7.23.0",
49+
"@babel/plugin-proposal-decorators": "^7.23.0",
5050
"@babel/plugin-syntax-import-attributes": "^7.22.5",
5151
"@babel/plugin-syntax-import-meta": "^7.10.4",
5252
"@babel/plugin-transform-typescript": "^7.22.15",
53-
"@vue/babel-plugin-jsx": "^1.1.1",
54-
"@vue/compiler-dom": "^3.2.47",
55-
"kolorist": "^1.7.0",
56-
"magic-string": "^0.30.0"
53+
"@vue/babel-plugin-jsx": "^1.1.5",
54+
"@vue/compiler-dom": "^3.3.4",
55+
"kolorist": "^1.8.0",
56+
"magic-string": "^0.30.4"
5757
},
5858
"devDependencies": {
59-
"@types/babel__core": "^7.20.0",
60-
"unplugin": "^1.3.1"
59+
"@types/babel__core": "^7.20.2",
60+
"unplugin": "^1.5.0"
6161
}
6262
}

packages/core/src/Overlay.vue

+11-6
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@ const isClient = typeof window !== 'undefined'
44
const importMetaUrl = isClient ? new URL(import.meta.url) : {}
55
const protocol = inspectorOptions.serverOptions?.https ? 'https:' : importMetaUrl?.protocol
66
const hostOpts = inspectorOptions.serverOptions?.host
7-
const host = hostOpts && hostOpts !== true ? hostOpts : importMetaUrl?.hostname
8-
const port = hostOpts && hostOpts !== true ? inspectorOptions.serverOptions?.port : importMetaUrl?.port
9-
const baseUrl = isClient ? inspectorOptions.openInEditorHost || `${protocol}//${host}:${port}` : ''
7+
const host = (hostOpts && hostOpts !== true) ? hostOpts : importMetaUrl?.hostname
8+
const port = (hostOpts && hostOpts !== true) ? inspectorOptions.serverOptions?.port : importMetaUrl?.port
9+
const baseUrl = isClient ? (inspectorOptions.openInEditorHost || `${protocol}//${host}:${port}`) : ''
1010
1111
const KEY_DATA = 'data-v-inspector'
1212
const KEY_IGNORE = 'data-v-inspector-ignore'
13+
const KEY_PROPS_DATA = '__v_inspector'
14+
15+
function getData(el) {
16+
return el?.__vnode?.props?.[KEY_PROPS_DATA] ?? el?.getAttribute?.(KEY_DATA)
17+
}
1318
1419
export default {
1520
name: 'VueInspectorOverlay',
@@ -94,7 +99,7 @@ export default {
9499
methods: {
95100
toggleEventListener() {
96101
const listener = this.enabled ? document.body.addEventListener : document.body.removeEventListener
97-
102+
98103
listener?.call(document.body, 'mousemove', this.updateLinkParams)
99104
listener?.call(document.body, 'resize', this.closeOverlay, true)
100105
listener?.call(document.body, 'click', this.handleClick, true)
@@ -138,14 +143,14 @@ export default {
138143
}
139144
}
140145
const ignoreIndex = path.findIndex(node => node?.hasAttribute?.(KEY_IGNORE))
141-
const targetNode = path.slice(ignoreIndex + 1).find(node => node?.hasAttribute?.(KEY_DATA))
146+
const targetNode = path.slice(ignoreIndex + 1).find(node => getData(node))
142147
if (!targetNode) {
143148
return {
144149
targetNode: null,
145150
params: null,
146151
}
147152
}
148-
const match = targetNode.getAttribute(KEY_DATA)?.match(splitRE)
153+
const match = getData(targetNode)?.match(splitRE)
149154
const [_, file, line, column] = match || []
150155
return {
151156
targetNode,

packages/core/src/index.ts

+129-71
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import fs from 'node:fs'
44
import { bold, dim, green, yellow } from 'kolorist'
55
import { normalizePath } from 'vite'
66
import type { PluginOption, ServerOptions } from 'vite'
7+
import MagicString from 'magic-string'
78
import { compileSFCTemplate } from './compiler'
89
import { idToFile, parseVueRequest } from './utils'
910

@@ -88,6 +89,15 @@ export interface VitePluginInspectorOptions {
8889
* @default false
8990
*/
9091
disableInspectorOnEditorOpen?: boolean
92+
93+
/**
94+
* Hide information in VNode and produce clean html in DevTools
95+
*
96+
* Currently, it only works for Vue 3
97+
*
98+
* @default true
99+
*/
100+
cleanHtml?: boolean
91101
}
92102

93103
const toggleComboKeysMap = {
@@ -125,88 +135,136 @@ function VitePluginInspector(options: VitePluginInspectorOptions = DEFAULT_INSPE
125135
let serverOptions: ServerOptions | undefined
126136

127137
const {
138+
vue,
128139
appendTo,
140+
cleanHtml = vue === 3, // Only enabled for Vue 3 by default
129141
} = normalizedOptions
130142

131-
return {
132-
name: 'vite-plugin-vue-inspector',
133-
enforce: 'pre',
134-
apply(_, { command }) {
135-
// apply only on serve and not for test
136-
return command === 'serve' && process.env.NODE_ENV !== 'test'
137-
},
138-
async resolveId(importee: string) {
139-
if (importee.startsWith('virtual:vue-inspector-options')) {
140-
return importee
141-
}
142-
else if (importee.startsWith('virtual:vue-inspector-path:')) {
143-
const resolved = importee.replace('virtual:vue-inspector-path:', `${inspectorPath}/`)
144-
return resolved
145-
}
146-
},
143+
return [
144+
{
145+
name: 'vite-plugin-vue-inspector',
146+
enforce: 'pre',
147+
apply(_, { command }) {
148+
// apply only on serve and not for test
149+
return command === 'serve' && process.env.NODE_ENV !== 'test'
150+
},
151+
async resolveId(importee: string) {
152+
if (importee.startsWith('virtual:vue-inspector-options')) {
153+
return importee
154+
}
155+
else if (importee.startsWith('virtual:vue-inspector-path:')) {
156+
const resolved = importee.replace('virtual:vue-inspector-path:', `${inspectorPath}/`)
157+
return resolved
158+
}
159+
},
147160

148-
async load(id) {
149-
if (id === 'virtual:vue-inspector-options') {
150-
return `export default ${JSON.stringify({ ...normalizedOptions, serverOptions })}`
151-
}
152-
else if (id.startsWith(inspectorPath)) {
153-
const { query } = parseVueRequest(id)
154-
if (query.type)
155-
return
156-
// read file ourselves to avoid getting shut out by vites fs.allow check
157-
const file = idToFile(id)
158-
if (fs.existsSync(file))
159-
return await fs.promises.readFile(file, 'utf-8')
160-
else
161-
console.error(`failed to find file for vue-inspector: ${file}, referenced by id ${id}.`)
162-
}
163-
},
164-
transform(code, id) {
165-
const { filename, query } = parseVueRequest(id)
161+
async load(id) {
162+
if (id === 'virtual:vue-inspector-options') {
163+
return `export default ${JSON.stringify({ ...normalizedOptions, serverOptions })}`
164+
}
165+
else if (id.startsWith(inspectorPath)) {
166+
const { query } = parseVueRequest(id)
167+
if (query.type)
168+
return
169+
// read file ourselves to avoid getting shut out by vites fs.allow check
170+
const file = idToFile(id)
171+
if (fs.existsSync(file))
172+
return await fs.promises.readFile(file, 'utf-8')
173+
else
174+
console.error(`failed to find file for vue-inspector: ${file}, referenced by id ${id}.`)
175+
}
176+
},
177+
transform(code, id) {
178+
const { filename, query } = parseVueRequest(id)
166179

167-
const isJsx = filename.endsWith('.jsx') || filename.endsWith('.tsx') || (filename.endsWith('.vue') && query.isJsx)
168-
const isTpl = filename.endsWith('.vue') && query.type !== 'style' && !query.raw
180+
const isJsx = filename.endsWith('.jsx') || filename.endsWith('.tsx') || (filename.endsWith('.vue') && query.isJsx)
181+
const isTpl = filename.endsWith('.vue') && query.type !== 'style' && !query.raw
169182

170-
if (isJsx || isTpl)
171-
return compileSFCTemplate({ code, id: filename, type: isJsx ? 'jsx' : 'template' })
183+
if (isJsx || isTpl)
184+
return compileSFCTemplate({ code, id: filename, type: isJsx ? 'jsx' : 'template' })
172185

173-
if (!appendTo)
174-
return
186+
if (!appendTo)
187+
return
175188

176-
if ((typeof appendTo === 'string' && filename.endsWith(appendTo))
189+
if ((typeof appendTo === 'string' && filename.endsWith(appendTo))
177190
|| (appendTo instanceof RegExp && appendTo.test(filename)))
178-
return { code: `${code}\nimport 'virtual:vue-inspector-path:load.js'` }
179-
},
180-
configureServer(server) {
181-
const _printUrls = server.printUrls
182-
const { toggleComboKey } = normalizedOptions
183-
184-
toggleComboKey && (server.printUrls = () => {
185-
const keys = normalizeComboKeyPrint(toggleComboKey)
186-
_printUrls()
187-
console.log(` ${green('➜')} ${bold('Vue Inspector')}: ${green(`Press ${yellow(keys)} in App to toggle the Inspector`)}\n`)
188-
})
189-
},
190-
transformIndexHtml(html) {
191-
if (appendTo)
192-
return
193-
return {
194-
html,
195-
tags: [
196-
{
197-
tag: 'script',
198-
injectTo: 'head',
199-
attrs: {
200-
type: 'module',
201-
src: '/@id/virtual:vue-inspector-path:load.js',
191+
return { code: `${code}\nimport 'virtual:vue-inspector-path:load.js'` }
192+
},
193+
configureServer(server) {
194+
const _printUrls = server.printUrls
195+
const { toggleComboKey } = normalizedOptions
196+
197+
toggleComboKey && (server.printUrls = () => {
198+
const keys = normalizeComboKeyPrint(toggleComboKey)
199+
_printUrls()
200+
console.log(` ${green('➜')} ${bold('Vue Inspector')}: ${green(`Press ${yellow(keys)} in App to toggle the Inspector`)}\n`)
201+
})
202+
},
203+
transformIndexHtml(html) {
204+
if (appendTo)
205+
return
206+
return {
207+
html,
208+
tags: [
209+
{
210+
tag: 'script',
211+
injectTo: 'head',
212+
attrs: {
213+
type: 'module',
214+
src: '/@id/virtual:vue-inspector-path:load.js',
215+
},
202216
},
203-
},
204-
],
205-
}
206-
},
207-
configResolved(resolvedConfig) {
208-
serverOptions = resolvedConfig.server
217+
],
218+
}
219+
},
220+
configResolved(resolvedConfig) {
221+
serverOptions = resolvedConfig.server
222+
},
209223
},
224+
{
225+
name: 'vite-plugin-vue-inspector:post',
226+
enforce: 'post',
227+
apply(_, { command }) {
228+
// apply only on serve and not for test
229+
return cleanHtml && vue === 3 && command === 'serve' && process.env.NODE_ENV !== 'test'
230+
},
231+
transform(code) {
232+
if (code.includes('_interopVNode'))
233+
return
234+
if (!code.includes('data-v-inspector'))
235+
return
236+
237+
const fn = new Set<string>()
238+
const s = new MagicString(code)
239+
240+
s.replace(/(createElementVNode|createVNode|createElementBlock) as _\1,?/g, (_, name) => {
241+
fn.add(name)
242+
return ''
243+
})
244+
245+
if (!fn.size)
246+
return
247+
248+
s.appendLeft(0, `/* Injection by vite-plugin-vue-inspector Start */
249+
import { ${Array.from(fn.values()).map(i => `${i} as __${i}`).join(',')} } from 'vue'
250+
function _interopVNode(vnode) {
251+
if (vnode && vnode.props && 'data-v-inspector' in vnode.props) {
252+
const data = vnode.props['data-v-inspector']
253+
delete vnode.props['data-v-inspector']
254+
Object.defineProperty(vnode.props, '__v_inspector', { value: data, enumerable: false })
210255
}
256+
return vnode
257+
}
258+
${Array.from(fn.values()).map(i => `function _${i}(...args) { return _interopVNode(__${i}(...args)) }`).join('\n')}
259+
/* Injection by vite-plugin-vue-inspector End */
260+
`)
261+
262+
return {
263+
code: s.toString(),
264+
map: s.generateMap({ hires: 'boundary' }),
265+
}
266+
},
267+
},
268+
]
211269
}
212270
export default VitePluginInspector

packages/playground/nuxt/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"preview": "nuxi preview"
88
},
99
"devDependencies": {
10-
"nuxt": "3.3.1",
10+
"nuxt": "3.7.4",
1111
"unplugin-vue-inspector": "workspace:*",
1212
"vite-plugin-vue-inspector": "workspace:*"
1313
}

packages/playground/vue2/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
"build": "vite build"
77
},
88
"dependencies": {
9-
"@vue/composition-api": "^1.7.1",
9+
"@vue/composition-api": "^1.7.2",
1010
"vue": "2.7.14",
1111
"vue-property-decorator": "^9.1.2",
1212
"vue-template-compiler": "2.7.14"
1313
},
1414
"devDependencies": {
15-
"sass": "^1.59.3",
15+
"sass": "^1.68.0",
1616
"unplugin-vue-inspector": "workspace:*",
1717
"vite-plugin-vue-inspector": "workspace:*",
1818
"vite-plugin-vue2": "^1.9.3"

packages/playground/vue3/package.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
"name": "playground-vue3",
33
"private": true,
44
"scripts": {
5-
"dev": "vite dev",
5+
"dev": "nodemon -w ../../packages/core/dist --exec \"vite dev\"",
66
"build": "vite build"
77
},
88
"dependencies": {
9-
"vue": "^3.2.47"
9+
"vue": "^3.3.4"
1010
},
1111
"devDependencies": {
12-
"@vitejs/plugin-vue": "^4.1.0",
13-
"@vitejs/plugin-vue-jsx": "^3.0.1",
14-
"@vue/compiler-sfc": "^3.2.47",
15-
"sass": "^1.59.3",
12+
"@vitejs/plugin-vue": "^4.3.4",
13+
"@vitejs/plugin-vue-jsx": "^3.0.2",
14+
"@vue/compiler-sfc": "^3.3.4",
15+
"sass": "^1.68.0",
1616
"vite-plugin-vue-inspector": "workspace:*"
1717
}
1818
}

0 commit comments

Comments
 (0)