Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b9fde60

Browse files
authored
feat: support resolveId/load/transform.filter, deprecate loadInclude & transformInclude (#494)
* feat: filters * docs: update * impl * test: filter * fix * refactor * refactor * test: refactor
1 parent c64d19b commit b9fde60

File tree

20 files changed

+646
-97
lines changed

20 files changed

+646
-97
lines changed

docs/guide/index.md

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,9 @@ export default defineConfig({
198198
| [`enforce`](https://vite.dev/guide/api-plugin.html#plugin-ordering) | ❌ <sup>1</sup> ||| ❌ <sup>1</sup> ||||
199199
| [`buildStart`](https://rollupjs.org/plugin-development/#buildstart) ||||||||
200200
| [`resolveId`](https://rollupjs.org/plugin-development/#resolveid) ||||| ✅ <sup>5</sup> |||
201-
| `loadInclude`<sup>2</sup> ||||||||
201+
| ~~`loadInclude`~~<sup>2</sup> ||||||||
202202
| [`load`](https://rollupjs.org/plugin-development/#load) |||| ✅ <sup>3</sup> ||||
203-
| `transformInclude`<sup>2</sup> ||||||||
203+
| ~~`transformInclude`~~<sup>2</sup> ||||||||
204204
| [`transform`](https://rollupjs.org/plugin-development/#transform) |||| ✅ <sup>3</sup> ||||
205205
| [`watchChange`](https://rollupjs.org/plugin-development/#watchchange) ||||||||
206206
| [`buildEnd`](https://rollupjs.org/plugin-development/#buildend) ||||||||
@@ -209,11 +209,14 @@ export default defineConfig({
209209
::: details Notice
210210

211211
1. Rollup and esbuild do not support using `enforce` to control the order of plugins. Users need to maintain the order manually.
212-
2. webpack's id filter is outside of loader logic; an additional hook is needed for better perf on webpack. In Rollup and Vite, this hook has been polyfilled to match the behaviors. See for the following usage examples.
212+
2. Webpack's id filter is outside of loader logic; an additional hook is needed for better performance on Webpack and Rolldown.
213+
However, it is now deprecated. Please use `transform/load/resolveId.filter` instead.
214+
In Rollup, this hook has been polyfilled to match the behaviors. See the following usage examples for reference.
213215
3. Although esbuild can handle both JavaScript and CSS and many other file formats, you can only return JavaScript in `load` and `transform` results.
214216
4. Currently, `writeBundle` is only serves as a hook for the timing. It doesn't pass any arguments.
215217
5. Rspack supports `resolveId` with a minimum required version of v1.0.0-alpha.1.
216-
:::
218+
219+
:::
217220

218221
### Usage
219222

@@ -227,14 +230,14 @@ export interface Options {
227230
228231
export const unpluginFactory: UnpluginFactory<Options | undefined> = options => ({
229232
name: 'unplugin-starter',
230-
// webpack's id filter is outside of loader logic,
231-
// an additional hook is needed for better perf on webpack
232-
transformInclude(id) {
233-
return id.endsWith('main.ts')
234-
},
235-
// just like rollup transform
236-
transform(code) {
237-
return code.replace(/<template>/, '<template><div>Injected</div>')
233+
transform: {
234+
// an additional hook is needed for better perf on webpack and rolldown
235+
filter: {
236+
id: /main\.ts$/
237+
},
238+
handler(code) {
239+
return code.replace(/<template>/, '<template><div>Injected</div>')
240+
},
238241
},
239242
// more hooks coming
240243
})
@@ -334,11 +337,14 @@ export const unpluginFactory: UnpluginFactory<Options | undefined> = (
334337
console.log(meta.framework) // vite rollup webpack esbuild rspack...
335338
return {
336339
name: 'unplugin-starter',
337-
transform(code) {
338-
return code.replace(/<template>/, '<template><div>Injected</div>')
339-
},
340-
transformInclude(id) {
341-
return id.endsWith('main.ts')
340+
transform: {
341+
// an additional hook is needed for better perf on webpack and rolldown
342+
filter: {
343+
id: /main\.ts$/
344+
},
345+
handler(code) {
346+
return code.replace(/<template>/, '<template><div>Injected</div>')
347+
},
342348
},
343349
vite: {
344350
// Vite plugin

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
},
4444
"dependencies": {
4545
"acorn": "^8.14.1",
46+
"picomatch": "^4.0.2",
4647
"webpack-virtual-modules": "^0.6.2"
4748
},
4849
"devDependencies": {
@@ -55,6 +56,7 @@
5556
"@rspack/core": "^1.3.4",
5657
"@types/fs-extra": "^11.0.4",
5758
"@types/node": "^22.14.0",
59+
"@types/picomatch": "^3.0.2",
5860
"ansis": "^3.17.0",
5961
"bumpp": "^10.1.0",
6062
"esbuild": "^0.25.2",

pnpm-lock.yaml

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/esbuild/index.ts

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
} from '../types'
1111
import fs from 'node:fs'
1212
import path from 'node:path'
13+
import { normalizeObjectHook } from '../utils/filter'
1314
import { toArray } from '../utils/general'
1415
import {
1516
combineSourcemaps,
@@ -167,20 +168,24 @@ function buildSetup() {
167168

168169
if (plugin.resolveId) {
169170
onResolve({ filter: onResolveFilter }, async (args) => {
170-
if (initialOptions.external?.includes(args.path)) {
171+
const id = args.path
172+
if (initialOptions.external?.includes(id)) {
171173
// We don't want to call the `resolveId` hook for external modules,
172174
// since rollup doesn't do that and we want to
173175
// have consistent behaviour across bundlers
174-
return undefined
176+
return
175177
}
176178

177-
const { errors, warnings, mixedContext }
178-
= createPluginContext(context)
179+
const { handler, filter } = normalizeObjectHook('resolveId', plugin.resolveId!)
180+
if (!filter(id))
181+
return
182+
183+
const { errors, warnings, mixedContext } = createPluginContext(context)
179184

180185
const isEntry = args.kind === 'entry-point'
181-
const result = await plugin.resolveId!.call(
186+
const result = await handler.call(
182187
mixedContext,
183-
args.path,
188+
id,
184189
// We explicitly have this if statement here for consistency with
185190
// the integration of other bundlers.
186191
// Here, `args.importer` is just an empty string on entry files
@@ -212,26 +217,26 @@ function buildSetup() {
212217

213218
if (plugin.load) {
214219
onLoad({ filter: onLoadFilter }, async (args) => {
220+
const { handler, filter } = normalizeObjectHook('load', plugin.load!)
215221
const id = args.path + (args.suffix || '') // compat for #427
216222

217-
const { errors, warnings, mixedContext }
218-
= createPluginContext(context)
223+
if (plugin.loadInclude && !plugin.loadInclude(id))
224+
return
225+
if (!filter(id))
226+
return
219227

220-
// because we use `namespace` to simulate virtual modules,
221-
// it is required to forward `resolveDir` for esbuild to find dependencies.
222-
const resolveDir = path.dirname(args.path)
228+
const { errors, warnings, mixedContext } = createPluginContext(context)
223229

224-
let code: string | undefined, map: SourceMap | null | undefined
230+
let code: string | undefined
231+
let map: SourceMap | null | undefined
225232

226-
if (plugin.load && (!plugin.loadInclude || plugin.loadInclude(id))) {
227-
const result = await plugin.load.call(mixedContext, id)
228-
if (typeof result === 'string') {
229-
code = result
230-
}
231-
else if (typeof result === 'object' && result !== null) {
232-
code = result.code
233-
map = result.map as any
234-
}
233+
const result = await handler.call(mixedContext, id)
234+
if (typeof result === 'string') {
235+
code = result
236+
}
237+
else if (typeof result === 'object' && result !== null) {
238+
code = result.code
239+
map = result.map as any
235240
}
236241

237242
if (code === undefined)
@@ -240,6 +245,10 @@ function buildSetup() {
240245
if (map)
241246
code = processCodeWithSourceMap(map, code)
242247

248+
// because we use `namespace` to simulate virtual modules,
249+
// it is required to forward `resolveDir` for esbuild to find dependencies.
250+
const resolveDir = path.dirname(args.path)
251+
243252
return {
244253
contents: code,
245254
errors,
@@ -253,17 +262,20 @@ function buildSetup() {
253262

254263
if (plugin.transform) {
255264
onTransform({ filter: onLoadFilter }, async (args) => {
256-
const id = args.path + (args.suffix || '')
265+
const { handler, filter } = normalizeObjectHook('transform', plugin.transform!)
257266

267+
const id = args.path + (args.suffix || '')
258268
if (plugin.transformInclude && !plugin.transformInclude(id))
259269
return
270+
let code = await args.getContents()
271+
if (!filter(id, code))
272+
return
260273

261274
const { mixedContext, errors, warnings } = createPluginContext(context)
262275
const resolveDir = path.dirname(args.path)
263276

264-
let code = await args.getContents()
265277
let map: SourceMap | null | undefined
266-
const result = await plugin.transform!.call(mixedContext, code, id)
278+
const result = await handler.call(mixedContext, code, id)
267279
if (typeof result === 'string') {
268280
code = result
269281
}

src/farm/index.ts

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type { JsPluginExtended, WatchChangeEvents } from './utils'
1818

1919
import path from 'node:path'
2020

21+
import { normalizeObjectHook } from '../utils/filter'
2122
import { toArray } from '../utils/general'
2223
import { createFarmContext, unpluginContext } from './context'
2324
import {
@@ -92,15 +93,21 @@ export function toFarmPlugin(plugin: UnpluginOptions, options?: Record<string, a
9293
const resolvedIdPath = path.resolve(
9394
params.importer ?? '',
9495
)
96+
const id = decodeStr(params.source)
97+
98+
const { handler, filter } = normalizeObjectHook('resolveId', _resolveId)
99+
if (!filter(id))
100+
return null
101+
95102
let isEntry = false
96103
if (isObject(params.kind) && 'entry' in params.kind) {
97104
const kindWithEntry = params.kind as { entry: string }
98105
isEntry = kindWithEntry.entry === 'index'
99106
}
100107
const farmContext = createFarmContext(context!, resolvedIdPath)
101-
const resolveIdResult = await _resolveId.call(
108+
const resolveIdResult = await handler.call(
102109
Object.assign(unpluginContext(context), farmContext),
103-
decodeStr(params.source),
110+
id,
104111
resolvedIdPath ?? null,
105112
{ isEntry },
106113
)
@@ -141,20 +148,17 @@ export function toFarmPlugin(plugin: UnpluginOptions, options?: Record<string, a
141148
context,
142149
): Promise<PluginLoadHookResult | null> {
143150
const resolvedPath = decodeStr(params.resolvedPath)
144-
145151
const id = appendQuery(resolvedPath, params.query)
146-
147152
const loader = formatTransformModuleType(id)
148153

149-
const shouldLoadInclude
150-
= plugin.loadInclude?.(id)
151-
152-
if (!shouldLoadInclude)
154+
if (plugin.loadInclude && !plugin.loadInclude?.(id))
155+
return null
156+
const { handler, filter } = normalizeObjectHook('load', _load)
157+
if (!filter(id))
153158
return null
154159

155160
const farmContext = createFarmContext(context!, id)
156-
157-
const content: TransformResult = await _load.call(
161+
const content: TransformResult = await handler.call(
158162
Object.assign(unpluginContext(context!), farmContext),
159163
id,
160164
)
@@ -178,19 +182,18 @@ export function toFarmPlugin(plugin: UnpluginOptions, options?: Record<string, a
178182
context: CompilationContext,
179183
) {
180184
const resolvedPath = decodeStr(params.resolvedPath)
181-
182185
const id = appendQuery(resolvedPath, params.query)
183-
184186
const loader = formatTransformModuleType(id)
185187

186-
const shouldTransformInclude
187-
= plugin.transformInclude?.(id)
188-
const farmContext = createFarmContext(context, id)
188+
if (plugin.transformInclude && !plugin.transformInclude(id))
189+
return null
189190

190-
if (!shouldTransformInclude)
191+
const { handler, filter } = normalizeObjectHook('transform', _transform)
192+
if (!filter(id, params.content))
191193
return null
192194

193-
const resource: TransformResult = await _transform.call(
195+
const farmContext = createFarmContext(context, id)
196+
const resource: TransformResult = await handler.call(
194197
Object.assign(unpluginContext(context), farmContext),
195198
params.content,
196199
id,

0 commit comments

Comments
 (0)