Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 13c8c59

Browse files
fix: make alias can be overridden properly (#1648)
Co-authored-by: meteorlxy <[email protected]>
1 parent aa20eaa commit 13c8c59

File tree

16 files changed

+98
-47
lines changed

16 files changed

+98
-47
lines changed

e2e/docs/.vuepress/config.ts

+9
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,13 @@ export default defineUserConfig({
8383
},
8484

8585
plugins: [fooPlugin],
86+
87+
// The alias entries are intentionally ordered by key length to ensure
88+
// that more specific aliases (e.g., '@dir/a.js') take precedence over
89+
// less specific ones (e.g., '@dir'). Do not reorder these entries.
90+
alias: {
91+
'@dir/a.js': path.resolve(__dirname, '../../modules/dir2/a.js'),
92+
'@dir': path.resolve(__dirname, '../../modules/dir1'),
93+
'@dir/b.js': path.resolve(__dirname, '../../modules/dir2/b.js'),
94+
},
8695
})

e2e/docs/hooks/alias/dir.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<p id="result">{{result}}</p>
2+
3+
<script setup>
4+
import { result } from '@dir/c.js'
5+
</script>

e2e/docs/hooks/alias/override.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<p id="a">{{aResult}}</p>
2+
<p id="b">{{bResult}}</p>
3+
4+
<script setup>
5+
import { result as aResult } from '@dir/a.js'
6+
import { result as bResult } from '@dir/b.js'
7+
</script>

e2e/modules/dir1/a.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const result = 'dir1 > a'

e2e/modules/dir1/b.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const result = 'dir1 > b'

e2e/modules/dir1/c.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const result = 'dir1 > c'

e2e/modules/dir2/a.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const result = 'dir2 > a'

e2e/modules/dir2/b.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const result = 'dir2 > b'

e2e/tests/hooks/alias/dir.spec.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { expect, test } from '@playwright/test'
2+
3+
test('should apply alias to subpath', async ({ page }) => {
4+
await page.goto('hooks/alias/dir.html')
5+
await expect(page.locator('#result')).toHaveText('dir1 > c')
6+
})
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { expect, test } from '@playwright/test'
2+
3+
test('longer aliases should override shorter ones', async ({ page }) => {
4+
await page.goto('hooks/alias/override.html')
5+
await expect(page.locator('#a')).toHaveText('dir2 > a')
6+
await expect(page.locator('#b')).toHaveText('dir2 > b')
7+
})

