mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-18 06:31:27 +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 type { TreeShakeComposablesPluginOptions } from './plugins/tree-shake'
|
||||||
import { TreeShakeComposablesPlugin } from './plugins/tree-shake'
|
import { TreeShakeComposablesPlugin } from './plugins/tree-shake'
|
||||||
import { DevOnlyPlugin } from './plugins/dev-only'
|
import { DevOnlyPlugin } from './plugins/dev-only'
|
||||||
|
import { LayerAliasingPlugin } from './plugins/layer-aliasing'
|
||||||
import { addModuleTranspiles } from './modules'
|
import { addModuleTranspiles } from './modules'
|
||||||
import { initNitro } from './nitro'
|
import { initNitro } from './nitro'
|
||||||
import schemaModule from './schema'
|
import schemaModule from './schema'
|
||||||
@ -80,6 +81,21 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
addVitePlugin(ImportProtectionPlugin.vite(config))
|
addVitePlugin(ImportProtectionPlugin.vite(config))
|
||||||
addWebpackPlugin(ImportProtectionPlugin.webpack(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', () => {
|
nuxt.hook('modules:done', () => {
|
||||||
// Add unctx transform
|
// Add unctx transform
|
||||||
addVitePlugin(UnctxTransformPlugin(nuxt).vite({ sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client }))
|
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. */
|
/** Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header. */
|
||||||
respectNoSSRHeader: false,
|
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', () => {
|
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 () => {
|
it('extends foo/middleware/foo', async () => {
|
||||||
const html = await $fetch('/foo')
|
const html = await $fetch('/foo')
|
||||||
expect(html).toContain('Middleware | foo: Injected by extended middleware from 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>
|
<script setup>
|
||||||
|
import { test } from '~/alias/test'
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: 'foo'
|
middleware: 'foo'
|
||||||
})
|
})
|
||||||
@ -8,6 +9,7 @@ const foo = useExtendsFoo()
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<div>{{ test }}</div>
|
||||||
<div>Extended page from foo</div>
|
<div>Extended page from foo</div>
|
||||||
<div>Middleware | foo: {{ $route.meta.foo }}</div>
|
<div>Middleware | foo: {{ $route.meta.foo }}</div>
|
||||||
<div>Composable | useExtendsFoo: {{ foo }}</div>
|
<div>Composable | useExtendsFoo: {{ foo }}</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user