refactor(nuxt): prefer logical assignment operators (#31004)

This commit is contained in:
Alex Liu 2025-02-16 21:31:49 +08:00 committed by Daniel Roe
parent 543a8e6e18
commit 6202f374c6
No known key found for this signature in database
GPG Key ID: CBC814C393D93268
35 changed files with 73 additions and 110 deletions

View File

@ -39,10 +39,8 @@ function captureStackTrace () {
continue
}
for (const key of ['line', 'column']) {
if (parsed[key]) {
// @ts-expect-error
parsed[key] = Number(parsed[key])
}
parsed[key] &&= Number(parsed[key])
}
trace.push(parsed)
}

View File

@ -48,6 +48,7 @@ export default createConfigForNuxt({
rules: {
'curly': ['error', 'all'], // Including if blocks with a single statement
'dot-notation': 'error',
'logical-assignment-operators': ['error', 'always', { enforceForIfStatements: true }],
'no-console': ['warn', { allow: ['warn', 'error', 'debug'] }],
'no-lonely-if': 'error', // No single if in an "else" block
'no-useless-rename': 'error',

View File

@ -34,7 +34,7 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
delete (globalThis as any).defineNuxtConfig
// Fill config
nuxtConfig.rootDir = nuxtConfig.rootDir || cwd
nuxtConfig.rootDir ||= cwd
nuxtConfig._nuxtConfigFile = configFile
nuxtConfig._nuxtConfigFiles = [configFile]
nuxtConfig.alias ||= {}
@ -64,7 +64,7 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
for (const layer of layers) {
// Resolve `rootDir` & `srcDir` of layers
layer.config ||= {}
layer.config.rootDir = layer.config.rootDir ?? layer.cwd!
layer.config.rootDir ??= layer.cwd!
// Only process/resolve layers once
if (processedLayers.has(layer.config.rootDir)) { continue }

View File

@ -72,9 +72,7 @@ export async function findPath (paths: string | string[], opts?: ResolvePathOpti
* Resolve path aliases respecting Nuxt alias options
*/
export function resolveAlias (path: string, alias?: Record<string, string>): string {
if (!alias) {
alias = tryUseNuxt()?.options.alias || {}
}
alias ||= tryUseNuxt()?.options.alias || {}
return _resolveAlias(path, alias)
}

View File

@ -105,9 +105,7 @@ export function normalizeTemplate<T> (template: NuxtTemplate<T> | string, buildD
}
// Resolve dst
if (!template.dst) {
template.dst = resolve(buildDir ?? useNuxt().options.buildDir, template.filename)
}
template.dst ||= resolve(buildDir ?? useNuxt().options.buildDir, template.filename)
return template as ResolvedNuxtTemplate<T>
}

View File

@ -59,9 +59,9 @@ export function createClientOnly<T extends ComponentOptions> (component: T) {
}
return elToStaticVNode(ctx._.vnode.el, STATIC_DIV)
}
} else if (clone.template) {
} else {
// handle runtime-compiler template
clone.template = `
clone.template &&= `
<template v-if="mounted$">${component.template}</template>
<template v-else>${STATIC_DIV}</template>
`

View File

@ -197,12 +197,10 @@ export default defineComponent({
}
async function fetchComponent (force = false) {
nuxtApp[pKey] = nuxtApp[pKey] || {}
if (!nuxtApp[pKey][uid.value]) {
nuxtApp[pKey][uid.value] = _fetchComponent(force).finally(() => {
nuxtApp[pKey] ||= {}
nuxtApp[pKey][uid.value] ||= _fetchComponent(force).finally(() => {
delete nuxtApp[pKey]![uid.value]
})
}
try {
const res: NuxtIslandResponse = await nuxtApp[pKey][uid.value]

View File

@ -506,15 +506,13 @@ function useObserver (): { observe: ObserveFn } | undefined {
const callbacks = new Map<Element, CallbackFn>()
const observe: ObserveFn = (element, callback) => {
if (!observer) {
observer = new IntersectionObserver((entries) => {
observer ||= new IntersectionObserver((entries) => {
for (const entry of entries) {
const callback = callbacks.get(entry.target)
const isVisible = entry.isIntersecting || entry.intersectionRatio > 0
if (isVisible && callback) { callback() }
}
})
}
callbacks.set(element, callback)
observer.observe(element)
return () => {

View File

@ -240,14 +240,14 @@ export function useAsyncData<
const getDefaultCachedData = () => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key]
// Apply defaults
options.server = options.server ?? true
options.default = options.default ?? (getDefault as () => DefaultT)
options.getCachedData = options.getCachedData ?? getDefaultCachedData
options.server ??= true
options.default ??= getDefault as () => DefaultT
options.getCachedData ??= getDefaultCachedData
options.lazy = options.lazy ?? false
options.immediate = options.immediate ?? true
options.deep = options.deep ?? asyncDataDefaults.deep
options.dedupe = options.dedupe ?? 'cancel'
options.lazy ??= false
options.immediate ??= true
options.deep ??= asyncDataDefaults.deep
options.dedupe ??= 'cancel'
if (import.meta.dev && typeof options.dedupe === 'boolean') {
console.warn('[nuxt] `boolean` values are deprecated for the `dedupe` option of `useAsyncData` and will be removed in the future. Use \'cancel\' or \'defer\' instead.')

View File

@ -34,7 +34,7 @@ export const showError = <DataT = unknown>(
nuxtApp.hooks.callHook('app:error', nuxtError)
}
error.value = error.value || nuxtError
error.value ||= nuxtError
} catch {
throw nuxtError
}

View File

@ -170,9 +170,9 @@ export function useLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}):
const nuxtApp = useNuxtApp()
// Initialise global loading indicator if it doesn't exist already
const indicator = nuxtApp._loadingIndicator = nuxtApp._loadingIndicator || createLoadingIndicator(opts)
const indicator = nuxtApp._loadingIndicator ||= createLoadingIndicator(opts)
if (import.meta.client && getCurrentScope()) {
nuxtApp._loadingIndicatorDeps = nuxtApp._loadingIndicatorDeps || 0
nuxtApp._loadingIndicatorDeps ||= 0
nuxtApp._loadingIndicatorDeps++
onScopeDispose(() => {
nuxtApp._loadingIndicatorDeps!--

View File

@ -38,7 +38,7 @@ export async function callOnce (...args: any): Promise<void> {
}
nuxtApp._once ||= {}
nuxtApp._once[_key] = nuxtApp._once[_key] || fn() || true
nuxtApp._once[_key] ||= fn() || true
await nuxtApp._once[_key]
nuxtApp.payload.once.add(_key)
delete nuxtApp._once[_key]

View File

@ -21,7 +21,7 @@ export async function loadPayload (url: string, opts: LoadPayloadOptions = {}):
if (import.meta.server || !payloadExtraction) { return null }
const payloadURL = await _getPayloadURL(url, opts)
const nuxtApp = useNuxtApp()
const cache = nuxtApp._payloadCache = nuxtApp._payloadCache || {}
const cache = nuxtApp._payloadCache ||= {}
if (payloadURL in cache) {
return cache[payloadURL] || null
}

View File

@ -49,10 +49,10 @@ export async function preloadRouteComponents (to: RouteLocationRaw, router: Rout
const { path, matched } = router.resolve(to)
if (!matched.length) { return }
if (!router._routePreloaded) { router._routePreloaded = new Set() }
router._routePreloaded ||= new Set()
if (router._routePreloaded.has(path)) { return }
const promises = router._preloadPromises = router._preloadPromises || []
const promises = router._preloadPromises ||= []
if (promises.length > 4) {
// Defer adding new preload requests until the existing ones have resolved

View File

@ -69,12 +69,12 @@ export function useRouteAnnouncer (opts: Partial<NuxtRouteAnnouncerOpts> = {}):
const nuxtApp = useNuxtApp()
// Initialise global route announcer if it doesn't exist already
const announcer = nuxtApp._routeAnnouncer = nuxtApp._routeAnnouncer || createRouteAnnouncer(opts)
const announcer = nuxtApp._routeAnnouncer ||= createRouteAnnouncer(opts)
if (opts.politeness !== announcer.politeness.value) {
announcer.politeness.value = opts.politeness || 'polite'
}
if (import.meta.client && getCurrentScope()) {
nuxtApp._routeAnnouncerDeps = nuxtApp._routeAnnouncerDeps || 0
nuxtApp._routeAnnouncerDeps ||= 0
nuxtApp._routeAnnouncerDeps++
onScopeDispose(() => {
nuxtApp._routeAnnouncerDeps!--

View File

@ -117,9 +117,7 @@ export interface NavigateToOptions {
const URL_QUOTE_RE = /"/g
/** @since 3.0.0 */
export const navigateTo = (to: RouteLocationRaw | undefined | null, options?: NavigateToOptions): Promise<void | NavigationFailure | false> | false | void | RouteLocationRaw => {
if (!to) {
to = '/'
}
to ||= '/'
const toPath = typeof to === 'string' ? to : 'path' in to ? resolveRouteObject(to) : useRouter().resolve(to).href

View File

@ -38,7 +38,7 @@ function deepAssign (obj: any, newObj: any) {
const val = newObj[key]
if (isPojoOrArray(val)) {
const defaultVal = Array.isArray(val) ? [] : {}
obj[key] = obj[key] || defaultVal
obj[key] ||= defaultVal
deepAssign(obj[key], val)
} else {
obj[key] = val
@ -48,9 +48,7 @@ function deepAssign (obj: any, newObj: any) {
export function useAppConfig (): AppConfig {
const nuxtApp = useNuxtApp()
if (!nuxtApp._appConfig) {
nuxtApp._appConfig = (import.meta.server ? klona(__appConfig) : reactive(__appConfig)) as AppConfig
}
nuxtApp._appConfig ||= (import.meta.server ? klona(__appConfig) : reactive(__appConfig)) as AppConfig
return nuxtApp._appConfig
}

View File

@ -32,7 +32,7 @@ if (import.meta.server) {
await nuxt.hooks.callHook('app:created', vueApp)
} catch (error) {
await nuxt.hooks.callHook('app:error', error)
nuxt.payload.error = nuxt.payload.error || createError(error as any)
nuxt.payload.error ||= createError(error as any)
}
if (ssrContext?._renderResponse) { throw new Error('skipping render') }
@ -63,7 +63,7 @@ if (import.meta.client) {
async function handleVueError (error: any) {
await nuxt.callHook('app:error', error)
nuxt.payload.error = nuxt.payload.error || createError(error as any)
nuxt.payload.error ||= createError(error as any)
}
vueApp.config.errorHandler = handleVueError

View File

@ -383,7 +383,7 @@ export function createNuxtApp (options: CreateOptions) {
}
})
}
window.useNuxtApp = window.useNuxtApp || useNuxtApp
window.useNuxtApp ||= useNuxtApp
// Log errors captured when running plugins, in the `app:created` and `app:beforeMount` hooks
// as well as when mounting the app.

View File

@ -21,7 +21,7 @@ if (componentIslands) {
revivers.push(['Island', ({ key, params, result }: any) => {
const nuxtApp = useNuxtApp()
if (!nuxtApp.isHydrating) {
nuxtApp.payload.data[key] = nuxtApp.payload.data[key] || $fetch(`/__nuxt_island/${key}.json`, {
nuxtApp.payload.data[key] ||= $fetch(`/__nuxt_island/${key}.json`, {
responseType: 'json',
...params ? { params } : {},
}).then((r) => {

View File

@ -230,7 +230,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
nuxtApp._route = route
// Handle middleware
nuxtApp._middleware = nuxtApp._middleware || {
nuxtApp._middleware ||= {
global: [],
named: {},
}

View File

@ -34,9 +34,9 @@ function pageToClientOnly<T extends ComponentOptions> (component: T) {
clone.render = (ctx: any, cache: any, $props: any, $setup: any, $data: any, $options: any) => ($setup.mounted$ ?? ctx.mounted$)
? h(component.render?.bind(ctx)(ctx, cache, $props, $setup, $data, $options))
: h('div')
} else if (clone.template) {
} else {
// handle runtime-compiler template
clone.template = `
clone.template &&= `
<template v-if="mounted$">${component.template}</template>
<template v-else><div></div></template>
`

View File

@ -138,29 +138,21 @@ async function futureCompileTemplate<T> (template: NuxtTemplate<T>, ctx: { nuxt:
export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
// Resolve main (app.vue)
if (!app.mainComponent) {
app.mainComponent = await findPath(
app.mainComponent ||= await findPath(
nuxt.options._layers.flatMap(layer => [
join(layer.config.srcDir, 'App'),
join(layer.config.srcDir, 'app'),
]),
)
}
if (!app.mainComponent) {
app.mainComponent = resolve(nuxt.options.appDir, 'components/welcome.vue')
}
app.mainComponent ||= resolve(nuxt.options.appDir, 'components/welcome.vue')
// Resolve root component
if (!app.rootComponent) {
app.rootComponent = await findPath(['~/app.root', resolve(nuxt.options.appDir, 'components/nuxt-root.vue')])
}
app.rootComponent ||= await findPath(['~/app.root', resolve(nuxt.options.appDir, 'components/nuxt-root.vue')])
// Resolve error component
if (!app.errorComponent) {
app.errorComponent = (await findPath(
app.errorComponent ||= (await findPath(
nuxt.options._layers.map(layer => join(layer.config.srcDir, 'error')),
)) ?? resolve(nuxt.options.appDir, 'components/nuxt-error-page.vue')
}
// Resolve layouts/ from all config layers
const layerConfigs = nuxt.options._layers.map(layer => layer.config)
@ -176,7 +168,7 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
logger.warn(`No layout name could be resolved for \`~/${relative(nuxt.options.srcDir, file)}\`. Bear in mind that \`index\` is ignored for the purpose of creating a layout name.`)
continue
}
app.layouts[name] = app.layouts[name] || { name, file }
app.layouts[name] ||= { name, file }
}
}

View File

@ -941,7 +941,7 @@ function createPortalProperties (sourceValue: any, options: NuxtOptions, paths:
while (segments.length) {
const key = segments.shift()!
parent = parent[key] || (parent[key] = {})
parent = parent[key] ||= {}
}
delete parent[key]

View File

@ -70,7 +70,7 @@ export async function extractMetadata (code: string, loader = 'ts' as 'ts' | 'ts
meta = defu(extractMetaFromObject(plugin.properties), meta)
}
meta.order = meta.order || orderMap[meta.enforce || 'default'] || orderMap.default
meta.order ||= orderMap[meta.enforce || 'default'] || orderMap.default
delete meta.enforce
})
metaCache[code] = meta

View File

@ -169,7 +169,7 @@ const getSPARenderer = lazyCachedFunction(async () => {
const renderToString = (ssrContext: NuxtSSRContext) => {
const config = useRuntimeConfig(ssrContext.event)
ssrContext.modules = ssrContext.modules || new Set<string>()
ssrContext.modules ||= new Set<string>()
ssrContext.payload.serverRendered = false
ssrContext.config = {
public: config.public,

View File

@ -135,7 +135,7 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
fileFilter: file => !isIgnored(file),
})
for (const i of scannedImports) {
i.priority = i.priority || priorities.find(([dir]) => i.from.startsWith(dir))?.[1]
i.priority ||= priorities.find(([dir]) => i.from.startsWith(dir))?.[1]
}
imports.push(...scannedImports)
}

View File

@ -264,9 +264,7 @@ export default defineNuxtModule({
}
nuxt.hooks.hookOnce('app:templates', async (app) => {
if (!app.pages) {
app.pages = await resolvePagesRoutes(nuxt)
}
app.pages ||= await resolvePagesRoutes(nuxt)
})
nuxt.hook('builder:watch', async (event, relativePath) => {

View File

@ -29,9 +29,7 @@ export const RouteInjectionPlugin = (nuxt: Nuxt) => createUnplugin(() => {
const start = match.index!
const end = start + match[0].length
s.overwrite(start, end, replacement)
if (!replaced) {
replaced = true
}
replaced ||= true
}
}

View File

@ -130,7 +130,7 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
nuxtApp._route = shallowReactive(route)
nuxtApp._middleware = nuxtApp._middleware || {
nuxtApp._middleware ||= {
global: [],
named: {},
}

View File

@ -41,13 +41,9 @@ export async function writeManifest (ctx: ViteBuildContext, css: string[] = [])
const BASE_RE = new RegExp(`^${escapeRE(buildAssetsDir)}`)
for (const entry of manifestEntries) {
if (entry.file) {
entry.file = entry.file.replace(BASE_RE, '')
}
entry.file &&= entry.file.replace(BASE_RE, '')
for (const item of ['css', 'assets'] as const) {
if (entry[item]) {
entry[item] = entry[item].map((i: string) => i.replace(BASE_RE, ''))
}
entry[item] &&= entry[item].map((i: string) => i.replace(BASE_RE, ''))
}
}

View File

@ -104,9 +104,7 @@ export default class VueSSRClientPlugin {
if (Array.isArray(m.modules)) {
for (const concatenatedModule of m.modules) {
const id = hash(concatenatedModule.identifier!.replace(/\s\w+$/, ''))
if (!webpackManifest.modules[id]) {
webpackManifest.modules[id] = files
}
webpackManifest.modules[id] ||= files
}
}

View File

@ -92,7 +92,7 @@ function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any)
if (ctx.isServer) {
// https://webpack.js.org/loaders/css-loader/#exportonlylocals
if (cssLoader.options.modules) {
cssLoader.options.modules.exportOnlyLocals = cssLoader.options.modules.exportOnlyLocals ?? true
cssLoader.options.modules.exportOnlyLocals ??= true
}
return [cssLoader]
}

View File

@ -27,7 +27,7 @@ export async function loadPackage (dir: string) {
const dep: Dep = { name: e[0], range: e[1] as string, type }
delete data[type][dep.name]
const updated = reviver(dep) || dep
data[updated.type] = data[updated.type] || {}
data[updated.type] ||= {}
data[updated.type][updated.name] = updated.range
}
}

View File

@ -2408,9 +2408,7 @@ describe('component islands', () => {
for (const key in result.head) {
if (key === 'link') {
result.head[key] = result.head[key]?.map((h) => {
if (h.href) {
h.href = resolveUnrefHeadInput(h.href).replace(fixtureDir, '/<rootDir>').replaceAll('//', '/')
}
h.href &&= resolveUnrefHeadInput(h.href).replace(fixtureDir, '/<rootDir>').replaceAll('//', '/')
return h
})
}
@ -2803,16 +2801,12 @@ function normaliseIslandResult (result: NuxtIslandResponse) {
if (result.head.style) {
for (const style of result.head.style) {
if (typeof style !== 'string') {
if (style.innerHTML) {
style.innerHTML =
style.innerHTML &&=
(style.innerHTML as string)
.replace(/data-v-[a-z0-9]+/g, 'data-v-xxxxx')
// Vite 6 enables CSS minify by default for SSR
.replace(/blue/, '#00f')
}
if (style.key) {
style.key = style.key.replace(/-[a-z0-9]+$/i, '')
}
style.key &&= style.key.replace(/-[a-z0-9]+$/i, '')
}
}
}