Repository navigation
Support ast-node-based filter in transformDirectiveProxyExport #1391
Description
We have demo-ed this capability for use cache imported in server, but not when imported in client directly.
Lines 5 to 8 in fba021f
| // Ordinary values remain available from "use cache" modules without becoming | |
| // callable server references. | |
| export const metadata = { title: 'cached metadata' } | |
| export const tags = ['cache'] |
We would need similar filtering feature for transformDirectiveProxyExport to support this use case.
3. Non-RSC Proxy Filtering For Known Non-Function Exports
Remaining primitive
Allow transformDirectiveProxyExport to select which module exports become Server Reference proxies using the same static export facts available to the RSC-side wrapper transform.
The gap is concrete for a module-level "use cache" file containing ordinary object/array exports alongside a cached function:
'use cache'
export const metadata = { title: 'page' }
export const tags = ['cache']
export async function cached(value) {
return value
}The callable cache example already has this source shape in file-directive-from-server/action.ts. Its RSC branch filters object and array exports before transformWrapExport validation at callable-cache-plugin.ts:37, so metadata and tags remain ordinary values while cached is wrapped.
The non-RSC branch has no equivalent filter. transformDirectiveProxyExport validates every variable initializer and proxies every discovered export at packages/plugin-rsc/src/transforms/proxy-export.ts:62. With the callable example's rejectNonAsyncFunction: true, metadata or tags throws unsupported non async function before cached can become a proxy. Existing E2E coverage avoids this path: the mixed-export fixture is imported only through the server, while the client-imported fixture exports only a function.
The required primitive is a metadata-aware proxy filter or equivalent selected-export contract. For framework-owned "use cache" behavior:
- Known function exports become proxies.
- Unknown expressions remain conservatively proxied because their runtime value is unavailable in the client/SSR graph.
- Known object and array exports are omitted from the proxy module.
- Direct primitive exports may still be rejected according to directive policy.
- Returned
exportNamesand Server Reference claims include only emitted proxies.
This is narrower than server-side classification. The RSC side can already implement typeof value === 'function' ? registerCacheWrapper(value) : value through transformWrapExport without re-evaluating the source initializer.
Next.js usage and rationale
Next.js client fixture 17 contains a module-level "use cache" file exporting an object and array. Its checked client output is empty, proving that known non-function exports do not become Server Reference proxies.
Client fixture 13 proxies known functions and statically unknown expressions from a "use cache" module. The corresponding classifier excludes object, array, and literal expressions from cache runtime wrapping at server_actions.rs:2966.
No single maintained Next.js fixture combines known non-functions and functions in one declaration. Fixtures 13 and 17 plus the shared classifier establish the mixed result: emit proxies for callable or potentially callable exports and omit known object/array exports.
Activity
[-]Non-RSC Proxy Filtering For Known Non-Function Exports[/-][+]Support node-based filter in `transformDirectiveProxyExport`[/+][-]Support node-based filter in `transformDirectiveProxyExport`[/-][+]Support ast-node-based filter in `transformDirectiveProxyExport`[/+]