perf(plugin): more efficient module filtering via regular expressions

This commit is contained in:
alex8088 2025-10-19 11:57:23 +08:00
parent 28bb22b353
commit 70e027d38a
4 changed files with 34 additions and 88 deletions

View File

@ -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<string, string> | 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)`

View File

@ -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<string | void> {
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',

View File

@ -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,25 +20,25 @@ 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)
if (nodeWorkerRE.test(id)) {
const match = nodeWorkerImporterRE.exec(id)
if (match) {
const hash = this.emitFile({
type: 'chunk',
id: cleanPath,
importer: query.importer
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 {
if (code.match(nodeWorkerAssetUrlRE)) {

View File

@ -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<string, string> | 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)