fix(nuxt): resolve full component paths (#28843)

This commit is contained in:
Daniel Roe 2024-09-05 17:38:43 +02:00 committed by GitHub
parent 2c1dfcf81d
commit d7586adfc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 14 additions and 6 deletions

View File

@ -1,6 +1,6 @@
import fs, { statSync } from 'node:fs' import { existsSync, statSync, writeFileSync } from 'node:fs'
import { join, normalize, relative, resolve } from 'pathe' import { join, normalize, relative, resolve } from 'pathe'
import { addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, logger, resolveAlias, updateTemplates } from '@nuxt/kit' import { addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, logger, resolveAlias, resolvePath, updateTemplates } from '@nuxt/kit'
import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema' import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema'
import { distDir } from '../dirs' import { distDir } from '../dirs'
@ -169,6 +169,10 @@ export default defineNuxtModule<ComponentsOptions>({
await nuxt.callHook('components:extend', newComponents) await nuxt.callHook('components:extend', newComponents)
// add server placeholder for .client components server side. issue: #7085 // add server placeholder for .client components server side. issue: #7085
for (const component of newComponents) { for (const component of newComponents) {
if (!(component as any /* untyped internal property */)._scanned && !(component.filePath in nuxt.vfs) && !existsSync(component.filePath)) {
// attempt to resolve component path
component.filePath = await resolvePath(component.filePath)
}
if (component.mode === 'client' && !newComponents.some(c => c.pascalName === component.pascalName && c.mode === 'server')) { if (component.mode === 'client' && !newComponents.some(c => c.pascalName === component.pascalName && c.mode === 'server')) {
newComponents.push({ newComponents.push({
...component, ...component,
@ -236,17 +240,17 @@ export default defineNuxtModule<ComponentsOptions>({
const selectiveClient = typeof nuxt.options.experimental.componentIslands === 'object' && nuxt.options.experimental.componentIslands.selectiveClient const selectiveClient = typeof nuxt.options.experimental.componentIslands === 'object' && nuxt.options.experimental.componentIslands.selectiveClient
if (isClient && selectiveClient) { if (isClient && selectiveClient) {
fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}') writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}')
if (!nuxt.options.dev) { if (!nuxt.options.dev) {
config.plugins.push(componentsChunkPlugin.vite({ config.plugins.push(componentsChunkPlugin.vite({
getComponents, getComponents,
buildDir: nuxt.options.buildDir, buildDir: nuxt.options.buildDir,
})) }))
} else { } else {
fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), `export const paths = ${JSON.stringify( writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), `export const paths = ${JSON.stringify(
getComponents().filter(c => c.mode === 'client' || c.mode === 'all').reduce((acc, c) => { getComponents().filter(c => c.mode === 'client' || c.mode === 'all').reduce((acc, c) => {
if (c.filePath.endsWith('.vue') || c.filePath.endsWith('.js') || c.filePath.endsWith('.ts')) { return Object.assign(acc, { [c.pascalName]: `/@fs/${c.filePath}` }) } if (c.filePath.endsWith('.vue') || c.filePath.endsWith('.js') || c.filePath.endsWith('.ts')) { return Object.assign(acc, { [c.pascalName]: `/@fs/${c.filePath}` }) }
const filePath = fs.existsSync(`${c.filePath}.vue`) ? `${c.filePath}.vue` : fs.existsSync(`${c.filePath}.js`) ? `${c.filePath}.js` : `${c.filePath}.ts` const filePath = existsSync(`${c.filePath}.vue`) ? `${c.filePath}.vue` : existsSync(`${c.filePath}.js`) ? `${c.filePath}.js` : `${c.filePath}.ts`
return Object.assign(acc, { [c.pascalName]: `/@fs/${filePath}` }) return Object.assign(acc, { [c.pascalName]: `/@fs/${filePath}` })
}, {} as Record<string, string>), }, {} as Record<string, string>),
)}`) )}`)
@ -307,7 +311,7 @@ export default defineNuxtModule<ComponentsOptions>({
getComponents, getComponents,
})) }))
} else { } else {
fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}') writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}')
} }
} }
}) })

View File

@ -126,6 +126,8 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
export: 'default', export: 'default',
// by default, give priority to scanned components // by default, give priority to scanned components
priority: dir.priority ?? 1, priority: dir.priority ?? 1,
// @ts-expect-error untyped property
_scanned: true,
} }
if (typeof dir.extendComponent === 'function') { if (typeof dir.extendComponent === 'function') {

View File

@ -241,6 +241,8 @@ it('components:scanComponents', async () => {
for (const c of scannedComponents) { for (const c of scannedComponents) {
// @ts-expect-error filePath is not optional but we don't want it to be in the snapshot // @ts-expect-error filePath is not optional but we don't want it to be in the snapshot
delete c.filePath delete c.filePath
// @ts-expect-error _scanned is added internally but we don't want it to be in the snapshot
delete c._scanned
} }
expect(scannedComponents).deep.eq(expectedComponents) expect(scannedComponents).deep.eq(expectedComponents)
}) })