mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
refactor(nuxt, kit): improve type strictness (#6685)
This commit is contained in:
parent
cdc75373d4
commit
e1e39b7e79
@ -11,7 +11,7 @@ export function isIgnored (pathname: string): boolean {
|
||||
|
||||
// Happens with CLI reloads
|
||||
if (!nuxt) {
|
||||
return null
|
||||
return false
|
||||
}
|
||||
|
||||
if (!nuxt._ignore) {
|
||||
@ -28,5 +28,5 @@ export function isIgnored (pathname: string): boolean {
|
||||
if (relativePath.startsWith('..')) {
|
||||
return false
|
||||
}
|
||||
return relativePath && nuxt._ignore.ignores(relativePath)
|
||||
return !!(relativePath && nuxt._ignore.ignores(relativePath))
|
||||
}
|
||||
|
@ -85,10 +85,10 @@ export function requireModulePkg (id: string, opts: RequireModuleOptions = {}) {
|
||||
/** Resolve the path of a module. */
|
||||
export function resolveModule (id: string, opts: ResolveModuleOptions = {}) {
|
||||
return normalize(_require.resolve(id, {
|
||||
paths: [].concat(
|
||||
paths: ([] as string[]).concat(
|
||||
// @ts-ignore
|
||||
global.__NUXT_PREPATHS__,
|
||||
opts.paths,
|
||||
opts.paths || [],
|
||||
process.cwd(),
|
||||
// @ts-ignore
|
||||
global.__NUXT_PATHS__
|
||||
@ -100,8 +100,8 @@ export function resolveModule (id: string, opts: ResolveModuleOptions = {}) {
|
||||
export function tryResolveModule (path: string, opts: ResolveModuleOptions = {}): string | null {
|
||||
try {
|
||||
return resolveModule(path, opts)
|
||||
} catch (error) {
|
||||
if (error.code !== 'MODULE_NOT_FOUND') {
|
||||
} catch (error: any) {
|
||||
if (error?.code !== 'MODULE_NOT_FOUND') {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,11 @@ export function parallel<T, R> (
|
||||
return Promise.all(tasks.map(fn))
|
||||
}
|
||||
|
||||
export function chainFn (base, fn) {
|
||||
export function chainFn<Fn> (base: Fn, fn: Fn): Fn {
|
||||
if (typeof fn !== 'function') {
|
||||
return base
|
||||
}
|
||||
return function (...args) {
|
||||
return function (this: any, ...args: any[]) {
|
||||
if (typeof base !== 'function') {
|
||||
return fn.apply(this, args)
|
||||
}
|
||||
@ -38,5 +38,5 @@ export function chainFn (base, fn) {
|
||||
return baseResult
|
||||
}
|
||||
return fnResult
|
||||
}
|
||||
} as unknown as Fn
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ import { useNuxt } from './context'
|
||||
import { logger } from './logger'
|
||||
import { addTemplate } from './template'
|
||||
|
||||
export function addLayout (tmpl: NuxtTemplate, name?: string) {
|
||||
export function addLayout (this: any, template: NuxtTemplate, name?: string) {
|
||||
const nuxt = useNuxt()
|
||||
const { filename, src } = addTemplate(tmpl)
|
||||
const layoutName = kebabCase(name || parse(tmpl.filename).name).replace(/["']/g, '')
|
||||
const { filename, src } = addTemplate(template)
|
||||
const layoutName = kebabCase(name || parse(filename).name).replace(/["']/g, '')
|
||||
|
||||
if (isNuxt2(nuxt)) {
|
||||
// Nuxt 2 adds layouts in options
|
||||
|
@ -7,7 +7,7 @@ import { NuxtConfigSchema } from '@nuxt/schema'
|
||||
export interface LoadNuxtConfigOptions extends LoadConfigOptions<NuxtConfig> {}
|
||||
|
||||
export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<NuxtOptions> {
|
||||
const { config: nuxtConfig, configFile, layers, cwd } = await loadConfig<NuxtConfig>({
|
||||
const result = await loadConfig<NuxtConfig>({
|
||||
name: 'nuxt',
|
||||
configFile: 'nuxt.config',
|
||||
rcFile: '.nuxtrc',
|
||||
@ -15,6 +15,8 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
|
||||
globalRc: true,
|
||||
...opts
|
||||
})
|
||||
const { configFile, layers = [], cwd } = result
|
||||
const nuxtConfig = result.config!
|
||||
|
||||
// Fill config
|
||||
nuxtConfig.rootDir = nuxtConfig.rootDir || cwd
|
||||
@ -25,7 +27,7 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
|
||||
for (const layer of layers) {
|
||||
layer.config = layer.config || {}
|
||||
layer.config.rootDir = layer.config.rootDir ?? layer.cwd
|
||||
layer.config.srcDir = resolve(layer.config.rootDir, layer.config.srcDir)
|
||||
layer.config.srcDir = resolve(layer.config.rootDir!, layer.config.srcDir!)
|
||||
}
|
||||
|
||||
// Filter layers
|
||||
|
@ -29,7 +29,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
|
||||
|
||||
const nearestNuxtPkg = await Promise.all(['nuxt3', 'nuxt', 'nuxt-edge']
|
||||
.map(pkg => resolvePackageJSON(pkg, { url: opts.cwd }).catch(() => null)))
|
||||
.then(r => r.filter(Boolean).sort((a, b) => b.length - a.length)[0])
|
||||
.then(r => (r.filter(Boolean) as string[]).sort((a, b) => b.length - a.length)[0])
|
||||
if (!nearestNuxtPkg) {
|
||||
throw new Error(`Cannot find any nuxt version from ${opts.cwd}`)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { relative } from 'pathe'
|
||||
import type { Nuxt, NuxtPluginTemplate, NuxtTemplate, ModuleContainer } from '@nuxt/schema'
|
||||
import type { Nuxt, ModuleContainer } from '@nuxt/schema'
|
||||
import { chainFn } from '../internal/task'
|
||||
import { addTemplate } from '../template'
|
||||
import { addLayout } from '../layout'
|
||||
@ -12,11 +12,10 @@ import { installModule } from './install'
|
||||
const MODULE_CONTAINER_KEY = '__module_container__'
|
||||
|
||||
export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
|
||||
if (nuxt[MODULE_CONTAINER_KEY]) {
|
||||
return nuxt[MODULE_CONTAINER_KEY]
|
||||
}
|
||||
// @ts-ignore
|
||||
if (nuxt[MODULE_CONTAINER_KEY]) { return nuxt[MODULE_CONTAINER_KEY] }
|
||||
|
||||
async function requireModule (moduleOpts) {
|
||||
async function requireModule (moduleOpts: any) {
|
||||
let src, inlineOptions
|
||||
if (typeof moduleOpts === 'string') {
|
||||
src = moduleOpts
|
||||
@ -35,7 +34,7 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
|
||||
await installModule(src, inlineOptions)
|
||||
}
|
||||
|
||||
nuxt[MODULE_CONTAINER_KEY] = <ModuleContainer>{
|
||||
const container: ModuleContainer = {
|
||||
nuxt,
|
||||
options: nuxt.options,
|
||||
|
||||
@ -47,7 +46,7 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
|
||||
|
||||
addServerMiddleware,
|
||||
|
||||
addTemplate (template: string | NuxtTemplate) {
|
||||
addTemplate (template) {
|
||||
if (typeof template === 'string') {
|
||||
template = { src: template }
|
||||
}
|
||||
@ -57,15 +56,15 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
|
||||
return addTemplate(template)
|
||||
},
|
||||
|
||||
addPlugin (pluginTemplate: NuxtPluginTemplate): NuxtPluginTemplate {
|
||||
addPlugin (pluginTemplate) {
|
||||
return addPluginTemplate(pluginTemplate)
|
||||
},
|
||||
|
||||
addLayout (tmpl: NuxtTemplate, name?: string) {
|
||||
addLayout (tmpl, name) {
|
||||
return addLayout(tmpl, name)
|
||||
},
|
||||
|
||||
addErrorLayout (dst: string) {
|
||||
addErrorLayout (dst) {
|
||||
const relativeBuildDir = relative(nuxt.options.rootDir, nuxt.options.buildDir)
|
||||
nuxt.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
|
||||
},
|
||||
@ -93,5 +92,9 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
nuxt[MODULE_CONTAINER_KEY] = container
|
||||
|
||||
// @ts-ignore
|
||||
return nuxt[MODULE_CONTAINER_KEY]
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { promises as fsp } from 'node:fs'
|
||||
import defu from 'defu'
|
||||
import { applyDefaults } from 'untyped'
|
||||
import { dirname } from 'pathe'
|
||||
import type { Nuxt, NuxtTemplate, NuxtModule, ModuleOptions, ModuleDefinition } from '@nuxt/schema'
|
||||
import type { Nuxt, NuxtModule, ModuleOptions, ModuleDefinition, NuxtOptions, ResolvedNuxtTemplate } from '@nuxt/schema'
|
||||
import { logger } from '../logger'
|
||||
import { useNuxt, nuxtCtx, tryUseNuxt } from '../context'
|
||||
import { isNuxt2, checkNuxtCompatibility } from '../compatibility'
|
||||
@ -31,9 +31,9 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
||||
|
||||
// Resolves module options from inline options, [configKey] in nuxt.config, defaults and schema
|
||||
function getOptions (inlineOptions?: OptionsT, nuxt: Nuxt = useNuxt()) {
|
||||
const configKey = definition.meta.configKey || definition.meta.name
|
||||
const configKey = definition.meta!.configKey || definition.meta!.name!
|
||||
const _defaults = definition.defaults instanceof Function ? definition.defaults(nuxt) : definition.defaults
|
||||
let _options = defu(inlineOptions, nuxt.options[configKey], _defaults) as OptionsT
|
||||
let _options = defu(inlineOptions, nuxt.options[configKey as keyof NuxtOptions], _defaults) as OptionsT
|
||||
if (definition.schema) {
|
||||
_options = applyDefaults(definition.schema, _options) as OptionsT
|
||||
}
|
||||
@ -41,13 +41,13 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
||||
}
|
||||
|
||||
// Module format is always a simple function
|
||||
async function normalizedModule (inlineOptions: OptionsT, nuxt: Nuxt) {
|
||||
async function normalizedModule (this: any, inlineOptions: OptionsT, nuxt: Nuxt) {
|
||||
if (!nuxt) {
|
||||
nuxt = tryUseNuxt() || this.nuxt /* invoked by nuxt 2 */
|
||||
}
|
||||
|
||||
// Avoid duplicate installs
|
||||
const uniqueKey = definition.meta.name || definition.meta.configKey
|
||||
const uniqueKey = definition.meta!.name || definition.meta!.configKey
|
||||
if (uniqueKey) {
|
||||
nuxt.options._requiredModules = nuxt.options._requiredModules || {}
|
||||
if (nuxt.options._requiredModules[uniqueKey]) {
|
||||
@ -58,10 +58,10 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
||||
}
|
||||
|
||||
// Check compatibility constraints
|
||||
if (definition.meta.compatibility) {
|
||||
const issues = await checkNuxtCompatibility(definition.meta.compatibility, nuxt)
|
||||
if (definition.meta!.compatibility) {
|
||||
const issues = await checkNuxtCompatibility(definition.meta!.compatibility, nuxt)
|
||||
if (issues.length) {
|
||||
logger.warn(`Module \`${definition.meta.name}\` is disabled due to incompatibility issues:\n${issues.toString()}`)
|
||||
logger.warn(`Module \`${definition.meta!.name}\` is disabled due to incompatibility issues:\n${issues.toString()}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -78,7 +78,7 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
||||
}
|
||||
|
||||
// Call setup
|
||||
await definition.setup?.call(null, _options, nuxt)
|
||||
await definition.setup?.call(null as any, _options, nuxt)
|
||||
}
|
||||
|
||||
// Define getters for options and meta
|
||||
@ -92,11 +92,13 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
||||
const NUXT2_SHIMS_KEY = '__nuxt2_shims_key__'
|
||||
function nuxt2Shims (nuxt: Nuxt) {
|
||||
// Avoid duplicate install and only apply to Nuxt2
|
||||
// @ts-ignore
|
||||
if (!isNuxt2(nuxt) || nuxt[NUXT2_SHIMS_KEY]) { return }
|
||||
// @ts-ignore
|
||||
nuxt[NUXT2_SHIMS_KEY] = true
|
||||
|
||||
// Allow using nuxt.hooks
|
||||
// @ts-ignore Nuxt 2 extends hookable
|
||||
// @ts-expect-error Nuxt 2 extends hookable
|
||||
nuxt.hooks = nuxt
|
||||
|
||||
// Allow using useNuxt()
|
||||
@ -106,7 +108,7 @@ function nuxt2Shims (nuxt: Nuxt) {
|
||||
}
|
||||
|
||||
// Support virtual templates with getContents() by writing them to .nuxt directory
|
||||
let virtualTemplates: NuxtTemplate[]
|
||||
let virtualTemplates: ResolvedNuxtTemplate[]
|
||||
nuxt.hook('builder:prepared', (_builder, buildOptions) => {
|
||||
virtualTemplates = buildOptions.templates.filter(t => t.getContents)
|
||||
for (const template of virtualTemplates) {
|
||||
|
@ -10,7 +10,12 @@ export async function installModule (moduleToInstall: string | NuxtModule, _inli
|
||||
const { nuxtModule, inlineOptions } = await normalizeModule(moduleToInstall, _inlineOptions)
|
||||
|
||||
// Call module
|
||||
await nuxtModule.call(useModuleContainer(), inlineOptions, nuxt)
|
||||
await nuxtModule.call(
|
||||
// Provide this context for backwards compatibility with Nuxt 2
|
||||
useModuleContainer() as any,
|
||||
inlineOptions,
|
||||
nuxt
|
||||
)
|
||||
|
||||
nuxt.options._installedModules = nuxt.options._installedModules || []
|
||||
nuxt.options._installedModules.push({
|
||||
|
@ -73,7 +73,7 @@ export function addPluginTemplate (plugin: NuxtPluginTemplate | string, opts: Ad
|
||||
const normalizedPlugin: NuxtPlugin = typeof plugin === 'string'
|
||||
? { src: plugin }
|
||||
// Update plugin src to template destination
|
||||
: { ...plugin, src: addTemplate(plugin).dst }
|
||||
: { ...plugin, src: addTemplate(plugin).dst! }
|
||||
|
||||
return addPlugin(normalizedPlugin, opts)
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ export function resolveAlias (path: string, alias?: Record<string, string>): str
|
||||
}
|
||||
|
||||
export interface Resolver {
|
||||
resolve(...path): string
|
||||
resolve(...path: string[]): string
|
||||
resolvePath(path: string, opts?: ResolvePathOptions): Promise<string>
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { existsSync } from 'node:fs'
|
||||
import { basename, parse, resolve } from 'pathe'
|
||||
import hash from 'hash-sum'
|
||||
import type { NuxtTemplate } from '@nuxt/schema'
|
||||
import type { NuxtTemplate, ResolvedNuxtTemplate } from '@nuxt/schema'
|
||||
import { useNuxt } from './context'
|
||||
|
||||
/**
|
||||
* Renders given template using lodash template during build into the project buildDir
|
||||
*/
|
||||
export function addTemplate (_template: NuxtTemplate | string) {
|
||||
export function addTemplate (_template: NuxtTemplate<any> | string) {
|
||||
const nuxt = useNuxt()
|
||||
|
||||
// Noprmalize template
|
||||
// Normalize template
|
||||
const template = normalizeTemplate(_template)
|
||||
|
||||
// Remove any existing template with the same filename
|
||||
@ -26,7 +26,7 @@ export function addTemplate (_template: NuxtTemplate | string) {
|
||||
/**
|
||||
* Normalize a nuxt template object
|
||||
*/
|
||||
export function normalizeTemplate (template: NuxtTemplate | string): NuxtTemplate {
|
||||
export function normalizeTemplate (template: NuxtTemplate<any> | string): ResolvedNuxtTemplate<any> {
|
||||
if (!template) {
|
||||
throw new Error('Invalid template: ' + JSON.stringify(template))
|
||||
}
|
||||
@ -69,5 +69,5 @@ export function normalizeTemplate (template: NuxtTemplate | string): NuxtTemplat
|
||||
template.dst = resolve(nuxt.options.buildDir, template.filename)
|
||||
}
|
||||
|
||||
return template
|
||||
return template as ResolvedNuxtTemplate<any>
|
||||
}
|
||||
|
11
packages/kit/tsconfig.json
Normal file
11
packages/kit/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts",
|
||||
"./test/**/*.ts"
|
||||
]
|
||||
}
|
@ -34,7 +34,7 @@ export const clearError = async (options: { redirect?: string } = {}) => {
|
||||
error.value = null
|
||||
}
|
||||
|
||||
export const isNuxtError = (err?: string | object): err is NuxtError => err && typeof err === 'object' && ('__nuxt_error' in err)
|
||||
export const isNuxtError = (err?: string | object): err is NuxtError => !!(err && typeof err === 'object' && ('__nuxt_error' in err))
|
||||
|
||||
export const createError = (err: string | Partial<NuxtError>): NuxtError => {
|
||||
const _err: NuxtError = _createError(err)
|
||||
|
@ -80,7 +80,7 @@ interface _NuxtApp {
|
||||
message: string
|
||||
description: string
|
||||
data?: any
|
||||
}
|
||||
} | null
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { Unimport } from 'unimport'
|
||||
import { AutoImportsOptions } from '@nuxt/schema'
|
||||
import { normalize } from 'pathe'
|
||||
|
||||
export const TransformPlugin = createUnplugin(({ ctx, options, sourcemap }: {ctx: Unimport, options: Partial<AutoImportsOptions>, sourcemap?: boolean }) => {
|
||||
export const TransformPlugin = createUnplugin(({ ctx, options, sourcemap }: { ctx: Unimport, options: Partial<AutoImportsOptions>, sourcemap?: boolean }) => {
|
||||
return {
|
||||
name: 'nuxt:auto-imports-transform',
|
||||
enforce: 'post',
|
||||
@ -48,7 +48,9 @@ export const TransformPlugin = createUnplugin(({ ctx, options, sourcemap }: {ctx
|
||||
if (s.hasChanged()) {
|
||||
return {
|
||||
code: s.toString(),
|
||||
map: sourcemap && s.generateMap({ source: id, includeContent: true })
|
||||
map: sourcemap
|
||||
? s.generateMap({ source: id, includeContent: true })
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,9 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => {
|
||||
if (s.hasChanged()) {
|
||||
return {
|
||||
code: s.toString(),
|
||||
map: options.sourcemap && s.generateMap({ source: id, includeContent: true })
|
||||
map: options.sourcemap
|
||||
? s.generateMap({ source: id, includeContent: true })
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import { TreeShakeTemplatePlugin } from './tree-shake'
|
||||
|
||||
const isPureObjectOrString = (val: any) => (!Array.isArray(val) && typeof val === 'object') || typeof val === 'string'
|
||||
const isDirectory = (p: string) => { try { return statSync(p).isDirectory() } catch (_e) { return false } }
|
||||
function compareDirByPathLength ({ path: pathA }, { path: pathB }) {
|
||||
function compareDirByPathLength ({ path: pathA }: { path: string}, { path: pathB }: { path: string}) {
|
||||
return pathB.split(/[\\/]/).filter(Boolean).length - pathA.split(/[\\/]/).filter(Boolean).length
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ export default defineNuxtModule<ComponentsOptions>({
|
||||
dirs: []
|
||||
},
|
||||
setup (componentOptions, nuxt) {
|
||||
let componentDirs = []
|
||||
let componentDirs: ComponentsDir[] = []
|
||||
const context = {
|
||||
components: [] as Component[]
|
||||
}
|
||||
@ -37,7 +37,7 @@ export default defineNuxtModule<ComponentsOptions>({
|
||||
: context.components
|
||||
}
|
||||
|
||||
const normalizeDirs = (dir: any, cwd: string) => {
|
||||
const normalizeDirs = (dir: any, cwd: string): ComponentsDir[] => {
|
||||
if (Array.isArray(dir)) {
|
||||
return dir.map(dir => normalizeDirs(dir, cwd)).flat().sort(compareDirByPathLength)
|
||||
}
|
||||
@ -48,14 +48,14 @@ export default defineNuxtModule<ComponentsOptions>({
|
||||
]
|
||||
}
|
||||
if (typeof dir === 'string') {
|
||||
return {
|
||||
path: resolve(cwd, resolveAlias(dir))
|
||||
}
|
||||
return [
|
||||
{ path: resolve(cwd, resolveAlias(dir)) }
|
||||
]
|
||||
}
|
||||
if (!dir) {
|
||||
return []
|
||||
}
|
||||
const dirs = (dir.dirs || [dir]).map(dir => typeof dir === 'string' ? { path: dir } : dir).filter(_dir => _dir.path)
|
||||
const dirs: ComponentsDir[] = (dir.dirs || [dir]).map((dir: any): ComponentsDir => typeof dir === 'string' ? { path: dir } : dir).filter((_dir: ComponentsDir) => _dir.path)
|
||||
return dirs.map(_dir => ({
|
||||
..._dir,
|
||||
path: resolve(cwd, resolveAlias(_dir.path))
|
||||
@ -113,7 +113,7 @@ export default defineNuxtModule<ComponentsOptions>({
|
||||
// components.d.ts
|
||||
addTemplate({ ...componentsTypeTemplate, options: { getComponents } })
|
||||
// components.plugin.mjs
|
||||
addPluginTemplate({ ...componentsPluginTemplate, options: { getComponents } })
|
||||
addPluginTemplate({ ...componentsPluginTemplate, options: { getComponents } } as any)
|
||||
// components.server.mjs
|
||||
addTemplate({ ...componentsTemplate, filename: 'components.server.mjs', options: { getComponents, mode: 'server' } })
|
||||
// components.client.mjs
|
||||
@ -121,12 +121,12 @@ export default defineNuxtModule<ComponentsOptions>({
|
||||
|
||||
nuxt.hook('vite:extendConfig', (config, { isClient }) => {
|
||||
const mode = isClient ? 'client' : 'server'
|
||||
config.resolve.alias['#components'] = resolve(nuxt.options.buildDir, `components.${mode}.mjs`)
|
||||
;(config.resolve!.alias as any)['#components'] = resolve(nuxt.options.buildDir, `components.${mode}.mjs`)
|
||||
})
|
||||
nuxt.hook('webpack:config', (configs) => {
|
||||
for (const config of configs) {
|
||||
const mode = config.name === 'server' ? 'server' : 'client'
|
||||
config.resolve.alias['#components'] = resolve(nuxt.options.buildDir, `components.${mode}.mjs`)
|
||||
;(config.resolve!.alias as any)['#components'] = resolve(nuxt.options.buildDir, `components.${mode}.mjs`)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -58,12 +58,12 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
|
||||
*
|
||||
* @example third-components/index.vue -> third-component
|
||||
* if not take the filename
|
||||
* @example thid-components/Awesome.vue -> Awesome
|
||||
* @example third-components/Awesome.vue -> Awesome
|
||||
*/
|
||||
let fileName = basename(filePath, extname(filePath))
|
||||
|
||||
const global = /\.(global)$/.test(fileName) || dir.global
|
||||
const mode = fileName.match(/(?<=\.)(client|server)(\.global)?$/)?.[1] as 'client' | 'server' || 'all'
|
||||
const mode = (fileName.match(/(?<=\.)(client|server)(\.global)?$/)?.[1] || 'all') as 'client' | 'server' | 'all'
|
||||
fileName = fileName.replace(/(\.(client|server))?(\.global)?$/, '')
|
||||
|
||||
if (fileName.toLowerCase() === 'index') {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { isAbsolute, relative } from 'pathe'
|
||||
import type { Component, Nuxt } from '@nuxt/schema'
|
||||
import type { Component, Nuxt, NuxtPluginTemplate, NuxtTemplate } from '@nuxt/schema'
|
||||
import { genDynamicImport, genExport, genObjectFromRawEntries } from 'knitwork'
|
||||
|
||||
export interface ComponentsTemplateContext {
|
||||
@ -25,9 +25,9 @@ const createImportMagicComments = (options: ImportMagicCommentsOptions) => {
|
||||
].filter(Boolean).join(', ')
|
||||
}
|
||||
|
||||
export const componentsPluginTemplate = {
|
||||
export const componentsPluginTemplate: NuxtPluginTemplate<ComponentsTemplateContext> = {
|
||||
filename: 'components.plugin.mjs',
|
||||
getContents ({ options }: ComponentsTemplateContext) {
|
||||
getContents ({ options }) {
|
||||
const globalComponents = options.getComponents().filter(c => c.global === true)
|
||||
|
||||
return `import { defineAsyncComponent } from 'vue'
|
||||
@ -50,9 +50,9 @@ export default defineNuxtPlugin(nuxtApp => {
|
||||
}
|
||||
}
|
||||
|
||||
export const componentsTemplate = {
|
||||
export const componentsTemplate: NuxtTemplate<ComponentsTemplateContext> = {
|
||||
// components.[server|client].mjs'
|
||||
getContents ({ options }: ComponentsTemplateContext) {
|
||||
getContents ({ options }) {
|
||||
return [
|
||||
'import { defineAsyncComponent } from \'vue\'',
|
||||
...options.getComponents(options.mode).flatMap((c) => {
|
||||
@ -69,9 +69,9 @@ export const componentsTemplate = {
|
||||
}
|
||||
}
|
||||
|
||||
export const componentsTypeTemplate = {
|
||||
export const componentsTypeTemplate: NuxtTemplate<ComponentsTemplateContext> = {
|
||||
filename: 'components.d.ts',
|
||||
getContents: ({ options, nuxt }: ComponentsTemplateContext) => {
|
||||
getContents: ({ options, nuxt }) => {
|
||||
const buildDir = nuxt.options.buildDir
|
||||
const componentTypes = options.getComponents().map(c => [
|
||||
c.pascalName,
|
||||
|
@ -31,7 +31,7 @@ export const TreeShakeTemplatePlugin = createUnplugin((options: TreeShakeTemplat
|
||||
regexpMap.set(components, new RegExp(`(${clientOnlyComponents.join('|')})`, 'g'))
|
||||
}
|
||||
|
||||
const COMPONENTS_RE = regexpMap.get(components)
|
||||
const COMPONENTS_RE = regexpMap.get(components)!
|
||||
const s = new MagicString(code)
|
||||
|
||||
// Do not render client-only slots on SSR, but preserve attributes
|
||||
@ -40,7 +40,9 @@ export const TreeShakeTemplatePlugin = createUnplugin((options: TreeShakeTemplat
|
||||
if (s.hasChanged()) {
|
||||
return {
|
||||
code: s.toString(),
|
||||
map: options.sourcemap && s.generateMap({ source: id, includeContent: true })
|
||||
map: options.sourcemap
|
||||
? s.generateMap({ source: id, includeContent: true })
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ export const vueAppPatterns = (nuxt: Nuxt) => [
|
||||
[/^(nuxt3|nuxt)$/, '`nuxt3`/`nuxt` cannot be imported directly. Instead, import runtime Nuxt composables from `#app` or `#imports`.'],
|
||||
[/^((|~|~~|@|@@)\/)?nuxt\.config(\.|$)/, 'Importing directly from a `nuxt.config` file is not allowed. Instead, use runtime config or a module.'],
|
||||
[/(^|node_modules\/)@vue\/composition-api/],
|
||||
...nuxt.options.modules.filter(m => typeof m === 'string').map((m: string) =>
|
||||
[new RegExp(`^${escapeRE(m)}$`), 'Importing directly from module entry points is not allowed.']),
|
||||
...nuxt.options.modules.filter(m => typeof m === 'string').map((m: any) =>
|
||||
[new RegExp(`^${escapeRE(m as string)}$`), 'Importing directly from module entry points is not allowed.']),
|
||||
...[/(^|node_modules\/)@nuxt\/kit/, /^nitropack/]
|
||||
.map(i => [i, 'This module cannot be imported in the Vue part of your app.']),
|
||||
[new RegExp(escapeRE(resolve(nuxt.options.srcDir, (nuxt.options.dir as any).server || 'server')) + '\\/(api|routes|middleware|plugins)\\/'), 'Importing from server is not allowed in the Vue part of your app.']
|
||||
@ -31,10 +31,11 @@ export const ImportProtectionPlugin = createUnplugin(function (options: ImportPr
|
||||
name: 'nuxt:import-protection',
|
||||
enforce: 'pre',
|
||||
resolveId (id, importer) {
|
||||
if (!importer) { return }
|
||||
if (importersToExclude.some(p => typeof p === 'string' ? importer === p : p.test(importer))) { return }
|
||||
|
||||
const invalidImports = options.patterns.filter(([pattern]) => pattern instanceof RegExp ? pattern.test(id) : pattern === id)
|
||||
let matched: boolean
|
||||
let matched = false
|
||||
for (const match of invalidImports) {
|
||||
cache[id] = cache[id] || new Map()
|
||||
const [pattern, warning] = match
|
||||
|
@ -35,13 +35,15 @@ export const TreeShakePlugin = createUnplugin((options: TreeShakePluginOptions)
|
||||
const s = new MagicString(code)
|
||||
const strippedCode = stripLiteral(code)
|
||||
for (const match of strippedCode.matchAll(COMPOSABLE_RE) || []) {
|
||||
s.overwrite(match.index, match.index + match[0].length, `${match[1]} /*#__PURE__*/ false && ${match[2]}`)
|
||||
s.overwrite(match.index!, match.index! + match[0].length, `${match[1]} /*#__PURE__*/ false && ${match[2]}`)
|
||||
}
|
||||
|
||||
if (s.hasChanged()) {
|
||||
return {
|
||||
code: s.toString(),
|
||||
map: options.sourcemap && s.generateMap({ source: id, includeContent: true })
|
||||
map: options.sourcemap
|
||||
? s.generateMap({ source: id, includeContent: true })
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
if (!vm) { return }
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
head.removeHeadObjs(headObj)
|
||||
head.removeHeadObjs(headObj as any)
|
||||
head.updateDOM()
|
||||
})
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ export default defineNuxtModule({
|
||||
// Check for router options
|
||||
const routerOptionsFiles = (await Promise.all(nuxt.options._layers.map(
|
||||
async layer => await findPath(resolve(layer.config.srcDir, 'app/router.options'))
|
||||
))).filter(Boolean)
|
||||
))).filter(Boolean) as string[]
|
||||
|
||||
const configRouterOptions = genObjectFromRawEntries(Object.entries(nuxt.options.router.options)
|
||||
.map(([key, value]) => [key, genString(value as string)]))
|
||||
|
@ -20,8 +20,8 @@ describe('auto-imports:transform', () => {
|
||||
|
||||
const transformPlugin = TransformPlugin.raw({ ctx, options: { transform: { exclude: [/node_modules/] } } }, { framework: 'rollup' })
|
||||
const transform = async (source: string) => {
|
||||
const { code } = await transformPlugin.transform.call({ error: null, warn: null }, source, '') || { code: null }
|
||||
return code
|
||||
const result = await transformPlugin.transform!.call({ error: null, warn: null } as any, source, '')
|
||||
return typeof result === 'string' ? result : result?.code
|
||||
}
|
||||
|
||||
it('should correct inject', async () => {
|
||||
@ -29,13 +29,13 @@ describe('auto-imports:transform', () => {
|
||||
})
|
||||
|
||||
it('should ignore existing imported', async () => {
|
||||
expect(await transform('import { ref } from "foo"; const a = ref(0)')).to.equal(null)
|
||||
expect(await transform('import { computed as ref } from "foo"; const a = ref(0)')).to.equal(null)
|
||||
expect(await transform('import ref from "foo"; const a = ref(0)')).to.equal(null)
|
||||
expect(await transform('import { z as ref } from "foo"; const a = ref(0)')).to.equal(null)
|
||||
expect(await transform('let ref = () => {}; const a = ref(0)')).to.equal(null)
|
||||
expect(await transform('let { ref } = Vue; const a = ref(0)')).to.equal(null)
|
||||
expect(await transform('let [\ncomputed,\nref\n] = Vue; const a = ref(0); const b = ref(0)')).to.equal(null)
|
||||
expect(await transform('import { ref } from "foo"; const a = ref(0)')).to.equal(undefined)
|
||||
expect(await transform('import { computed as ref } from "foo"; const a = ref(0)')).to.equal(undefined)
|
||||
expect(await transform('import ref from "foo"; const a = ref(0)')).to.equal(undefined)
|
||||
expect(await transform('import { z as ref } from "foo"; const a = ref(0)')).to.equal(undefined)
|
||||
expect(await transform('let ref = () => {}; const a = ref(0)')).to.equal(undefined)
|
||||
expect(await transform('let { ref } = Vue; const a = ref(0)')).to.equal(undefined)
|
||||
expect(await transform('let [\ncomputed,\nref\n] = Vue; const a = ref(0); const b = ref(0)')).to.equal(undefined)
|
||||
})
|
||||
|
||||
it('should ignore comments', async () => {
|
||||
@ -48,7 +48,7 @@ describe('auto-imports:transform', () => {
|
||||
})
|
||||
|
||||
it('should exclude files from transform', async () => {
|
||||
expect(await transform('excluded')).toEqual(null)
|
||||
expect(await transform('excluded')).toEqual(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
@ -65,7 +65,7 @@ describe('auto-imports:nuxt', () => {
|
||||
continue
|
||||
}
|
||||
it(`should register ${name} globally`, () => {
|
||||
expect(defaultPresets.find(a => a.from === '#app').imports).to.include(name)
|
||||
expect(defaultPresets.find(a => a.from === '#app')!.imports).to.include(name)
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
@ -176,7 +176,7 @@ describe('auto-imports:vue', () => {
|
||||
continue
|
||||
}
|
||||
it(`should register ${name} globally`, () => {
|
||||
expect(defaultPresets.find(a => a.from === 'vue').imports).toContain(name)
|
||||
expect(defaultPresets.find(a => a.from === 'vue')!.imports).toContain(name)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -304,7 +304,7 @@ describe('pages:generateRouteKey', () => {
|
||||
|
||||
const tests = [
|
||||
{ description: 'should handle overrides', override: 'key', route: getRouteProps(), output: 'key' },
|
||||
{ description: 'should handle overrides', override: route => route.meta.key as string, route: getRouteProps(), output: 'route-meta-key' },
|
||||
{ description: 'should handle overrides', override: (route: any) => route.meta.key as string, route: getRouteProps(), output: 'route-meta-key' },
|
||||
{ description: 'should handle overrides', override: false as any, route: getRouteProps(), output: false },
|
||||
{
|
||||
description: 'should key dynamic routes without keys',
|
||||
|
@ -4,7 +4,7 @@ import { expect, it, vi } from 'vitest'
|
||||
import { scanComponents } from '../src/components/scan'
|
||||
|
||||
const fixtureDir = resolve(__dirname, 'fixture')
|
||||
const rFixture = (...p) => resolve(fixtureDir, ...p)
|
||||
const rFixture = (...p: string[]) => resolve(fixtureDir, ...p)
|
||||
|
||||
vi.mock('@nuxt/kit', () => ({
|
||||
isIgnored: () => false
|
||||
@ -108,6 +108,7 @@ const srcDir = rFixture('.')
|
||||
it('components:scanComponents', async () => {
|
||||
const scannedComponents = await scanComponents(dirs, srcDir)
|
||||
for (const c of scannedComponents) {
|
||||
// @ts-ignore
|
||||
delete c.filePath
|
||||
}
|
||||
expect(scannedComponents).deep.eq(expectedComponents)
|
||||
|
@ -9,7 +9,7 @@ import type { NuxtTemplate, Nuxt, NuxtApp } from './nuxt'
|
||||
import type { Preset as ImportPreset, Import } from 'unimport'
|
||||
import type { NuxtConfig, NuxtOptions } from './config'
|
||||
import type { Nitro, NitroConfig } from 'nitropack'
|
||||
import type { Component, ComponentsDir, ScanDir, ComponentsOptions } from './components'
|
||||
import type { Component, ComponentsOptions } from './components'
|
||||
import { NuxtCompatibility, NuxtCompatibilityIssues } from '..'
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ export interface NuxtHooks {
|
||||
|
||||
// Components
|
||||
'components:dirs': (dirs: ComponentsOptions['dirs']) => HookResult
|
||||
'components:extend': (components: (Component | ComponentsDir | ScanDir)[]) => HookResult
|
||||
'components:extend': (components: Component[]) => HookResult
|
||||
|
||||
// @nuxt/builder
|
||||
'build:before':
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { NuxtHooks } from './hooks'
|
||||
import type { Nuxt, NuxtTemplate } from "./nuxt"
|
||||
import type { Nuxt, NuxtPluginTemplate, NuxtTemplate } from "./nuxt"
|
||||
import type { NuxtCompatibility } from './compatibility'
|
||||
|
||||
export interface ModuleMeta {
|
||||
@ -58,6 +58,9 @@ export interface ModuleContainer {
|
||||
/** Renders given template using lodash template during build into the project buildDir (`.nuxt`).*/
|
||||
addTemplate(template: string | NuxtTemplate): NuxtTemplate
|
||||
|
||||
/** Registers a custom plugin. */
|
||||
addPlugin(template: NuxtPluginTemplate): NuxtPluginTemplate
|
||||
|
||||
/** Registers a custom layout. If its name is 'error' it will override the default error layout. */
|
||||
addLayout(tmpl: NuxtTemplate, name: string): any
|
||||
|
||||
|
@ -34,15 +34,20 @@ export interface NuxtTemplate<Options = Record<string, any>> {
|
||||
/** The target filename once the template is copied into the Nuxt buildDir */
|
||||
filename?: string
|
||||
/** An options object that will be accessible within the template via `<% options %>` */
|
||||
options?: Record<string, any>
|
||||
options?: Options
|
||||
/** The resolved path to the source file to be template */
|
||||
src?: string
|
||||
/** Provided compile option instead of src */
|
||||
getContents?: (data: Record<string, any>) => string | Promise<string>
|
||||
getContents?: (data: Options) => string | Promise<string>
|
||||
/** Write to filesystem */
|
||||
write?: boolean
|
||||
}
|
||||
|
||||
export interface ResolvedNuxtTemplate<Options = Record<string, any>> extends NuxtTemplate<Options> {
|
||||
filename: string
|
||||
dst: string
|
||||
}
|
||||
|
||||
export interface NuxtPlugin {
|
||||
/** @deprecated use mode */
|
||||
ssr?: boolean
|
||||
@ -63,5 +68,5 @@ export interface NuxtApp {
|
||||
configs: string[]
|
||||
}
|
||||
|
||||
type _TemplatePlugin = Omit<NuxtPlugin, 'src'> & NuxtTemplate
|
||||
export interface NuxtPluginTemplate extends _TemplatePlugin { }
|
||||
type _TemplatePlugin<Options> = Omit<NuxtPlugin, 'src'> & NuxtTemplate<Options>
|
||||
export interface NuxtPluginTemplate<Options = Record<string, any>> extends _TemplatePlugin<Options> { }
|
||||
|
Loading…
Reference in New Issue
Block a user