feat(kit,nuxt,vite,webpack): add toArray util (#24857)

This commit is contained in:
Damian Głowala 2023-12-23 15:22:58 +01:00 committed by GitHub
parent cf1a698ed8
commit a2ef3091e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 70 additions and 60 deletions

View File

@ -1,6 +1,7 @@
import type { Configuration as WebpackConfig, WebpackPluginInstance } from 'webpack'
import type { UserConfig as ViteConfig, Plugin as VitePlugin } from 'vite'
import { useNuxt } from './context'
import { toArray } from './utils'
export interface ExtendConfigOptions {
/**
@ -108,11 +109,7 @@ export function addWebpackPlugin (pluginOrGetter: WebpackPluginInstance | Webpac
const plugin = typeof pluginOrGetter === 'function' ? pluginOrGetter() : pluginOrGetter
config.plugins = config.plugins || []
if (Array.isArray(plugin)) {
config.plugins[method](...plugin)
} else {
config.plugins[method](plugin)
}
config.plugins[method](...toArray(plugin))
}, options)
}
@ -125,11 +122,7 @@ export function addVitePlugin (pluginOrGetter: VitePlugin | VitePlugin[] | (() =
const plugin = typeof pluginOrGetter === 'function' ? pluginOrGetter() : pluginOrGetter
config.plugins = config.plugins || []
if (Array.isArray(plugin)) {
config.plugins[method](...plugin)
} else {
config.plugins[method](plugin)
}
config.plugins[method](...toArray(plugin))
}, options)
}

View File

@ -2,12 +2,13 @@ import type { Import } from 'unimport'
import type { ImportPresetWithDeprecation } from '@nuxt/schema'
import { useNuxt } from './context'
import { assertNuxtCompatibility } from './compatibility'
import { toArray } from './utils'
export function addImports (imports: Import | Import[]) {
assertNuxtCompatibility({ bridge: true })
useNuxt().hook('imports:extend', (_imports) => {
_imports.push(...(Array.isArray(imports) ? imports : [imports]))
_imports.push(...toArray(imports))
})
}
@ -15,7 +16,7 @@ export function addImportsDir (dirs: string | string[], opts: { prepend?: boolea
assertNuxtCompatibility({ bridge: true })
useNuxt().hook('imports:dirs', (_dirs: string[]) => {
for (const dir of (Array.isArray(dirs) ? dirs : [dirs])) {
for (const dir of toArray(dirs)) {
_dirs[opts.prepend ? 'unshift' : 'push'](dir)
}
})
@ -24,7 +25,7 @@ export function addImportsSources (presets: ImportPresetWithDeprecation | Import
assertNuxtCompatibility({ bridge: true })
useNuxt().hook('imports:sources', (_presets: ImportPresetWithDeprecation[]) => {
for (const preset of (Array.isArray(presets) ? presets : [presets])) {
for (const preset of toArray(presets)) {
_presets.push(preset)
}
})

View File

@ -5,6 +5,7 @@ import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork'
import type { NuxtTemplate } from '@nuxt/schema'
import { logger } from '../logger'
import { toArray } from '../utils'
/** @deprecated */
// TODO: Remove support for compiling ejs templates in v4
@ -30,10 +31,7 @@ const serialize = (data: any) => JSON.stringify(data, null, 2).replace(/"{(.+)}"
/** @deprecated */
const importSources = (sources: string | string[], { lazy = false } = {}) => {
if (!Array.isArray(sources)) {
sources = [sources]
}
return sources.map((src) => {
return toArray(sources).map((src) => {
if (lazy) {
return `const ${genSafeVariableName(src)} = ${genDynamicImport(src, { comment: `webpackChunkName: ${JSON.stringify(src)}` })}`
}

View File

@ -2,6 +2,7 @@ import type { Nitro, NitroDevEventHandler, NitroEventHandler } from 'nitropack'
import type { Import } from 'unimport'
import { normalize } from 'pathe'
import { useNuxt } from './context'
import { toArray } from './utils'
/**
* normalize handler object
@ -47,10 +48,8 @@ export function addServerPlugin (plugin: string) {
*/
export function addPrerenderRoutes (routes: string | string[]) {
const nuxt = useNuxt()
if (!Array.isArray(routes)) {
routes = [routes]
}
routes = routes.filter(Boolean)
routes = toArray(routes).filter(Boolean)
if (!routes.length) {
return
}
@ -90,11 +89,8 @@ export function addServerImports (imports: Import[]) {
const nuxt = useNuxt()
nuxt.hook('nitro:config', (config) => {
config.imports = config.imports || {}
if (Array.isArray(config.imports.imports)) {
config.imports.imports.push(...imports)
} else {
config.imports.imports = [config.imports.imports, ...imports]
}
config.imports.imports = config.imports.imports || []
config.imports.imports.push(...imports)
})
}
@ -103,7 +99,7 @@ export function addServerImports (imports: Import[]) {
*/
export function addServerImportsDir (dirs: string | string[], opts: { prepend?: boolean } = {}) {
const nuxt = useNuxt()
const _dirs = Array.isArray(dirs) ? dirs : [dirs]
const _dirs = toArray(dirs)
nuxt.hook('nitro:config', (config) => {
config.imports = config.imports || {}
config.imports.dirs = config.imports.dirs || []
@ -120,7 +116,7 @@ export function addServerScanDir (dirs: string | string[], opts: { prepend?: boo
nuxt.hook('nitro:config', (config) => {
config.scanDirs = config.scanDirs || []
for (const dir of (Array.isArray(dirs) ? dirs : [dirs])) {
for (const dir of toArray(dirs)) {
config.scanDirs[opts.prepend ? 'unshift' : 'push'](dir)
}
})

View File

@ -4,6 +4,7 @@ import { defu } from 'defu'
import { useNuxt } from './context'
import { isNuxt2 } from './compatibility'
import { logger } from './logger'
import { toArray } from './utils'
export function extendPages (cb: NuxtHooks['pages:extend']) {
const nuxt = useNuxt()
@ -45,7 +46,7 @@ export interface AddRouteMiddlewareOptions {
export function addRouteMiddleware (input: NuxtMiddleware | NuxtMiddleware[], options: AddRouteMiddlewareOptions = {}) {
const nuxt = useNuxt()
const middlewares = Array.isArray(input) ? input : [input]
const middlewares = toArray(input)
nuxt.hook('app:resolve', (app) => {
for (const middleware of middlewares) {
const find = app.middleware.findIndex(item => item.name === middleware.name)

View File

@ -6,6 +6,7 @@ import { resolvePath as _resolvePath } from 'mlly'
import { resolveAlias as _resolveAlias } from 'pathe/utils'
import { tryUseNuxt } from './context'
import { isIgnored } from './ignore'
import { toArray } from './utils'
export interface ResolvePathOptions {
/** Base for resolving paths from. Default is Nuxt rootDir. */
@ -84,10 +85,7 @@ export async function resolvePath (path: string, opts: ResolvePathOptions = {}):
* Try to resolve first existing file in paths
*/
export async function findPath (paths: string | string[], opts?: ResolvePathOptions, pathType: 'file' | 'dir' = 'file'): Promise<string | null> {
if (!Array.isArray(paths)) {
paths = [paths]
}
for (const path of paths) {
for (const path of toArray(paths)) {
const rPath = await resolvePath(path, opts)
if (await existsSensitive(rPath)) {
const _isDir = await isDirectory(rPath)

View File

@ -0,0 +1,3 @@
export function toArray<T> (value: T | T[]): T[] {
return Array.isArray(value) ? value : [value]
}

View File

@ -2,6 +2,7 @@ import { getCurrentInstance, onBeforeMount, onServerPrefetch, onUnmounted, ref,
import type { Ref, WatchSource } from 'vue'
import type { NuxtApp } from '../nuxt'
import { useNuxtApp } from '../nuxt'
import { toArray } from '../utils'
import type { NuxtError} from './error';
import { createError } from './error'
import { onNuxtReady } from './ready'
@ -378,7 +379,7 @@ export async function refreshNuxtData (keys?: string | string[]): Promise<void>
await new Promise<void>(resolve => onNuxtReady(resolve))
const _keys = keys ? Array.isArray(keys) ? keys : [keys] : undefined
const _keys = keys ? toArray(keys) : undefined
await useNuxtApp().hooks.callHookParallel('app:data:refresh', _keys)
}
@ -389,7 +390,7 @@ export function clearNuxtData (keys?: string | string[] | ((key: string) => bool
? _allKeys
: typeof keys === 'function'
? _allKeys.filter(keys)
: Array.isArray(keys) ? keys : [keys]
: toArray(keys)
for (const key of _keys) {
if (key in nuxtApp.payload.data) {

View File

@ -227,8 +227,7 @@ function generateOptionSegments <_ResT, DataT, DefaultT>(opts: UseFetchOptions<_
if (!obj) { continue }
const unwrapped: Record<string, string> = {}
const iterator = Array.isArray(obj) ? obj : Object.entries(obj)
for (const [key, value] of iterator) {
for (const [key, value] of Object.entries(obj)) {
unwrapped[toValue(key)] = toValue(value)
}
segments.push(unwrapped)

View File

@ -1,6 +1,7 @@
import type { Component } from 'vue'
import type { RouteLocationRaw, Router } from '#vue-router'
import { useNuxtApp } from '../nuxt'
import { toArray } from '../utils'
import { useRouter } from './router'
/**
@ -11,7 +12,7 @@ export const preloadComponents = async (components: string | string[]) => {
if (import.meta.server) { return }
const nuxtApp = useNuxtApp()
components = Array.isArray(components) ? components : [components]
components = toArray(components)
await Promise.all(components.map(name => _loadAsyncComponent(nuxtApp.vueApp._context.components[name])))
}

View File

@ -2,6 +2,7 @@ import type { H3Event } from 'h3'
import { setResponseStatus as _setResponseStatus, appendHeader, getRequestHeader, getRequestHeaders } from 'h3'
import type { NuxtApp } from '../nuxt'
import { useNuxtApp } from '../nuxt'
import { toArray } from '../utils'
export function useRequestEvent (nuxtApp: NuxtApp = useNuxtApp()): H3Event {
return nuxtApp.ssrContext?.event as H3Event
@ -44,6 +45,6 @@ export function setResponseStatus (arg1: H3Event | number | undefined, arg2?: nu
export function prerenderRoutes (path: string | string[]) {
if (!import.meta.server || !import.meta.prerender) { return }
const paths = Array.isArray(path) ? path : [path]
const paths = toArray(path)
appendHeader(useRequestEvent(), 'x-nitro-prerender', paths.map(p => encodeURIComponent(p)).join(', '))
}

View File

@ -1,6 +1,7 @@
import { isRef, toRef } from 'vue'
import type { Ref } from 'vue'
import { useNuxtApp } from '../nuxt'
import { toArray } from '../utils'
const useStateKeyPrefix = '$s'
/**
@ -47,7 +48,7 @@ export function clearNuxtState (
? _allKeys
: typeof keys === 'function'
? _allKeys.filter(keys)
: Array.isArray(keys) ? keys : [keys]
: toArray(keys)
for (const _key of _keys) {
const key = useStateKeyPrefix + _key

View File

@ -0,0 +1,3 @@
export function toArray<T> (value: T | T[]): T[] {
return Array.isArray(value) ? value : [value]
}

View File

@ -16,6 +16,7 @@ import type { Nuxt, RuntimeConfig } from 'nuxt/schema'
import { template as defaultSpaLoadingTemplate } from '@nuxt/ui-templates/templates/spa-loading-icon.mjs'
import { version as nuxtVersion } from '../../package.json'
import { distDir } from '../dirs'
import { toArray } from '../utils'
import { ImportProtectionPlugin } from './plugins/import-protection'
export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
@ -333,7 +334,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
// Register nuxt protection patterns
nitroConfig.rollupConfig!.plugins = await nitroConfig.rollupConfig!.plugins || []
nitroConfig.rollupConfig!.plugins = Array.isArray(nitroConfig.rollupConfig!.plugins) ? nitroConfig.rollupConfig!.plugins : [nitroConfig.rollupConfig!.plugins]
nitroConfig.rollupConfig!.plugins = toArray(nitroConfig.rollupConfig!.plugins)
nitroConfig.rollupConfig!.plugins!.push(
ImportProtectionPlugin.rollup({
rootDir: nuxt.options.rootDir,

View File

@ -4,6 +4,7 @@ import { RouterView } from '#vue-router'
import { defu } from 'defu'
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from '#vue-router'
import { toArray } from './utils'
import type { RouterViewSlotProps } from './utils'
import { generateRouteKey, wrapInKeepAlive } from './utils'
import { RouteProvider } from '#app/components/route-provider'
@ -127,14 +128,10 @@ export default defineComponent({
}
})
function _toArray (val: any) {
return Array.isArray(val) ? val : (val ? [val] : [])
}
function _mergeTransitionProps (routeProps: TransitionProps[]): TransitionProps {
const _props: TransitionProps[] = routeProps.map(prop => ({
...prop,
onAfterLeave: _toArray(prop.onAfterLeave)
onAfterLeave: prop.onAfterLeave ? toArray(prop.onAfterLeave) : undefined
}))
return defu(..._props as [TransitionProps, TransitionProps])
}

View File

@ -1,4 +1,5 @@
import { hasProtocol } from 'ufo'
import { toArray } from '../utils'
import { defineNuxtPlugin } from '#app/nuxt'
import { useRouter } from '#app/composables/router'
// @ts-expect-error virtual file
@ -25,8 +26,8 @@ export default defineNuxtPlugin({
if (hasProtocol(url)) { return }
const route = router.resolve(url)
if (!route) { return }
const layout = route?.meta?.layout
let middleware = Array.isArray(route?.meta?.middleware) ? route?.meta?.middleware : [route?.meta?.middleware]
const layout = route.meta.layout
let middleware = toArray(route.meta.middleware)
middleware = middleware.filter(m => typeof m === 'string')
for (const name of middleware) {

View File

@ -13,6 +13,7 @@ import { isEqual, withoutBase } from 'ufo'
import type { PageMeta } from '../composables'
import { toArray } from '../utils'
import type { Plugin, RouteMiddleware } from '#app'
import { defineNuxtPlugin, useRuntimeConfig } from '#app/nuxt'
import { clearError, showError, useError } from '#app/composables/error'
@ -155,12 +156,8 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
for (const component of to.matched) {
const componentMiddleware = component.meta.middleware as MiddlewareDef | MiddlewareDef[]
if (!componentMiddleware) { continue }
if (Array.isArray(componentMiddleware)) {
for (const entry of componentMiddleware) {
middlewareEntries.add(entry)
}
} else {
middlewareEntries.add(componentMiddleware)
for (const entry of toArray(componentMiddleware)) {
middlewareEntries.add(entry)
}
}

View File

@ -21,3 +21,7 @@ export const generateRouteKey = (routeProps: RouterViewSlotProps, override?: str
export const wrapInKeepAlive = (props: any, children: any) => {
return { default: () => import.meta.client && props ? h(KeepAlive, props === true ? {} : props, children) : children }
}
export function toArray<T> (value: T | T[]): T[] {
return Array.isArray(value) ? value : [value]
}

View File

@ -12,6 +12,7 @@ import type { CallExpression, ExpressionStatement, ObjectExpression, Program, Pr
import type { NuxtPage } from 'nuxt/schema'
import { uniqueBy } from '../core/utils'
import { toArray } from '../utils'
enum SegmentParserState {
initial,
@ -325,7 +326,7 @@ export function normalizeRoutes (routes: NuxtPage[], metaImports: Set<string> =
metaImports.add(genImport(`${file}?macro=true`, [{ name: 'default', as: metaImportName }]))
let aliasCode = `${metaImportName}?.alias || []`
const alias = Array.isArray(page.alias) ? page.alias : [page.alias].filter(Boolean)
const alias = toArray(page.alias).filter(Boolean)
if (alias.length) {
aliasCode = `${JSON.stringify(alias)}.concat(${aliasCode})`
}

View File

@ -0,0 +1,3 @@
export function toArray<T> (value: T | T[]): T[] {
return Array.isArray(value) ? value : [value]
}

View File

@ -1,6 +1,7 @@
import type { ExternalsOptions } from 'externality'
import { ExternalsDefaults, isExternal } from 'externality'
import type { ViteDevServer } from 'vite'
import { toArray } from '.'
export function createIsExternal (viteServer: ViteDevServer, rootDir: string, modulesDirs?: string[]) {
const externalOpts: ExternalsOptions = {
@ -8,7 +9,11 @@ export function createIsExternal (viteServer: ViteDevServer, rootDir: string, mo
/virtual:/,
/\.ts$/,
...ExternalsDefaults.inline || [],
...Array.isArray(viteServer.config.ssr.noExternal) ? viteServer.config.ssr.noExternal : []
...(
viteServer.config.ssr.noExternal && viteServer.config.ssr.noExternal !== true
? toArray(viteServer.config.ssr.noExternal)
: []
)
],
external: [
...viteServer.config.ssr.external || [],

View File

@ -24,3 +24,7 @@ export function matchWithStringOrRegex (value: string, matcher: string | RegExp)
return false
}
export function toArray<T> (value: T | T[]): T[] {
return Array.isArray(value) ? value : [value]
}

View File

@ -2,6 +2,7 @@ import type { Configuration } from 'webpack'
import type { Nuxt, NuxtOptions } from '@nuxt/schema'
import { logger } from '@nuxt/kit'
import { cloneDeep } from 'lodash-es'
import { toArray } from './index'
export interface WebpackConfigContext {
nuxt: Nuxt
@ -37,10 +38,7 @@ export function createWebpackConfigContext (nuxt: Nuxt): WebpackConfigContext {
}
export function applyPresets (ctx: WebpackConfigContext, presets: WebpackConfigPresetItem | WebpackConfigPresetItem[]) {
if (!Array.isArray(presets)) {
presets = [presets]
}
for (const preset of presets) {
for (const preset of toArray(presets)) {
if (Array.isArray(preset)) {
preset[0](ctx, preset[1])
} else {

View File

@ -0,0 +1,3 @@
export function toArray<T> (value: T | T[]): T[] {
return Array.isArray(value) ? value : [value]
}