Skip to content

Commit 9b3bdde

Browse files
authored
perf(plugin-rsc): add hook filters (#1094)
1 parent f7ea163 commit 9b3bdde

File tree

9 files changed

+66
-5
lines changed

9 files changed

+66
-5
lines changed

packages/plugin-rsc/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"prepack": "tsdown"
4040
},
4141
"dependencies": {
42+
"@rolldown/pluginutils": "1.0.0-rc.2",
4243
"es-module-lexer": "^2.0.0",
4344
"estree-walker": "^3.0.3",
4445
"magic-string": "^0.30.21",

packages/plugin-rsc/src/core/plugin.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export default function vitePluginRscCore(): Plugin[] {
55
{
66
name: 'rsc:patch-react-server-dom-webpack',
77
transform: {
8+
filter: { code: '__webpack_require__' },
89
handler(originalCode, _id, _options) {
910
let code = originalCode
1011
if (code.includes('__webpack_require__.u')) {

packages/plugin-rsc/src/plugin.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createRequire } from 'node:module'
44
import path from 'node:path'
55
import { pathToFileURL } from 'node:url'
66
import { createDebug } from '@hiogawa/utils'
7+
import { exactRegex, prefixRegex } from '@rolldown/pluginutils'
78
import * as esModuleLexer from 'es-module-lexer'
89
import MagicString from 'magic-string'
910
import { toNodeHandler } from 'srvx/node'
@@ -326,6 +327,7 @@ export function vitePluginRscMinimal(
326327
name: 'rsc:vite-client-raw-import',
327328
transform: {
328329
order: 'post',
330+
filter: { code: '__vite_rsc_raw_import__' },
329331
handler(code) {
330332
if (code.includes('__vite_rsc_raw_import__')) {
331333
// inject dynamic import last to avoid Vite adding `?import` query
@@ -343,6 +345,7 @@ export function vitePluginRscMinimal(
343345
name: 'rsc:reference-validation',
344346
apply: 'serve',
345347
load: {
348+
filter: { id: prefixRegex('\0virtual:vite-rsc/reference-validation?') },
346349
handler(id, _options) {
347350
if (id.startsWith('\0virtual:vite-rsc/reference-validation?')) {
348351
const parsed = parseReferenceValidationVirtual(id)
@@ -824,6 +827,7 @@ export default function vitePluginRsc(
824827
name: 'rsc:react-server-dom-webpack-alias',
825828
resolveId: {
826829
order: 'pre',
830+
filter: { id: prefixRegex(`${PKG_NAME}/vendor/react-server-dom/`) },
827831
async handler(source, importer, options) {
828832
if (
829833
hasReactServerDomWebpack &&
@@ -848,6 +852,7 @@ export default function vitePluginRsc(
848852
// - (build) rewriting to external `import("../<env>/<entry>.js")`
849853
name: 'rsc:load-environment-module',
850854
transform: {
855+
filter: { code: 'import.meta.viteRsc.loadModule' },
851856
async handler(code) {
852857
if (!code.includes('import.meta.viteRsc.loadModule')) return
853858
const { server } = manager
@@ -996,13 +1001,15 @@ export default function vitePluginRsc(
9961001
{
9971002
name: 'rsc:virtual:vite-rsc/rpc-client',
9981003
resolveId: {
1004+
filter: { id: exactRegex('virtual:vite-rsc/rpc-client') },
9991005
handler(source) {
10001006
if (source === 'virtual:vite-rsc/rpc-client') {
10011007
return `\0${source}`
10021008
}
10031009
},
10041010
},
10051011
load: {
1012+
filter: { id: exactRegex('\0virtual:vite-rsc/rpc-client') },
10061013
handler(id) {
10071014
if (id === '\0virtual:vite-rsc/rpc-client') {
10081015
const { server } = manager
@@ -1026,6 +1033,7 @@ export function createRpcClient(params) {
10261033
{
10271034
name: 'rsc:virtual:vite-rsc/assets-manifest',
10281035
resolveId: {
1036+
filter: { id: exactRegex('virtual:vite-rsc/assets-manifest') },
10291037
handler(source) {
10301038
if (source === 'virtual:vite-rsc/assets-manifest') {
10311039
if (this.environment.mode === 'build') {
@@ -1036,6 +1044,7 @@ export function createRpcClient(params) {
10361044
},
10371045
},
10381046
load: {
1047+
filter: { id: exactRegex('\0virtual:vite-rsc/assets-manifest') },
10391048
handler(id) {
10401049
if (id === '\0virtual:vite-rsc/assets-manifest') {
10411050
assert(this.environment.name !== 'client')
@@ -1168,6 +1177,7 @@ export default assetsManifest.bootstrapScriptContent;
11681177
{
11691178
name: 'rsc:bootstrap-script-content',
11701179
transform: {
1180+
filter: { code: 'loadBootstrapScriptContent' },
11711181
async handler(code) {
11721182
if (
11731183
!code.includes('loadBootstrapScriptContent') ||
@@ -1287,6 +1297,7 @@ function globalAsyncLocalStoragePlugin(): Plugin[] {
12871297
{
12881298
name: 'rsc:inject-async-local-storage',
12891299
transform: {
1300+
filter: { code: 'typeof AsyncLocalStorage' },
12901301
handler(code) {
12911302
if (
12921303
(this.environment.name === 'ssr' ||
@@ -1350,6 +1361,10 @@ function vitePluginUseClient(
13501361
{
13511362
name: 'rsc:use-client',
13521363
transform: {
1364+
// TODO: cannot use filter because handler has cleanup side effect
1365+
// (`delete manager.clientReferenceMetaMap[id]`) that must run
1366+
// even when directive is removed (HMR case)
1367+
// filter: { code: 'use client' },
13531368
async handler(code, id) {
13541369
if (this.environment.name !== serverEnvironmentName) return
13551370
if (!code.includes('use client')) {
@@ -1456,13 +1471,15 @@ function vitePluginUseClient(
14561471
{
14571472
name: 'rsc:use-client/build-references',
14581473
resolveId: {
1474+
filter: { id: prefixRegex('virtual:vite-rsc/client-references') },
14591475
handler(source) {
14601476
if (source.startsWith('virtual:vite-rsc/client-references')) {
14611477
return '\0' + source
14621478
}
14631479
},
14641480
},
14651481
load: {
1482+
filter: { id: prefixRegex('\0virtual:vite-rsc/client-references') },
14661483
handler(id) {
14671484
if (id === '\0virtual:vite-rsc/client-references') {
14681485
// not used during dev
@@ -1543,6 +1560,9 @@ function vitePluginUseClient(
15431560
{
15441561
name: 'rsc:virtual-client-in-server-package',
15451562
load: {
1563+
filter: {
1564+
id: prefixRegex('\0virtual:vite-rsc/client-in-server-package-proxy/'),
1565+
},
15461566
async handler(id) {
15471567
if (
15481568
id.startsWith('\0virtual:vite-rsc/client-in-server-package-proxy/')
@@ -1583,6 +1603,7 @@ function vitePluginUseClient(
15831603
},
15841604
},
15851605
load: {
1606+
filter: { id: prefixRegex('\0virtual:vite-rsc/client-package-proxy/') },
15861607
async handler(id) {
15871608
if (id.startsWith('\0virtual:vite-rsc/client-package-proxy/')) {
15881609
assert(this.environment.mode === 'dev')
@@ -1764,6 +1785,7 @@ function vitePluginDefineEncryptionKey(
17641785
}
17651786
},
17661787
resolveId: {
1788+
filter: { id: exactRegex('virtual:vite-rsc/encryption-key') },
17671789
handler(source) {
17681790
if (source === 'virtual:vite-rsc/encryption-key') {
17691791
// encryption logic can be tree-shaken if action bind is not used.
@@ -1772,6 +1794,7 @@ function vitePluginDefineEncryptionKey(
17721794
},
17731795
},
17741796
load: {
1797+
filter: { id: exactRegex('\0virtual:vite-rsc/encryption-key') },
17751798
handler(id) {
17761799
if (id === '\0virtual:vite-rsc/encryption-key') {
17771800
if (this.environment.mode === 'build') {
@@ -1828,6 +1851,10 @@ function vitePluginUseServer(
18281851
{
18291852
name: 'rsc:use-server',
18301853
transform: {
1854+
// TODO: cannot use filter because handler has cleanup side effect
1855+
// (`delete manager.serverReferenceMetaMap[id]`) that must run
1856+
// even when directive is removed (HMR case)
1857+
// filter: { code: 'use server' },
18311858
async handler(code, id) {
18321859
if (!code.includes('use server')) {
18331860
delete manager.serverReferenceMetaMap[id]
@@ -2240,6 +2267,8 @@ function vitePluginRscCss(
22402267
{
22412268
name: 'rsc:rsc-css-export-transform',
22422269
transform: {
2270+
// TODO:
2271+
// filter: {},
22432272
async handler(code, id) {
22442273
if (this.environment.name !== 'rsc') return
22452274
const filter = getRscCssTransformFilter({ id, code })
@@ -2267,6 +2296,9 @@ function vitePluginRscCss(
22672296
apply: 'serve',
22682297
transform: {
22692298
order: 'post',
2299+
filter: {
2300+
id: /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(\?|$)/,
2301+
},
22702302
handler(_code, id, _options) {
22712303
if (
22722304
this.environment.name === 'client' &&
@@ -2285,13 +2317,15 @@ function vitePluginRscCss(
22852317
{
22862318
name: 'rsc:css-virtual',
22872319
resolveId: {
2320+
filter: { id: prefixRegex('virtual:vite-rsc/css?') },
22882321
handler(source) {
22892322
if (source.startsWith('virtual:vite-rsc/css?')) {
22902323
return '\0' + source
22912324
}
22922325
},
22932326
},
22942327
load: {
2328+
filter: { id: prefixRegex('\0virtual:vite-rsc/css?') },
22952329
async handler(id) {
22962330
const parsed = parseCssVirtual(id)
22972331
if (parsed?.type === 'ssr') {
@@ -2334,6 +2368,7 @@ function vitePluginRscCss(
23342368
}
23352369
},
23362370
transform: {
2371+
filter: { code: 'import.meta.viteRsc.loadCss' },
23372372
async handler(code, id) {
23382373
if (!code.includes('import.meta.viteRsc.loadCss')) return
23392374

@@ -2401,6 +2436,7 @@ function vitePluginRscCss(
24012436
},
24022437
},
24032438
load: {
2439+
filter: { id: prefixRegex('\0virtual:vite-rsc/css?') },
24042440
handler(id) {
24052441
const { server } = manager
24062442
const parsed = parseCssVirtual(id)

packages/plugin-rsc/src/plugins/cjs.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ export function cjsModuleRunnerPlugin(): Plugin[] {
1818
apply: 'serve',
1919
applyToEnvironment: (env) => env.config.dev.moduleRunnerTransform,
2020
transform: {
21+
filter: {
22+
id: /\/node_modules\//,
23+
code: /\b(require|exports)\b/,
24+
},
2125
async handler(code, id) {
2226
if (
2327
id.includes('/node_modules/') &&

packages/plugin-rsc/src/plugins/import-environment.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import assert from 'node:assert'
22
import fs from 'node:fs'
33
import path from 'node:path'
4+
import { exactRegex } from '@rolldown/pluginutils'
45
import MagicString from 'magic-string'
56
import { stripLiteral } from 'strip-literal'
67
import type { Plugin, ResolvedConfig } from 'vite'
@@ -50,6 +51,7 @@ export function vitePluginImportEnvironment(
5051
{
5152
name: 'rsc:import-environment',
5253
resolveId: {
54+
filter: { id: exactRegex(ENV_IMPORTS_MANIFEST_PLACEHOLDER) },
5355
handler(source) {
5456
// Use placeholder as external, renderChunk will replace with correct relative path
5557
if (source === ENV_IMPORTS_MANIFEST_PLACEHOLDER) {
@@ -80,6 +82,7 @@ export function vitePluginImportEnvironment(
8082
}
8183
},
8284
transform: {
85+
filter: { code: 'import.meta.viteRsc.import' },
8386
async handler(code, id) {
8487
if (!code.includes('import.meta.viteRsc.import')) return
8588

packages/plugin-rsc/src/plugins/resolved-id-proxy.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { prefixRegex } from '@rolldown/pluginutils'
12
import type { Plugin } from 'vite'
23

34
// Resolved ID proxy plugin
@@ -130,7 +131,7 @@ export function vitePluginResolvedIdProxy(): Plugin {
130131
return {
131132
name: 'rsc:resolved-id-proxy',
132133
resolveId: {
133-
// TODO: filter
134+
filter: { id: prefixRegex(RESOLVED_ID_PROXY_PREFIX) },
134135
handler(source) {
135136
const originalId = fromResolvedIdProxy(source)
136137
if (originalId !== undefined) {

packages/plugin-rsc/src/plugins/utils.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { createHash } from 'node:crypto'
22
import path from 'node:path'
3+
import { exactRegex } from '@rolldown/pluginutils'
34
import {
45
normalizePath,
56
type Plugin,
@@ -41,17 +42,22 @@ export function createVirtualPlugin(
4142
name: string,
4243
load: Plugin['load'],
4344
): Plugin {
44-
name = 'virtual:' + name
45+
const virtualId = 'virtual:' + name
46+
const resolvedId = '\0' + virtualId
4547
return {
4648
name: `rsc:virtual-${name}`,
4749
resolveId: {
48-
handler(source, _importer, _options) {
49-
return source === name ? '\0' + name : undefined
50+
filter: { id: exactRegex(virtualId) },
51+
handler(source) {
52+
if (source === virtualId) {
53+
return resolvedId
54+
}
5055
},
5156
},
5257
load: {
58+
filter: { id: exactRegex(resolvedId) },
5359
handler(id, options) {
54-
if (id === '\0' + name) {
60+
if (id === resolvedId) {
5561
return (load as Function).apply(this, [id, options])
5662
}
5763
},

packages/plugin-rsc/src/plugins/validate-import.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from 'node:path'
2+
import { prefixRegex } from '@rolldown/pluginutils'
23
import type { DevEnvironment, Plugin, Rollup } from 'vite'
34

45
// https://github.com/vercel/next.js/blob/90f564d376153fe0b5808eab7b83665ee5e08aaf/packages/next/src/build/webpack-config.ts#L1249-L1280
@@ -9,6 +10,7 @@ export function validateImportPlugin(): Plugin {
910
name: 'rsc:validate-imports',
1011
resolveId: {
1112
order: 'pre',
13+
filter: { id: /^(client-only|server-only)$/ },
1214
async handler(source, _importer, options) {
1315
// optimizer is not aware of server/client boudnary so skip
1416
if ('scan' in options && options.scan) {
@@ -36,6 +38,7 @@ export function validateImportPlugin(): Plugin {
3638
},
3739
},
3840
load: {
41+
filter: { id: prefixRegex('\0virtual:vite-rsc/validate-imports/') },
3942
handler(id) {
4043
if (id.startsWith('\0virtual:vite-rsc/validate-imports/invalid/')) {
4144
// it should surface as build error but we make a runtime error just in case.
@@ -50,6 +53,9 @@ export function validateImportPlugin(): Plugin {
5053
// for dev, use DevEnvironment.moduleGraph during post transform
5154
transform: {
5255
order: 'post',
56+
filter: {
57+
id: prefixRegex('\0virtual:vite-rsc/validate-imports/invalid/'),
58+
},
5359
async handler(_code, id) {
5460
if (this.environment.mode === 'dev') {
5561
if (id.startsWith(`\0virtual:vite-rsc/validate-imports/invalid/`)) {

pnpm-lock.yaml

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

0 commit comments

Comments
 (0)