Skip to content

Commit

Permalink
feat: add a feature option to support custom component id generator (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Jinjiang authored Nov 13, 2024
1 parent 23ea2f9 commit 7a1fc4c
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 2 deletions.
17 changes: 17 additions & 0 deletions packages/plugin-vue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ export interface Options {
* - **default:** `false`
*/
prodHydrationMismatchDetails?: boolean
/**
* Customize the component ID generation strategy.
* - `'filepath'`: hash the file path (relative to the project root)
* - `'filepath-source'`: hash the file path and the source code
* - `function`: custom function that takes the file path, source code,
* whether in production mode, and the default hash function as arguments
* - **default:** `'filepath'` in development, `'filepath-source'` in production
*/
componentIdGenerator?:
| 'filepath'
| 'filepath-source'
| ((
filepath: string,
source: string,
isProduction: boolean | undefined,
getHash: (text: string) => string,
) => string)
}

// `script`, `template` and `style` are lower-level compiler options
Expand Down
17 changes: 17 additions & 0 deletions packages/plugin-vue/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,23 @@ export interface Options {
* - **default:** `false`
*/
prodHydrationMismatchDetails?: boolean
/**
* Customize the component ID generation strategy.
* - `'filepath'`: hash the file path (relative to the project root)
* - `'filepath-source'`: hash the file path and the source code
* - `function`: custom function that takes the file path, source code,
* whether in production mode, and the default hash function as arguments
* - **default:** `'filepath'` in development, `'filepath-source'` in production
*/
componentIdGenerator?:
| 'filepath'
| 'filepath-source'
| ((
filepath: string,
source: string,
isProduction: boolean | undefined,
getHash: (text: string) => string,
) => string)
}

/**
Expand Down
27 changes: 25 additions & 2 deletions packages/plugin-vue/src/utils/descriptorCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ const prevCache = new Map<string, SFCDescriptor | undefined>()
export function createDescriptor(
filename: string,
source: string,
{ root, isProduction, sourceMap, compiler, template }: ResolvedOptions,
{
root,
isProduction,
sourceMap,
compiler,
template,
features,
}: ResolvedOptions,
hmr = false,
): SFCParseResult {
const { descriptor, errors } = compiler.parse(source, {
Expand All @@ -34,7 +41,23 @@ export function createDescriptor(
// ensure the path is normalized in a way that is consistent inside
// project (relative to root) and on different systems.
const normalizedPath = normalizePath(path.relative(root, filename))
descriptor.id = getHash(normalizedPath + (isProduction ? source : ''))

const componentIdGenerator = features?.componentIdGenerator
if (componentIdGenerator === 'filepath') {
descriptor.id = getHash(normalizedPath)
} else if (componentIdGenerator === 'filepath-source') {
descriptor.id = getHash(normalizedPath + source)
} else if (typeof componentIdGenerator === 'function') {
descriptor.id = componentIdGenerator(
normalizedPath,
source,
isProduction,
getHash,
)
} else {
descriptor.id = getHash(normalizedPath + (isProduction ? source : ''))
}

;(hmr ? hmrCache : cache).set(filename, descriptor)
return { descriptor, errors }
}
Expand Down
7 changes: 7 additions & 0 deletions playground/vue-custom-id/Main.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script setup>
import Foo from './components/Foo.vue'
</script>

<template>
<Foo />
</template>
8 changes: 8 additions & 0 deletions playground/vue-custom-id/__tests__/vue-custom-id.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { expect, test } from 'vitest'
import { page } from '~utils'

test('should render', async () => {
expect(await page.innerHTML('div')).toMatch(
'<h1 data-v-components-foo="">Foo</h1>',
)
})
9 changes: 9 additions & 0 deletions playground/vue-custom-id/components/Foo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<template>
<h1>Foo</h1>
</template>

<style scoped>
h1 {
color: red;
}
</style>
7 changes: 7 additions & 0 deletions playground/vue-custom-id/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div id="app"></div>
<script type="module">
import { createApp, defineCustomElement } from 'vue'
import Main from './Main.vue'

createApp(Main).mount('#app')
</script>
17 changes: 17 additions & 0 deletions playground/vue-custom-id/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@vitejs/test-vue-custom-id",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"debug": "node --inspect-brk vite",
"preview": "vite preview"
},
"dependencies": {
"vue": "catalog:"
},
"devDependencies": {
"@vitejs/plugin-vue": "workspace:*"
}
}
21 changes: 21 additions & 0 deletions playground/vue-custom-id/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { defineConfig } from 'vite'
import vuePlugin from '@vitejs/plugin-vue'

export default defineConfig({
plugins: [
vuePlugin({
features: {
componentIdGenerator: (filename) => {
return filename
.replace(/\.\w+$/, '')
.replace(/[^a-z0-9]/gi, '-')
.toLowerCase()
},
},
}),
],
build: {
// to make tests faster
minify: false,
},
})
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7a1fc4c

Please sign in to comment.