mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(nuxt): support ~
/~~
/@
/@@
aliases within layers (#19986)
This commit is contained in:
parent
ee8d3f6ea6
commit
f40b3e2492
@ -20,6 +20,7 @@ import { UnctxTransformPlugin } from './plugins/unctx'
|
||||
import type { TreeShakeComposablesPluginOptions } from './plugins/tree-shake'
|
||||
import { TreeShakeComposablesPlugin } from './plugins/tree-shake'
|
||||
import { DevOnlyPlugin } from './plugins/dev-only'
|
||||
import { LayerAliasingPlugin } from './plugins/layer-aliasing'
|
||||
import { addModuleTranspiles } from './modules'
|
||||
import { initNitro } from './nitro'
|
||||
import schemaModule from './schema'
|
||||
@ -80,6 +81,21 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
addVitePlugin(ImportProtectionPlugin.vite(config))
|
||||
addWebpackPlugin(ImportProtectionPlugin.webpack(config))
|
||||
|
||||
if (nuxt.options.experimental.localLayerAliases) {
|
||||
// Add layer aliasing support for ~, ~~, @ and @@ aliases
|
||||
addVitePlugin(LayerAliasingPlugin.vite({
|
||||
sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client,
|
||||
// skip top-level layer (user's project) as the aliases will already be correctly resolved
|
||||
layers: nuxt.options._layers.slice(1)
|
||||
}))
|
||||
addWebpackPlugin(LayerAliasingPlugin.webpack({
|
||||
sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client,
|
||||
// skip top-level layer (user's project) as the aliases will already be correctly resolved
|
||||
layers: nuxt.options._layers.slice(1),
|
||||
transform: true
|
||||
}))
|
||||
}
|
||||
|
||||
nuxt.hook('modules:done', () => {
|
||||
// Add unctx transform
|
||||
addVitePlugin(UnctxTransformPlugin(nuxt).vite({ sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client }))
|
||||
|
68
packages/nuxt/src/core/plugins/layer-aliasing.ts
Normal file
68
packages/nuxt/src/core/plugins/layer-aliasing.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { createUnplugin } from 'unplugin'
|
||||
import type { NuxtConfigLayer } from 'nuxt/schema'
|
||||
import { resolveAlias } from '@nuxt/kit'
|
||||
import { normalize } from 'pathe'
|
||||
import MagicString from 'magic-string'
|
||||
|
||||
interface LayerAliasingOptions {
|
||||
sourcemap?: boolean
|
||||
transform?: boolean
|
||||
layers: NuxtConfigLayer[]
|
||||
}
|
||||
|
||||
const ALIAS_RE = /(?<=['"])[~@]{1,2}(?=\/)/g
|
||||
|
||||
export const LayerAliasingPlugin = createUnplugin((options: LayerAliasingOptions) => {
|
||||
const aliases = Object.fromEntries(options.layers.map(l => [l.config.srcDir || l.cwd, {
|
||||
'~': l.config?.alias?.['~'] || l.config.srcDir || l.cwd,
|
||||
'@': l.config?.alias?.['@'] || l.config.srcDir || l.cwd,
|
||||
'~~': l.config?.alias?.['~~'] || l.config.rootDir || l.cwd,
|
||||
'@@': l.config?.alias?.['@@'] || l.config.rootDir || l.cwd
|
||||
}]))
|
||||
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 resolvedId = resolveAlias(id, aliases[layer])
|
||||
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 || !code.match(ALIAS_RE)) { return }
|
||||
|
||||
const s = new MagicString(code)
|
||||
s.replace(ALIAS_RE, r => aliases[layer][r as '~'] || r)
|
||||
|
||||
if (s.hasChanged()) {
|
||||
return {
|
||||
code: s.toString(),
|
||||
map: options.sourcemap ? s.generateMap({ source: id, includeContent: true }) : undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
@ -162,5 +162,8 @@ export default defineUntypedSchema({
|
||||
|
||||
/** Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header. */
|
||||
respectNoSSRHeader: false,
|
||||
|
||||
/** Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. */
|
||||
localLayerAliases: true,
|
||||
}
|
||||
})
|
||||
|
@ -707,6 +707,10 @@ describe('extends support', () => {
|
||||
})
|
||||
|
||||
describe('middlewares', () => {
|
||||
it('works with layer aliases', async () => {
|
||||
const html = await $fetch('/foo')
|
||||
expect(html).toContain('from layer alias')
|
||||
})
|
||||
it('extends foo/middleware/foo', async () => {
|
||||
const html = await $fetch('/foo')
|
||||
expect(html).toContain('Middleware | foo: Injected by extended middleware from foo')
|
||||
|
1
test/fixtures/basic/extends/node_modules/foo/alias/test.ts
generated
vendored
Normal file
1
test/fixtures/basic/extends/node_modules/foo/alias/test.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export const test = 'from layer alias'
|
2
test/fixtures/basic/extends/node_modules/foo/pages/foo.vue
generated
vendored
2
test/fixtures/basic/extends/node_modules/foo/pages/foo.vue
generated
vendored
@ -1,4 +1,5 @@
|
||||
<script setup>
|
||||
import { test } from '~/alias/test'
|
||||
definePageMeta({
|
||||
middleware: 'foo'
|
||||
})
|
||||
@ -8,6 +9,7 @@ const foo = useExtendsFoo()
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div>{{ test }}</div>
|
||||
<div>Extended page from foo</div>
|
||||
<div>Middleware | foo: {{ $route.meta.foo }}</div>
|
||||
<div>Composable | useExtendsFoo: {{ foo }}</div>
|
||||
|
Loading…
Reference in New Issue
Block a user