Skip to content

Commit 2fcf7f3

Browse files
longlhoclaude
andauthored
fix(@formatjs/unplugin): strip query/hash in transformInclude (#6465)
## Summary - React Router splits routes that export `clientLoader`/`clientAction` into virtual chunk modules with IDs like `route.tsx?route-chunk=main`. The plain `\.[jt]sx?$` test in `transformInclude` rejected those, so `defineMessage` calls in those chunks never got their `id` injected during production builds. - Strip `?…` and `#…` off the id before the extension check. - Added a regression test covering query-string and hash IDs (and the negative `node_modules` case with a query). Fixes #6455 ## Test plan - [x] `bazel test //packages/unplugin/...` — all tests pass, including the new regression case - [ ] CI green 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
1 parent cff6ade commit 2fcf7f3

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

packages/unplugin/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ export const unpluginFactory: UnpluginFactory<Options | undefined> = (
1313
name: 'formatjs',
1414
enforce: 'pre' as const,
1515
transformInclude(id: string): boolean {
16-
return /\.[jt]sx?$/.test(id) && !id.includes('node_modules')
16+
// Strip query/hash so virtual chunk IDs like
17+
// `route.tsx?route-chunk=main` (e.g. React Router's clientLoader/
18+
// clientAction split) still match the JS/TS extension test.
19+
const path = id.replace(/[?#].*$/, '')
20+
return /\.[jt]sx?$/.test(path) && !path.includes('node_modules')
1721
},
1822
transform(code: string, id: string) {
1923
return transform(code, id, options)

packages/unplugin/tests/transform.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,21 @@ describe('@formatjs/unplugin factory', () => {
518518
expect(plugin.transformInclude('/node_modules/react/index.js')).toBe(false)
519519
})
520520

521+
test('transformInclude ignores query/hash on the id (#6455)', async () => {
522+
const {unpluginFactory} = await import('../index.js')
523+
const plugin = getPlugin(unpluginFactory)
524+
// React Router splits routes that export clientLoader/clientAction into
525+
// virtual chunk modules — IDs come in with a `?route-chunk=...` query.
526+
expect(plugin.transformInclude('/src/route.tsx?route-chunk=main')).toBe(
527+
true
528+
)
529+
expect(plugin.transformInclude('/src/route.ts?v=123')).toBe(true)
530+
expect(plugin.transformInclude('/src/route.tsx#anchor')).toBe(true)
531+
expect(plugin.transformInclude('/node_modules/foo/index.js?v=123')).toBe(
532+
false
533+
)
534+
})
535+
521536
test('transform processes formatjs descriptors', async () => {
522537
const {unpluginFactory} = await import('../index.js')
523538
const plugin = getPlugin(unpluginFactory)

0 commit comments

Comments
 (0)