From 70e027d38accfb28ced64ae52674ee0d71d854de Mon Sep 17 00:00:00 2001 From: alex8088 <244096523@qq.com> Date: Sun, 19 Oct 2025 11:57:23 +0800 Subject: [PATCH] perf(plugin): more efficient module filtering via regular expressions --- src/plugins/asset.ts | 62 +++++++-------------------------------- src/plugins/modulePath.ts | 19 ++++-------- src/plugins/worker.ts | 32 ++++++++++---------- src/utils.ts | 9 ------ 4 files changed, 34 insertions(+), 88 deletions(-) diff --git a/src/plugins/asset.ts b/src/plugins/asset.ts index e33d82c..3dc9f95 100644 --- a/src/plugins/asset.ts +++ b/src/plugins/asset.ts @@ -3,48 +3,15 @@ import fs from 'node:fs/promises' import type { SourceMapInput } from 'rollup' import { type Plugin, normalizePath } from 'vite' import MagicString from 'magic-string' -import { cleanUrl, parseRequest, getHash, toRelativePath } from '../utils' - -interface AssetResolved { - type: 'asset' | 'native' | 'wasm' - file: string - query: Record | null -} - -function resolveAsset(id: string): AssetResolved | null { - const file = cleanUrl(id) - const query = parseRequest(id) - - if (query && typeof query.asset === 'string') { - return { - type: 'asset', - file, - query - } - } - - if (file.endsWith('.node')) { - return { - type: 'native', - file, - query - } - } - - if (id.endsWith('.wasm?loader')) { - return { - type: 'wasm', - file, - query - } - } - - return null -} +import { cleanUrl, getHash, toRelativePath } from '../utils' const nodeAssetRE = /__VITE_NODE_ASSET__([\w$]+)__/g const nodePublicAssetRE = /__VITE_NODE_PUBLIC_ASSET__([a-z\d]{8})__/g +const assetImportRE = /(?:[?|&]asset(?:&|$)|\.wasm\?loader$|\.node$)/ +const assetRE = /[?|&]asset(?:&|$)/ +const assetUnpackRE = /[?|&]asset&asarUnpack$/ + const wasmHelperId = '\0__electron-vite-wasm-helper' const wasmHelperCode = ` @@ -87,19 +54,12 @@ export default function assetPlugin(): Plugin { return wasmHelperCode } - if (id.startsWith('\0')) { - // Rollup convention, this id should be handled by the - // plugin that marked it with \0 - return - } - - const assetResolved = resolveAsset(id) - if (!assetResolved) { + if (id.startsWith('\0') || !assetImportRE.test(id)) { return } let referenceId: string - const file = assetResolved.file + const file = cleanUrl(id) if (publicDir && file.startsWith(publicDir)) { const hash = getHash(file) if (!publicAssetPathCache.get(hash)) { @@ -122,8 +82,8 @@ export default function assetPlugin(): Plugin { } } - if (assetResolved.type === 'asset') { - if (assetResolved.query && typeof assetResolved.query.asarUnpack === 'string') { + if (assetRE.test(id)) { + if (assetUnpackRE.test(id)) { return ` import { join } from 'path' export default join(__dirname, ${referenceId}).replace('app.asar', 'app.asar.unpacked')` @@ -134,11 +94,11 @@ export default function assetPlugin(): Plugin { } } - if (assetResolved.type === 'native') { + if (id.endsWith('.node')) { return `export default require(${referenceId})` } - if (assetResolved.type === 'wasm') { + if (id.endsWith('.wasm?loader')) { return ` import loadWasm from ${JSON.stringify(wasmHelperId)} export default importObject => loadWasm(${referenceId}, importObject)` diff --git a/src/plugins/modulePath.ts b/src/plugins/modulePath.ts index f694479..7bb36c6 100644 --- a/src/plugins/modulePath.ts +++ b/src/plugins/modulePath.ts @@ -2,7 +2,7 @@ import path from 'node:path' import { type Plugin, type InlineConfig, build as viteBuild, mergeConfig } from 'vite' import type { SourceMapInput, RollupOutput, OutputOptions } from 'rollup' import MagicString from 'magic-string' -import { cleanUrl, parseRequest, toRelativePath } from '../utils' +import { cleanUrl, toRelativePath } from '../utils' const modulePathRE = /__VITE_MODULE_PATH__([\w$]+)__/g @@ -18,17 +18,10 @@ export default function modulePathPlugin(config: InlineConfig): Plugin { configResolved(config): void { sourcemap = config.build.sourcemap }, - resolveId(id, importer): string | void { - const query = parseRequest(id) - if (query && typeof query.modulePath === 'string') { - return id + `&importer=${importer}` - } - }, async load(id): Promise { - const query = parseRequest(id) - if (query && typeof query.modulePath === 'string' && typeof query.importer === 'string') { - const entry = path.resolve(path.dirname(query.importer), cleanUrl(id)) - const bundle = await bundleEntryFile(entry, config) + if (id.endsWith('?modulePath')) { + // id resolved by Vite resolve plugin + const bundle = await bundleEntryFile(cleanUrl(id), config) const [outputChunk, ...outputChunks] = bundle.output const hash = this.emitFile({ type: 'asset', @@ -44,8 +37,8 @@ export default function modulePathPlugin(config: InlineConfig): Plugin { }) const refId = `__VITE_MODULE_PATH__${hash}__` return ` - import { join } from 'path' - export default join(__dirname, ${refId})` + import { join } from 'path' + export default join(__dirname, ${refId})` } }, renderChunk(code, chunk): { code: string; map: SourceMapInput } | null { diff --git a/src/plugins/worker.ts b/src/plugins/worker.ts index e2d468b..f09352c 100644 --- a/src/plugins/worker.ts +++ b/src/plugins/worker.ts @@ -1,9 +1,11 @@ import type { Plugin } from 'vite' import type { SourceMapInput } from 'rollup' import MagicString from 'magic-string' -import { cleanUrl, parseRequest, toRelativePath } from '../utils' +import { cleanUrl, toRelativePath } from '../utils' const nodeWorkerAssetUrlRE = /__VITE_NODE_WORKER_ASSET__([\w$]+)__/g +const nodeWorkerRE = /\?nodeWorker(?:&|$)/ +const nodeWorkerImporterRE = /(?:\?)nodeWorker&importer=([^&]+)(?:&|$)/ /** * Resolve `?nodeWorker` import and automatically generate `Worker` wrapper. @@ -18,24 +20,24 @@ export default function workerPlugin(): Plugin { sourcemap = config.build.sourcemap }, resolveId(id, importer): string | void { - const query = parseRequest(id) - if (query && typeof query.nodeWorker === 'string') { + if (id.endsWith('?nodeWorker')) { return id + `&importer=${importer}` } }, load(id): string | void { - const query = parseRequest(id) - if (query && typeof query.nodeWorker === 'string' && typeof query.importer === 'string') { - const cleanPath = cleanUrl(id) - const hash = this.emitFile({ - type: 'chunk', - id: cleanPath, - importer: query.importer - }) - const assetRefId = `__VITE_NODE_WORKER_ASSET__${hash}__` - return ` - import { Worker } from 'node:worker_threads'; - export default function (options) { return new Worker(new URL(${assetRefId}, import.meta.url), options); }` + if (nodeWorkerRE.test(id)) { + const match = nodeWorkerImporterRE.exec(id) + if (match) { + const hash = this.emitFile({ + type: 'chunk', + id: cleanUrl(id), + importer: match[1] + }) + const assetRefId = `__VITE_NODE_WORKER_ASSET__${hash}__` + return ` + import { Worker } from 'node:worker_threads'; + export default function (options) { return new Worker(new URL(${assetRefId}, import.meta.url), options); }` + } } }, renderChunk(code, chunk): { code: string; map: SourceMapInput } | null { diff --git a/src/utils.ts b/src/utils.ts index 3d1821e..ffcebbd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,3 @@ -import { URL, URLSearchParams } from 'node:url' import path from 'node:path' import fs from 'node:fs' import { createHash } from 'node:crypto' @@ -20,14 +19,6 @@ export const hashRE = /#.*$/s export const cleanUrl = (url: string): string => url.replace(hashRE, '').replace(queryRE, '') -export function parseRequest(id: string): Record | null { - const { search } = new URL(id, 'file:') - if (!search) { - return null - } - return Object.fromEntries(new URLSearchParams(search)) -} - export function getHash(text: Buffer | string): string { return createHash('sha256') .update(text as unknown as Uint8Array)