packages/bundler-vite/src/plugins/vuepressConfigPlugin.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,17 @@ const resolveAlias = async ({
2525
const aliasResult = await app.pluginApi.hooks.alias.process(app, isServer)
2626

2727
aliasResult.forEach((aliasObject) => {
28-
Object.entries(aliasObject).forEach(([key, value]) => {
29-
alias[key] = value as string
30-
})
28+
Object.assign(alias, aliasObject)
3129
})
3230

3331
return [
34-
...Object.keys(alias).map((item) => ({
35-
find: item,
36-
replacement: alias[item],
37-
})),
32+
...Object.keys(alias)
33+
// sort alias by length in descending order to ensure longer alias is handled first
34+
.sort((a, b) => b.length - a.length)
35+
.map((item) => ({
36+
find: item,
37+
replacement: alias[item],
38+
})),
3839
...(isServer
3940
? []
4041
: [

packages/bundler-webpack/src/config/handleResolve.ts

+22-16
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,27 @@ export const handleResolve = async ({
1414
isServer: boolean
1515
}): Promise<void> => {
1616
// aliases
17-
config.resolve.alias
18-
.set('@source', app.dir.source())
19-
.set('@temp', app.dir.temp())
20-
.set('@internal', app.dir.temp('internal'))
17+
const alias = {
18+
'@source': app.dir.source(),
19+
'@temp': app.dir.temp(),
20+
'@internal': app.dir.temp('internal'),
21+
}
2122

22-
// extensionAlias
23-
config.resolve.extensionAlias.merge({
24-
'.js': ['.js', '.ts'],
25-
'.mjs': ['.mjs', '.mts'],
23+
// plugin hook: alias
24+
const aliasResult = await app.pluginApi.hooks.alias.process(app, isServer)
25+
26+
aliasResult.forEach((aliasObject) => {
27+
Object.assign(alias, aliasObject)
2628
})
2729

30+
// set aliases
31+
config.resolve.alias.merge(
32+
Object.fromEntries(
33+
// sort alias by length in descending order to ensure longer alias is handled first
34+
Object.entries(alias).sort(([a], [b]) => b.length - a.length),
35+
),
36+
)
37+
2838
// extensions
2939
config.resolve.extensions.merge([
3040
'.js',
@@ -35,13 +45,9 @@ export const handleResolve = async ({
3545
'.json',
3646
])
3747

38-
// plugin hook: alias
39-
const aliasResult = await app.pluginApi.hooks.alias.process(app, isServer)
40-
41-
// set aliases
42-
aliasResult.forEach((aliasObject) => {
43-
Object.entries(aliasObject).forEach(([key, value]) => {
44-
config.resolve.alias.set(key, value as string)
45-
})
48+
// extensionAlias
49+
config.resolve.extensionAlias.merge({
50+
'.js': ['.js', '.ts'],
51+
'.mjs': ['.mjs', '.mts'],
4652
})
4753
}

packages/core/src/pluginApi/createPluginApiRegisterHooks.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { PluginApi } from '../types/index.js'
1+
import type { AliasHook, DefineHook, PluginApi } from '../types/index.js'
22
import { normalizeAliasDefineHook } from './normalizeAliasDefineHook.js'
33
import { normalizeClientConfigFileHook } from './normalizeClientConfigFileHook.js'
44

@@ -30,14 +30,14 @@ export const createPluginApiRegisterHooks =
3030
if (alias) {
3131
hooks.alias.add({
3232
pluginName,
33-
hook: normalizeAliasDefineHook(alias),
33+
hook: normalizeAliasDefineHook<AliasHook>(alias),
3434
})
3535
}
3636

3737
if (define) {
3838
hooks.define.add({
3939
pluginName,
40-
hook: normalizeAliasDefineHook(define),
40+
hook: normalizeAliasDefineHook<DefineHook>(define),
4141
})
4242
}
4343

Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { isFunction } from '@vuepress/shared'
2-
import type { AliasDefineHook } from '../types/index.js'
2+
import type { AliasHook, DefineHook } from '../types/index.js'
33

44
/**
55
* Normalize alias and define hook
66
*
77
* @internal
88
*/
99
export const normalizeAliasDefineHook =
10-
(hook: AliasDefineHook['exposed']): AliasDefineHook['normalized'] =>
10+
<T extends AliasHook | DefineHook>(hook: T['exposed']): T['normalized'] =>
1111
async (app, isServer) =>
1212
isFunction(hook) ? hook(app, isServer) : hook

packages/core/src/types/pluginApi/hooks.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,15 @@ export type ClientConfigFileHook = Hook<
4141
(app: App) => Promise<string>
4242
>
4343

44-
// alias and define hook
45-
export type AliasDefineHook = Hook<
44+
// alias hook
45+
export type AliasHook = Hook<
46+
| Record<string, string>
47+
| ((app: App, isServer: boolean) => PromiseOrNot<Record<string, string>>),
48+
(app: App, isServer: boolean) => Promise<Record<string, string>>
49+
>
50+
51+
// define hook
52+
export type DefineHook = Hook<
4653
| Record<string, unknown>
4754
| ((app: App, isServer: boolean) => PromiseOrNot<Record<string, unknown>>),
4855
(app: App, isServer: boolean) => Promise<Record<string, unknown>>
@@ -62,8 +69,8 @@ export interface Hooks {
6269
extendsPage: ExtendsHook<Page>
6370
extendsBundlerOptions: ExtendsHook<BundlerOptions>
6471
clientConfigFile: ClientConfigFileHook
65-
alias: AliasDefineHook
66-
define: AliasDefineHook
72+
alias: AliasHook
73+
define: DefineHook
6774
}
6875

6976
/**
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { path } from '@vuepress/utils'
22
import { expect, it, vi } from 'vitest'
3-
import type { AliasDefineHook, Bundler } from '../../src/index.js'
3+
import type { AliasHook, Bundler, DefineHook } from '../../src/index.js'
44
import { createBaseApp, normalizeAliasDefineHook } from '../../src/index.js'
55

66
const app = createBaseApp({
@@ -9,13 +9,19 @@ const app = createBaseApp({
99
bundler: {} as Bundler,
1010
})
1111

12+
it('should wrap object with a function', async () => {
13+
const rawHook: AliasHook['exposed'] = {
14+
foo: 'bar',
15+
}
16+
const normalizedHook = normalizeAliasDefineHook(rawHook)
17+
expect(await normalizedHook(app, true)).toEqual({ foo: 'bar' })
18+
})
19+
1220
it('should keep function as is', async () => {
13-
const rawHook: AliasDefineHook['exposed'] = vi.fn(
14-
(_app, isServer: boolean) => ({
15-
foo: 'bar',
16-
isServer,
17-
}),
18-
)
21+
const rawHook: DefineHook['exposed'] = vi.fn((_app, isServer: boolean) => ({
22+
foo: 'bar',
23+
isServer,
24+
}))
1925
const normalizedHook = normalizeAliasDefineHook(rawHook)
2026
expect(await normalizedHook(app, true)).toEqual({
2127
foo: 'bar',
@@ -24,11 +30,3 @@ it('should keep function as is', async () => {
2430
expect(rawHook).toHaveBeenCalledTimes(1)
2531
expect(rawHook).toHaveBeenCalledWith(app, true)
2632
})
27-
28-
it('should wrap object with a function', async () => {
29-
const rawHook: AliasDefineHook['exposed'] = {
30-
foo: 'bar',
31-
}
32-
const normalizedHook = normalizeAliasDefineHook(rawHook)
33-
expect(await normalizedHook(app, true)).toEqual({ foo: 'bar' })
34-
})

0 commit comments

Comments
 (0)