-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
/
layer-aliasing.ts
89 lines (77 loc) · 2.92 KB
/
layer-aliasing.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { existsSync, readdirSync } from 'node:fs'
import { createUnplugin } from 'unplugin'
import type { NuxtConfigLayer } from 'nuxt/schema'
import { resolveAlias } from '@nuxt/kit'
import { join, normalize, relative } from 'pathe'
import MagicString from 'magic-string'
interface LayerAliasingOptions {
sourcemap?: boolean
transform?: boolean
root: string
dev: boolean
layers: NuxtConfigLayer[]
}
const ALIAS_RE = /(?<=['"])[~@]{1,2}(?=\/)/g
const ALIAS_RE_SINGLE = /(?<=['"])[~@]{1,2}(?=\/)/
export const LayerAliasingPlugin = createUnplugin((options: LayerAliasingOptions) => {
const aliases: Record<string, { aliases: Record<string, string>, prefix: string, publicDir: false | string }> = {}
for (const layer of options.layers) {
const srcDir = layer.config.srcDir || layer.cwd
const rootDir = layer.config.rootDir || layer.cwd
const publicDir = join(srcDir, layer.config?.dir?.public || 'public')
aliases[srcDir] = {
aliases: {
'~': layer.config?.alias?.['~'] || srcDir,
'@': layer.config?.alias?.['@'] || srcDir,
'~~': layer.config?.alias?.['~~'] || rootDir,
'@@': layer.config?.alias?.['@@'] || rootDir
},
prefix: relative(options.root, publicDir),
publicDir: !options.dev && existsSync(publicDir) && publicDir
}
}
const layers = Object.keys(aliases).sort((a, b) => b.length - a.length)
return {
name: 'nuxt:layer-aliasing',
enforce: 'pre',
vite: {
resolveId: {
order: 'pre',
async handler (id, importer) {
if (!importer) { return }
const layer = layers.find(l => importer.startsWith(l))
if (!layer) { return }
const publicDir = aliases[layer].publicDir
if (id.startsWith('/') && publicDir && readdirSync(publicDir).some(file => file === id.slice(1) || id.startsWith('/' + file + '/'))) {
const resolvedId = '/' + join(aliases[layer].prefix, id.slice(1))
return await this.resolve(resolvedId, importer, { skipSelf: true })
}
const resolvedId = resolveAlias(id, aliases[layer].aliases)
if (resolvedId !== id) {
return await this.resolve(resolvedId, importer, { skipSelf: true })
}
}
}
},
// webpack-only transform
transformInclude: (id) => {
if (!options.transform) { return false }
const _id = normalize(id)
return layers.some(dir => _id.startsWith(dir))
},
transform (code, id) {
if (!options.transform) { return }
const _id = normalize(id)
const layer = layers.find(l => _id.startsWith(l))
if (!layer || !ALIAS_RE_SINGLE.test(code)) { return }
const s = new MagicString(code)
s.replace(ALIAS_RE, r => aliases[layer].aliases[r as '~'] || r)
if (s.hasChanged()) {
return {
code: s.toString(),
map: options.sourcemap ? s.generateMap({ hires: true }) : undefined
}
}
}
}
})