8000 perf: refactor Array.includes checks to use Sets (#32133) · nuxt/nuxt@d74a40e · GitHub
[go: up one dir, main page]

Skip to content

Commit d74a40e

Browse files
authored
perf: refactor Array.includes checks to use Sets (#32133)
1 parent fa3c208 commit d74a40e

File tree

21 files changed

+102
-75
lines changed

21 files changed

+102
-75
lines changed

packages/kit/src/loader/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
7373

7474
const _layers: ConfigLayer<NuxtConfig, ConfigLayerMeta>[] = []
7575
const processedLayers = new Set<string>()
76+
const localRelativePaths = new Set(localLayers)
7677
for (const layer of layers) {
7778
// Resolve `rootDir` & `srcDir` of layers
7879
layer.config ||= {}
@@ -89,7 +90,7 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
8990
if (!layer.configFile || layer.configFile.endsWith('.nuxtrc')) { continue }
9091

9192
// Add layer name for local layers
92-
if (layer.cwd && cwd && localLayers.includes(relative(cwd, layer.cwd))) {
93+
if (layer.cwd && cwd && localRelativePaths.has(relative(cwd, layer.cwd))) {
9394
layer.meta ||= {}
9495
layer.meta.name ||= basename(layer.cwd)
9596
}

packages/kit/src/resolve.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ async function _resolvePathGranularly (path: string, opts: ResolvePathOptions =
220220
}
221221

222222
async function existsSensitive (path: string) {
223-
const dirFiles = await fsp.readdir(dirname(path)).catch(() => null)
224-
return dirFiles && dirFiles.includes(basename(path))
223+
const dirFiles = new Set(await fsp.readdir(dirname(path)).catch(() => []))
224+
return dirFiles.has(basename(path))
225225
}
226226

227227
function existsInVFS (path: string, nuxt = tryUseNuxt()) {

packages/nuxt/src/app/components/nuxt-island.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,10 @@ export default defineComponent({
159159
}
160160

161161
const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] || getId())
162-
const availableSlots = computed(() => [...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1]))
162+
163+
const currentSlots = new Set(Object.keys(slots))
164+
const availableSlots = computed(() => new Set([...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1])))
163165
const html = computed(() => {
164-
const currentSlots = Object.keys(slots)
165166
let html = ssrHTML.value
166167

167168
if (props.scopeId) {
@@ -178,7 +179,7 @@ export default defineComponent({
178179

179180
if (payloads.slots) {
180181
return html.replaceAll(SLOT_FALLBACK_RE, (full, slotName) => {
181-
if (!currentSlots.includes(slotName)) {
182+
if (!currentSlots.has(slotName)) {
182183
return full + (payloads.slots?.[slotName]?.fallback || '')
183184
}
184185
return full
@@ -305,7 +306,7 @@ export default defineComponent({
305306

306307
if (uid.value && html.value && (import.meta.server || props.lazy ? canTeleport : (mounted.value || instance.vnode?.el))) {
307308
for (const slot in slots) {
308-
if (availableSlots.value.includes(slot)) {
309+
if (availableSlots.value.has(slot)) {
309310
teleports.push(createVNode(Teleport,
310311
// use different selectors for even and odd teleportKey to force trigger the teleport
311312
{ to: import.meta.client ? `${isKeyOdd ? 'div' : ''}[data-island-uid="${uid.value}"][data-island-slot="${slot}"]` : `uid=${uid.value};slot=${slot}` },

packages/nuxt/src/app/nuxt.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,20 +418,20 @@ export async function applyPlugin (nuxtApp: NuxtApp, plugin: Plugin & ObjectPlug
418418

419419
/** @since 3.0.0 */
420420
export async function applyPlugins (nuxtApp: NuxtApp, plugins: Array<Plugin & ObjectPlugin<any>>) {
421-
const resolvedPlugins: string[] = []
421+
const resolvedPlugins: Set<string> = new Set()
422422
const unresolvedPlugins: [Set<string>, Plugin & ObjectPlugin<any>][] = []
423423
const parallels: Promise<any>[] = []
424424
const errors: Error[] = []
425425
let promiseDepth = 0
426426

427427
async function executePlugin (plugin: Plugin & ObjectPlugin<any>) {
428-
const unresolvedPluginsForThisPlugin = plugin.dependsOn?.filter(name => plugins.some(p => p._name === name) && !resolvedPlugins.includes(name)) ?? []
428+
const unresolvedPluginsForThisPlugin = plugin.dependsOn?.filter(name => plugins.some(p => p._name === name) && !resolvedPlugins.has(name)) ?? []
429429
if (unresolvedPluginsForThisPlugin.length > 0) {
430430
unresolvedPlugins.push([new Set(unresolvedPluginsForThisPlugin), plugin])
431431
} else {
432432
const promise = applyPlugin(nuxtApp, plugin).then(async () => {
433433
if (plugin._name) {
434-
resolvedPlugins.push(plugin._name)
434+
resolvedPlugins.add(plugin._name)
435435
await Promise.all(unresolvedPlugins.map(async ([dependsOn, unexecutedPlugin]) => {
436436
if (dependsOn.has(plugin._name!)) {
437437
dependsOn.delete(plugin._name!)

packages/nuxt/src/app/plugins/cross-origin-prefetch.client.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ref } from 'vue'
22
import { defineNuxtPlugin } from '../nuxt'
33
import { useHead } from '../composables/head'
44

5-
const SUPPORTED_PROTOCOLS = ['http:', 'https:']
5+
const SUPPORTED_PROTOCOLS = new Set(['http:', 'https:'])
66

77
export default defineNuxtPlugin({
88
name: 'nuxt:cross-origin-prefetch',
@@ -27,11 +27,12 @@ export default defineNuxtPlugin({
2727
script: [generateRules()],
2828
})
2929
nuxtApp.hook('link:prefetch', (url) => {
30-
if (SUPPORTED_PROTOCOLS.some(p => url.startsWith(p)) && SUPPORTED_PROTOCOLS.includes(new URL(url).protocol)) {
31-
externalURLs.value.add(url)
32-
head?.patch({
33-
script: [generateRules()],
34-
})
30+
for (const protocol of SUPPORTED_PROTOCOLS) {
31+
if (url.startsWith(protocol) && SUPPORTED_PROTOCOLS.has(new URL(url).protocol)) {
32+
externalURLs.value.add(url)
33+
head?.patch({ script: [generateRules()] })
34+
return
35+
}
3536
}
3637
})
3738
},

packages/nuxt/src/components/module.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,19 +144,25 @@ export default defineNuxtModule<ComponentsOptions>({
144144

145145
// Do not prefetch global components chunks
146146
nuxt.hook('build:manifest', (manifest) => {
147-
const sourceFiles = getComponents().filter(c => c.global).map(c => relative(nuxt.options.srcDir, c.filePath))
147+
const sourceFiles = new Set<string>()
148+
for (const c of getComponents()) {
149+
if (c.global) {
150+
sourceFiles.add(relative(nuxt.options.srcDir, c.filePath))
151+
}
152+
}
148153

149154
for (const chunk of Object.values(manifest)) {
150155
if (chunk.isEntry) {
151-
chunk.dynamicImports =
152-
chunk.dynamicImports?.filter(i => !sourceFiles.includes(i))
156+
chunk.dynamicImports = chunk.dynamicImports?.filter(i => !sourceFiles.has(i))
153157
}
154158
}
155159
})
156160

157161
// Restart dev server when component directories are added/removed
162+
const restartEvents = new Set(['addDir', 'unlinkDir'])
163+
// const restartPaths
158164
nuxt.hook('builder:watch', (event, relativePath) => {
159-
if (!['addDir', 'unlinkDir'].includes(event)) {
165+
if (!restartEvents.has(event)) {
160166
return
161167
}
162168

packages/nuxt/src/components/plugins/loader.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ export const LoaderPlugin = (options: LoaderOptions) => createUnplugin(() => {
170170
function findComponent (components: Component[], name: string, mode: LoaderOptions['mode']) {
171171
const id = pascalCase(name).replace(QUOTE_RE, '')
172172
// Prefer exact match
173-
const component = components.find(component => id === component.pascalName && ['all', mode, undefined].includes(component.mode))
173+
const validModes = new Set(['all', mode, undefined])
174+
const component = components.find(component => id === component.pascalName && validModes.has(component.mode))
174175
if (component) { return component }
175176

176177
const otherModeComponent = components.find(component => id === component.pascalName)

packages/nuxt/src/components/plugins/transform.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ export function TransformPlugin (nuxt: Nuxt, options: TransformPluginOptions) {
3131

3232
function getComponentsImports (): Import[] {
3333
const components = options.getComponents(options.mode)
34+
const clientOrServerModes = new Set(['client', 'server'])
3435
return components.flatMap((c): Import[] => {
3536
const withMode = (mode: string | undefined) => mode
3637
? `${c.filePath}${c.filePath.includes('?') ? '&' : '?'}nuxt_component=${mode}&nuxt_component_name=${c.pascalName}&nuxt_component_export=${c.export || 'default'}`
3738
: c.filePath
3839

39-
const mode = !c._raw && c.mode && ['client', 'server'].includes(c.mode) ? c.mode : undefined
40+
const mode = !c._raw && c.mode && clientOrServerModes.has(c.mode) ? c.mode : undefined
4041

4142
return [
4243
{

packages/nuxt/src/components/scan.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,18 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
4141

4242
// Check if the directory exists (globby will otherwise read it case insensitively on MacOS)
4343
if (files.length) {
44-
const siblings = await readdir(dirname(dir.path)).catch(() => [] as string[])
45-
44+
const siblings = new Set(await readdir(dirname(dir.path)).catch(() => [] as string[]))
4645
const directory = basename(dir.path)
47-
if (!siblings.includes(directory)) {
46+
if (!siblings.has(directory)) {
4847
const directoryLowerCase = directory.toLowerCase()
49-
const caseCorrected = siblings.find(sibling => sibling.toLowerCase() === directoryLowerCase)
50-
if (caseCorrected) {
51-
const nuxt = useNuxt()
52-
const original = relative(nuxt.options.srcDir, dir.path)
53-
const corrected = relative(nuxt.options.srcDir, join(dirname(dir.path), caseCorrected))
54-
logger.warn(`Components not scanned from \`~/${corrected}\`. Did you mean to name the directory \`~/${original}\` instead?`)
55-
continue
48+
for (const sibling of siblings) {
49+
if (sibling.toLowerCase() === directoryLowerCase) {
50+
const nuxt = useNuxt()
51+
const original = relative(nuxt.options.srcDir, dir.path)
52+
const corrected = relative(nuxt.options.srcDir, join(dirname(dir.path), sibling))
53+
logger.warn(`Components not scanned from \`~/${corrected}\`. Did you mean to name the directory \`~/${original}\` instead?`)
54+
break
55+
}
5656
}
5757
}
5858
}
@@ -145,7 +145,8 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
145145
continue
146146
}
147147

148-
const existingComponent = components.find(c => c.pascalName === component.pascalName && ['all', component.mode].includes(c.mode))
148+
const validModes = new Set(['all', component.mode])
149+
const existingComponent = components.find(c => c.pascalName === component.pascalName && validModes.has(c.mode))
149150
// Ignore component if component is already defined (with same mode)
150151
if (existingComponent) {
151152
const existingPriority = existingComponent.priority ?? 0

packages/nuxt/src/core/app.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ export function createApp (nuxt: Nuxt, options: Partial<NuxtApp> = {}): NuxtApp
2121
} as unknown as NuxtApp) as NuxtApp
2222
}
2323

24-
const postTemplates = [
24+
const postTemplates = new Set([
2525
defaultTemplates.clientPluginTemplate.filename,
2626
defaultTemplates.serverPluginTemplate.filename,
2727
defaultTemplates.pluginsDeclaration.filename,
28-
]
28+
])
2929

3030
export async function generateApp (nuxt: Nuxt, app: NuxtApp, options: { filter?: (template: ResolvedNuxtTemplate<any>) => boolean } = {}) {
3131
// Resolve app
@@ -49,7 +49,7 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp, options: { filter?:
4949

5050
for (const template of app.templates as Array<ResolvedNuxtTemplate<any>>) {
5151
if (options.filter && !options.filter(template)) { continue }
52-
const key = template.filename && postTemplates.includes(template.filename) ? 'post' : 'pre'
52+
const key = template.filename && postTemplates.has(template.filename) ? 'post' : 'pre'
5353
filteredTemplates[key].push(template)
5454
}
5555

@@ -279,11 +279,11 @@ export async function annotatePlugins (nuxt: Nuxt, plugins: NuxtPlugin[]) {
279279

280280
export function checkForCircularDependencies (_plugins: Array<NuxtPlugin & Omit<PluginMeta, 'enforce'>>) {
281281
const deps: Record<string, string[]> = Object.create(null)
282-
const pluginNameSet = new Set(_plugins.map(plugin = 7F47 > plugin.name))
282+
const pluginNames = new Set(_plugins.map(plugin => plugin.name))
283283
for (const plugin of _plugins) {
284284
// Make sure dependency plugins are registered
285-
if (plugin.dependsOn && plugin.dependsOn.some(name => !pluginNameSet.has(name))) {
286-
console.error(`Plugin \`${plugin.name}\` depends on \`${plugin.dependsOn.filter(name => !pluginNameSet.has(name)).join(', ')}\` but they are not registered.`)
285+
if (plugin.dependsOn && plugin.dependsOn.some(name => !pluginNames.has(name))) {
286+
console.error(`Plugin \`${plugin.name}\` depends on \`${plugin.dependsOn.filter(name => !pluginNames.has(name)).join(', ')}\` but they are not registered.`)
287287
}
288288
// Make graph to detect circular dependencies
289289
if (plugin.name) {

0 commit comments

Comments
 (0)
0