Skip to content

Commit 7a1fc4c

Browse files
authored
feat: add a feature option to support custom component id generator (#461)
1 parent 23ea2f9 commit 7a1fc4c

File tree

10 files changed

+138
-2
lines changed

10 files changed

+138
-2
lines changed

packages/plugin-vue/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,23 @@ export interface Options {
5858
* - **default:** `false`
5959
*/
6060
prodHydrationMismatchDetails?: boolean
61+
/**
62+
* Customize the component ID generation strategy.
63+
* - `'filepath'`: hash the file path (relative to the project root)
64+
* - `'filepath-source'`: hash the file path and the source code
65+
* - `function`: custom function that takes the file path, source code,
66+
* whether in production mode, and the default hash function as arguments
67+
* - **default:** `'filepath'` in development, `'filepath-source'` in production
68+
*/
69+
componentIdGenerator?:
70+
| 'filepath'
71+
| 'filepath-source'
72+
| ((
73+
filepath: string,
74+
source: string,
75+
isProduction: boolean | undefined,
76+
getHash: (text: string) => string,
77+
) => string)
6178
}
6279

6380
// `script`, `template` and `style` are lower-level compiler options

packages/plugin-vue/src/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,23 @@ export interface Options {
138138
* - **default:** `false`
139139
*/
140140
prodHydrationMismatchDetails?: boolean
141+
/**
142+
* Customize the component ID generation strategy.
143+
* - `'filepath'`: hash the file path (relative to the project root)
144+
* - `'filepath-source'`: hash the file path and the source code
145+
* - `function`: custom function that takes the file path, source code,
146+
* whether in production mode, and the default hash function as arguments
147+
* - **default:** `'filepath'` in development, `'filepath-source'` in production
148+
*/
149+
componentIdGenerator?:
150+
| 'filepath'
151+
| 'filepath-source'
152+
| ((
153+
filepath: string,
154+
source: string,
155+
isProduction: boolean | undefined,
156+
getHash: (text: string) => string,
157+
) => string)
141158
}
142159

143160
/**

packages/plugin-vue/src/utils/descriptorCache.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,14 @@ const prevCache = new Map<string, SFCDescriptor | undefined>()
2222
export function createDescriptor(
2323
filename: string,
2424
source: string,
25-
{ root, isProduction, sourceMap, compiler, template }: ResolvedOptions,
25+
{
26+
root,
27+
isProduction,
28+
sourceMap,
29+
compiler,
30+
template,
31+
features,
32+
}: ResolvedOptions,
2633
hmr = false,
2734
): SFCParseResult {
2835
const { descriptor, errors } = compiler.parse(source, {
@@ -34,7 +41,23 @@ export function createDescriptor(
3441
// ensure the path is normalized in a way that is consistent inside
3542
// project (relative to root) and on different systems.
3643
const normalizedPath = normalizePath(path.relative(root, filename))
37-
descriptor.id = getHash(normalizedPath + (isProduction ? source : ''))
44+
45+
const componentIdGenerator = features?.componentIdGenerator
46+
if (componentIdGenerator === 'filepath') {
47+
descriptor.id = getHash(normalizedPath)
48+
} else if (componentIdGenerator === 'filepath-source') {
49+
descriptor.id = getHash(normalizedPath + source)
50+
} else if (typeof componentIdGenerator === 'function') {
51+
descriptor.id = componentIdGenerator(
52+
normalizedPath,
53+
source,
54+
isProduction,
55+
getHash,
56+
)
57+
} else {
58+
descriptor.id = getHash(normalizedPath + (isProduction ? source : ''))
59+
}
60+
3861
;(hmr ? hmrCache : cache).set(filename, descriptor)
3962
return { descriptor, errors }
4063
}

playground/vue-custom-id/Main.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script setup>
2+
import Foo from './components/Foo.vue'
3+
</script>
4+
5+
<template>
6+
<Foo />
7+
</template>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { expect, test } from 'vitest'
2+
import { page } from '~utils'
3+
4+
test('should render', async () => {
5+
expect(await page.innerHTML('div')).toMatch(
6+
'<h1 data-v-components-foo="">Foo</h1>',
7+
)
8+
})
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<template>
2+
<h1>Foo</h1>
3+
</template>
4+
5+
<style scoped>
6+
h1 {
7+
color: red;
8+
}
9+
</style>

playground/vue-custom-id/index.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div id="app"></div>
2+
<script type="module">
3+
import { createApp, defineCustomElement } from 'vue'
4+
import Main from './Main.vue'
5+
6+
createApp(Main).mount('#app')
7+
</script>

playground/vue-custom-id/package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "@vitejs/test-vue-custom-id",
3+
"private": true,
4+
"version": "0.0.0",
5+
"scripts": {
6+
"dev": "vite",
7+
"build": "vite build",
8+
"debug": "node --inspect-brk vite",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
"vue": "catalog:"
13+
},
14+
"devDependencies": {
15+
"@vitejs/plugin-vue": "workspace:*"
16+
}
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { defineConfig } from 'vite'
2+
import vuePlugin from '@vitejs/plugin-vue'
3+
4+
export default defineConfig({
5+
plugins: [
6+
vuePlugin({
7+
features: {
8+
componentIdGenerator: (filename) => {
9+
return filename
10+
.replace(/\.\w+$/, '')
11+
.replace(/[^a-z0-9]/gi, '-')
12+
.toLowerCase()
13+
},
14+
},
15+
}),
16+
],
17+
build: {
18+
// to make tests faster
19+
minify: false,
20+
},
21+
})

pnpm-lock.yaml

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy