From 7ee6fed812247da6b1b6ff8ac8d0e75a01148afa Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Thu, 12 Jan 2023 17:55:27 +0800 Subject: [PATCH] perf: optimize path matches --- src/pathRules.ts | 12 ++++++++++++ src/pathToImage.ts | 9 ++++----- src/plugin.ts | 24 +++++++++++++----------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/pathRules.ts b/src/pathRules.ts index 1dde376..93d9aa5 100644 --- a/src/pathRules.ts +++ b/src/pathRules.ts @@ -1,3 +1,7 @@ +import { pathToRegexp } from 'path-to-regexp' + +export type FindPathRule = (pathname: string) => string | undefined + export function generatePathRules(prefix: string) { return [ '/bg/:background/text/:text/:width?/:height?{.:type}?', @@ -7,3 +11,11 @@ export function generatePathRules(prefix: string) { '/:width?/:height?{.:type}?', ].map((_) => `${prefix}${_}`) } + +export function createPathRuleMatch(prefix: string): FindPathRule { + const rules = generatePathRules(prefix).map((rule) => ({ + regexp: pathToRegexp(rule), + rule, + })) + return (pathname) => rules.find(({ regexp }) => regexp.test(pathname))?.rule +} diff --git a/src/pathToImage.ts b/src/pathToImage.ts index 3f9a8d9..4fde068 100644 --- a/src/pathToImage.ts +++ b/src/pathToImage.ts @@ -1,9 +1,10 @@ import { parse as urlParse } from 'node:url' -import { match, pathToRegexp } from 'path-to-regexp' +import { match } from 'path-to-regexp' import type { Create, CreateText } from 'sharp' import sharp from 'sharp' import { bufferCache } from './cache' import { DEFAULT_PARAMS } from './constants' +import type { FindPathRule } from './pathRules' import type { ImageCacheItem, ImagePlaceholderOptions, @@ -19,7 +20,7 @@ export type TextOptions = CreateText export async function pathToImage( url: string, - rules: string[], + findPathRule: FindPathRule, options: Required, ): Promise { if (bufferCache.has(url)) { @@ -27,9 +28,7 @@ export async function pathToImage( } const { query: urlQuery, pathname } = urlParse(url, true) - const rule = rules.find((rule) => { - return pathToRegexp(rule).test(pathname!) - }) + const rule = findPathRule(pathname!) if (!rule) return const urlMatch = match(rule, { decode: decodeURIComponent })(pathname!) || { diff --git a/src/plugin.ts b/src/plugin.ts index 6d8ebb1..056f714 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -4,7 +4,8 @@ import { isCSSRequest } from 'vite' import { bufferToFile } from './bufferToFile' import { contentCache } from './cache' import { DEFAULT_PREFIX } from './constants' -import { generatePathRules } from './pathRules' +import type { FindPathRule } from './pathRules' +import { createPathRuleMatch } from './pathRules' import { pathToImage } from './pathToImage' import type { ImageCacheItem, @@ -63,7 +64,7 @@ function placeholderServerPlugin( options: ImagePlaceholderOptions = {}, ): Plugin { const opts = parseOptions(options) - const pathRules = generatePathRules(opts.prefix) + const findPathRule = createPathRuleMatch(opts.prefix) return { name: 'vite-plugin-image-placeholder-server', @@ -73,7 +74,7 @@ function placeholderServerPlugin( const url = req.url! if (!url.startsWith(opts.prefix)) return next() - const image = await pathToImage(url, pathRules, opts) + const image = await pathToImage(url, findPathRule, opts) if (!image) return next() @@ -89,7 +90,7 @@ function placeholderImporterPlugin( options: ImagePlaceholderOptions = {}, ): Plugin { const opts = parseOptions(options) - const pathRules = generatePathRules(opts.prefix) + const findPathRule = createPathRuleMatch(opts.prefix) const RE_VIRTUAL = /^\0virtual:\s*/ const moduleId = `virtual:${opts.prefix.slice(1)}` const resolveVirtualModuleId = `\0${moduleId}` @@ -112,7 +113,7 @@ function placeholderImporterPlugin( if (contentCache.has(url)) { return `export default '${contentCache.get(url)!}'` } - const image = await pathToImage(url, pathRules, opts) + const image = await pathToImage(url, findPathRule, opts) if (image) { let content: string if ( @@ -143,7 +144,7 @@ function placeholderTransformPlugin( options: ImagePlaceholderOptions = {}, ): Plugin { const opts = parseOptions(options) - const pathRules = generatePathRules(opts.prefix) + const findPathRule = createPathRuleMatch(opts.prefix) const moduleId = `virtual:${opts.prefix.slice(1)}` const resolveVirtualModuleId = `\0${moduleId}` const s = `(${opts.prefix}.*?)` @@ -183,7 +184,7 @@ function placeholderTransformPlugin( ctx, code, RE_PATTERN, - pathRules, + findPathRule, opts, config, ) @@ -197,7 +198,7 @@ function placeholderTransformPlugin( ctx, html, RE_PATTERN, - pathRules, + findPathRule, opts, config, ) @@ -211,7 +212,7 @@ async function transformPlaceholder( ctx: PluginContext, code: string, pattern: RegExp, - rules: string[], + findPathRule: FindPathRule, opts: Required, config: ResolvedConfig, ) { @@ -228,13 +229,14 @@ async function transformPlaceholder( hasReplaced = true s.update(start, end, `${dynamic[0]}${contentCache.get(url)}${dynamic[1]}`) } else { - const image = await pathToImage(url, rules, opts) + const image = await pathToImage(url, findPathRule, opts) if (image) { hasReplaced = true let content: string if ( opts.output && - image.buffer.byteLength >= config.build.assetsInlineLimit + image.buffer.byteLength >= config.build.assetsInlineLimit && + config.command === 'build' ) { const { assetsDir, filename } = parseOutput(opts.output, config) content = await bufferToFile(