Skip to content

Commit

Permalink
chore: replace micromatch w/ picomatch (#60699)
Browse files Browse the repository at this point in the history
The PR continues from #58038 aiming to reduce the installation size
further, and **improve performance in doing so**.

Most of `micromatch`'s APIs are essentially wrappers/alias of
`picomatch`, supplemented with additional features facilitated by a
transitive dependency `braces`. However, Next.js doesn't use those
"extra features". Switching from `micromatch` to `picomatch` can avoid
introducing the transitive dependency `braces`.

The PR also improves some globs' performance by hoisting.

- `micromatch.makeRe` is just an alias of `picomatch.makeRe`
-
https://github.com/micromatch/micromatch/blob/90dc0cd3e186b8ab4dd05bfc41e2b98f5067a49b/index.js#L387C30-L387C30
- `micromatch.isMatch(str, patterns, options)` equals
`picomatch(patterns, options)(str)`
-
https://github.com/micromatch/micromatch/blob/90dc0cd3e186b8ab4dd05bfc41e2b98f5067a49b/index.js#L123
- `micromatch.matcher` is just an alias of `picomatch`
-
https://github.com/micromatch/micromatch/blob/90dc0cd3e186b8ab4dd05bfc41e2b98f5067a49b/index.js#L104C1-L104C40

---------

Co-authored-by: Sam Ko <sam@vercel.com>
  • Loading branch information
SukkaW and samcx authored Jan 19, 2024
1 parent 4a74492 commit 53a0a0f
Show file tree
Hide file tree
Showing 16 changed files with 87 additions and 80 deletions.
4 changes: 2 additions & 2 deletions packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@
"@types/lodash": "4.14.198",
"@types/lodash.curry": "4.1.6",
"@types/lru-cache": "5.1.0",
"@types/micromatch": "4.0.2",
"@types/path-to-regexp": "1.7.0",
"@types/picomatch": "2.3.3",
"@types/platform": "1.3.4",
"@types/react": "18.2.37",
"@types/react-dom": "18.2.15",
Expand Down Expand Up @@ -250,7 +250,6 @@
"loader-utils3": "npm:loader-utils@3.1.3",
"lodash.curry": "4.1.1",
"lru-cache": "5.1.1",
"micromatch": "4.0.4",
"mini-css-extract-plugin": "2.4.3",
"msw": "1.3.0",
"nanoid": "3.1.32",
Expand All @@ -262,6 +261,7 @@
"p-limit": "3.1.0",
"path-browserify": "1.0.1",
"path-to-regexp": "6.1.0",
"picomatch": "3.0.1",
"platform": "1.3.6",
"postcss-flexbugs-fixes": "5.0.2",
"postcss-modules-extract-imports": "3.0.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/next/src/build/analysis/get-page-static-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Middleware, RouteHas } from '../../lib/load-custom-routes'

import { promises as fs } from 'fs'
import LRUCache from 'next/dist/compiled/lru-cache'
import { matcher } from 'next/dist/compiled/micromatch'
import picomatch from 'next/dist/compiled/picomatch'
import type { ServerRuntime } from 'next/types'
import {
extractExportedConstValue,
Expand Down Expand Up @@ -395,7 +395,7 @@ function getMiddlewareConfig(
: [config.unstable_allowDynamic]
for (const glob of result.unstable_allowDynamicGlobs ?? []) {
try {
matcher(glob)
picomatch(glob)
} catch (err) {
throw new Error(
`${pageFilePath} exported 'config.unstable_allowDynamic' contains invalid pattern '${glob}': ${
Expand Down
41 changes: 25 additions & 16 deletions packages/next/src/build/collect-build-traces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { loadBindings } from './swc'
import { nonNullable } from '../lib/non-nullable'
import * as ciEnvironment from '../telemetry/ci-info'
import debugOriginal from 'next/dist/compiled/debug'
import { isMatch } from 'next/dist/compiled/micromatch'
import picomatch from 'next/dist/compiled/picomatch'
import { defaultOverrides } from '../server/require-hook'
import { nodeFileTrace } from 'next/dist/compiled/@vercel/nft'
import { normalizePagePath } from '../shared/lib/page-path/normalize-page-path'
Expand Down Expand Up @@ -273,22 +273,27 @@ export async function collectBuildTraces({
const additionalIgnores = new Set<string>()

for (const glob of excludeGlobKeys) {
if (isMatch('next-server', glob)) {
if (picomatch(glob)('next-server')) {
outputFileTracingExcludes[glob].forEach((exclude) => {
additionalIgnores.add(exclude)
})
}
}

const makeIgnoreFn = (ignores: string[]) => (pathname: string) => {
if (path.isAbsolute(pathname) && !pathname.startsWith(root)) {
return true
}

return isMatch(pathname, ignores, {
const makeIgnoreFn = (ignores: string[]) => {
// pre compile the ignore globs
const isMatch = picomatch(ignores, {
contains: true,
dot: true,
})

return (pathname: string) => {
if (path.isAbsolute(pathname) && !pathname.startsWith(root)) {
return true
}

return isMatch(pathname)
}
}

const sharedIgnores = [
Expand Down Expand Up @@ -699,15 +704,17 @@ export async function collectBuildTraces({
const combinedIncludes = new Set<string>()
const combinedExcludes = new Set<string>()
for (const curGlob of includeGlobKeys) {
if (isMatch(route, [curGlob], { dot: true, contains: true })) {
const isMatch = picomatch(curGlob, { dot: true, contains: true })
if (isMatch(route)) {
for (const include of outputFileTracingIncludes[curGlob]) {
combinedIncludes.add(include.replace(/\\/g, '/'))
}
}
}

for (const curGlob of excludeGlobKeys) {
if (isMatch(route, [curGlob], { dot: true, contains: true })) {
const isMatch = picomatch(curGlob, { dot: true, contains: true })
if (isMatch(route)) {
for (const exclude of outputFileTracingExcludes[curGlob]) {
combinedExcludes.add(exclude)
}
Expand Down Expand Up @@ -750,13 +757,15 @@ export async function collectBuildTraces({
const resolvedGlobs = [...combinedExcludes].map((exclude) =>
path.join(dir, exclude)
)

// pre compile before forEach
const isMatch = picomatch(resolvedGlobs, {
dot: true,
contains: true,
})

combined.forEach((file) => {
if (
isMatch(path.join(pageDir, file), resolvedGlobs, {
dot: true,
contains: true,
})
) {
if (isMatch(path.join(pageDir, file))) {
combined.delete(file)
}
})
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import '../lib/setup-exception-listeners'
import { loadEnvConfig, type LoadedEnvFiles } from '@next/env'
import { bold, yellow } from '../lib/picocolors'
import crypto from 'crypto'
import { makeRe } from 'next/dist/compiled/micromatch'
import { makeRe } from 'next/dist/compiled/picomatch'
import { existsSync, promises as fs } from 'fs'
import os from 'os'
import { Worker } from '../lib/worker'
Expand Down
5 changes: 3 additions & 2 deletions packages/next/src/build/webpack/plugins/middleware-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getNamedMiddlewareRegex } from '../../../shared/lib/router/utils/route-
import { getModuleBuildInfo } from '../loaders/get-module-build-info'
import { getSortedRoutes } from '../../../shared/lib/router/utils'
import { webpack, sources } from 'next/dist/compiled/webpack/webpack'
import { isMatch } from 'next/dist/compiled/micromatch'
import picomatch from 'next/dist/compiled/picomatch'
import path from 'path'
import {
EDGE_RUNTIME_WEBPACK,
Expand Down Expand Up @@ -277,7 +277,8 @@ function isDynamicCodeEvaluationAllowed(
}

const name = fileName.replace(rootDir ?? '', '')
return isMatch(name, middlewareConfig?.unstable_allowDynamicGlobs ?? [])

return picomatch(middlewareConfig?.unstable_allowDynamicGlobs ?? [])(name)
}

function buildUnsupportedApiError({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from '../../webpack-config'
import type { NextConfigComplete } from '../../../server/config-shared'
import { loadBindings } from '../../swc'
import { isMatch } from 'next/dist/compiled/micromatch'
import picomatch from 'next/dist/compiled/picomatch'
import { getModuleBuildInfo } from '../loaders/get-module-build-info'
import { getPageFilePath } from '../../entries'
import { resolveExternal } from '../../handle-externals'
Expand Down Expand Up @@ -462,8 +462,14 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
...this.traceIgnores,
'**/node_modules/**',
]

// pre-compile the ignore matcher to avoid repeating on every ignoreFn call
const isIgnoreMatcher = picomatch(ignores, {
contains: true,
dot: true,
})
const ignoreFn = (path: string) => {
return isMatch(path, ignores, { contains: true, dot: true })
return isIgnoreMatcher(path)
}

await finishModulesSpan
Expand Down
22 changes: 20 additions & 2 deletions packages/next/src/compiled/@vercel/nft/index.js

Large diffs are not rendered by default.

22 changes: 0 additions & 22 deletions packages/next/src/compiled/micromatch/index.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/next/src/compiled/micromatch/package.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2014-present, Jon Schlinkert.
Copyright (c) 2017-present, Jon Schlinkert.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/compiled/picomatch/index.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/next/src/compiled/picomatch/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name":"picomatch","main":"index.js","author":"Jon Schlinkert (https://github.com/jonschlinkert)","license":"MIT"}
2 changes: 1 addition & 1 deletion packages/next/src/shared/lib/match-remote-pattern.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { RemotePattern } from './image-config'
import { makeRe } from 'next/dist/compiled/micromatch'
import { makeRe } from 'next/dist/compiled/picomatch'

export function matchRemotePattern(pattern: RemotePattern, url: URL): boolean {
if (pattern.protocol !== undefined) {
Expand Down
8 changes: 4 additions & 4 deletions packages/next/taskfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -2045,12 +2045,12 @@ export async function ncc_webpack_sources3(task, opts) {
}

// eslint-disable-next-line camelcase
externals['micromatch'] = 'next/dist/compiled/micromatch'
externals['picomatch'] = 'next/dist/compiled/picomatch'
export async function ncc_minimatch(task, opts) {
await task
.source(relative(__dirname, require.resolve('micromatch')))
.ncc({ packageName: 'micromatch', externals })
.target('src/compiled/micromatch')
.source(relative(__dirname, require.resolve('picomatch')))
.ncc({ packageName: 'picomatch', externals })
.target('src/compiled/picomatch')
}

// eslint-disable-next-line camelcase
Expand Down
4 changes: 2 additions & 2 deletions packages/next/types/misc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ declare module 'next/dist/compiled/lru-cache' {
import m from 'lru-cache'
export = m
}
declare module 'next/dist/compiled/micromatch' {
import m from 'micromatch'
declare module 'next/dist/compiled/picomatch' {
import m from 'picomatch'
export = m
}
declare module 'next/dist/compiled/nanoid/index.cjs' {
Expand Down
38 changes: 16 additions & 22 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 53a0a0f

Please sign in to comment.