-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(tanstackstart-react): Auto-instrument global middleware #18844
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
nicohrubec
wants to merge
42
commits into
develop
Choose a base branch
from
nh/automatic-middleware-instrumentation
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+486
−39
Open
Changes from all commits
Commits
Show all changes
42 commits
Select commit
Hold shift + click to select a range
704a781
Add placeholder vite config wrapper
nicohrubec 6cc5784
align usage with solidstart
nicohrubec b4a0d83
Add placeholder to add plugins
nicohrubec b6ddbff
Add sentry vite plugin and enable source maps plugins automatically
nicohrubec 8c6f0fa
?
nicohrubec 207a96a
add unit tests
nicohrubec 53e9099
add vite wrapper to e2e tests
nicohrubec b9c51e9
simplify unit tests
nicohrubec 6eb1c8b
use buildTimeOptionsBase instead of defining my own type
nicohrubec 4dcdabf
Merge branch 'develop' into nh/tss-vite-config-wrapper
nicohrubec 9aaabd9
.
nicohrubec bfa238a
switch to sentry vite plugin
nicohrubec 086b9f6
add changelog entry and pass down all options
nicohrubec 05e08f1
clean
nicohrubec bc0acdd
always add sentry vite plugin and pass down disable option
nicohrubec 8e60de8
Merge branch 'develop' into nh/tss-vite-config-wrapper
nicohrubec 9bbd0b0
readability
nicohrubec 283a545
update tests
nicohrubec 1e736b4
Merge branch 'develop' into nh/tss-vite-config-wrapper
nicohrubec 841a311
bump bundler plugins
nicohrubec 9ad7a8d
update
nicohrubec 286f624
update bundler plugins fr this time
nicohrubec 505c92c
Revert "update bundler plugins fr this time"
nicohrubec 07d5e77
Merge branch 'develop' into nh/tss-vite-config-wrapper
nicohrubec 073e352
Merge branch 'develop' into nh/tss-vite-config-wrapper
nicohrubec 8ce5358
update sentry vite plugin
nicohrubec 76c746c
address some pr comments
nicohrubec bbf7be4
use post for config plugin
nicohrubec 63a6660
fix files to delete after upload settings
nicohrubec c99e1a1
Merge branch 'develop' into nh/tss-vite-config-wrapper
nicohrubec e2bf4b0
make global middleware auto-wrapping work
nicohrubec b7d35ad
update unit tests for sentryTanstackStart
nicohrubec c6d7624
do not transform files with manul middleware wrapping
nicohrubec 8142b20
clean
nicohrubec 463d7f0
clean
nicohrubec 1ed2308
.
nicohrubec 2706bc0
Add changelog entry
nicohrubec bdb9ac5
Merge branch 'develop' into nh/automatic-middleware-instrumentation
nicohrubec a39e88f
handle use directive edge case and improve tests
nicohrubec 00fbbbd
warn users if stuff goes wrong
nicohrubec 993ba3f
deduplicate middleware entries
nicohrubec aa7adc5
yarn fix
nicohrubec File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 4 additions & 3 deletions
7
dev-packages/e2e-tests/test-applications/tanstackstart-react/src/start.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,10 @@ | ||
| import { createStart } from '@tanstack/react-start'; | ||
| import { wrappedGlobalRequestMiddleware, wrappedGlobalFunctionMiddleware } from './middleware'; | ||
| // NOTE: These are NOT wrapped - auto-instrumentation via the Vite plugin will wrap them | ||
| import { globalRequestMiddleware, globalFunctionMiddleware } from './middleware'; | ||
|
|
||
| export const startInstance = createStart(() => { | ||
| return { | ||
| requestMiddleware: [wrappedGlobalRequestMiddleware], | ||
| functionMiddleware: [wrappedGlobalFunctionMiddleware], | ||
| requestMiddleware: [globalRequestMiddleware], | ||
| functionMiddleware: [globalFunctionMiddleware], | ||
| }; | ||
| }); |
116 changes: 116 additions & 0 deletions
116
packages/tanstackstart-react/src/vite/autoInstrumentMiddleware.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| import type { Plugin } from 'vite'; | ||
|
|
||
| type AutoInstrumentMiddlewareOptions = { | ||
| enabled?: boolean; | ||
| debug?: boolean; | ||
| }; | ||
|
|
||
| /** | ||
| * A Vite plugin that automatically instruments TanStack Start middlewares | ||
| * by wrapping `requestMiddleware` and `functionMiddleware` arrays in `createStart()`. | ||
| */ | ||
| export function makeAutoInstrumentMiddlewarePlugin(options: AutoInstrumentMiddlewareOptions = {}): Plugin { | ||
| const { enabled = true, debug = false } = options; | ||
|
|
||
| return { | ||
| name: 'sentry-tanstack-middleware-auto-instrument', | ||
| enforce: 'pre', | ||
|
|
||
| transform(code, id) { | ||
| if (!enabled) { | ||
| return null; | ||
| } | ||
|
|
||
| // Skip if not a TS/JS file | ||
| if (!/\.(ts|tsx|js|jsx|mjs|mts)$/.test(id)) { | ||
| return null; | ||
| } | ||
|
|
||
| // Only wrap requestMiddleware and functionMiddleware in createStart() | ||
| if (!code.includes('createStart')) { | ||
| return null; | ||
| } | ||
|
|
||
| // Skip if the user already did some manual wrapping | ||
| if (code.includes('wrapMiddlewaresWithSentry')) { | ||
| return null; | ||
| } | ||
|
|
||
| let transformed = code; | ||
| let needsImport = false; | ||
| const skippedMiddlewares: string[] = []; | ||
|
|
||
| transformed = transformed.replace( | ||
| /(requestMiddleware|functionMiddleware)\s*:\s*\[([^\]]*)\]/g, | ||
| (match: string, key: string, contents: string) => { | ||
| const objContents = arrayToObjectShorthand(contents); | ||
| if (objContents) { | ||
| needsImport = true; | ||
| if (debug) { | ||
| // eslint-disable-next-line no-console | ||
| console.log(`[Sentry] Auto-wrapping ${key} in ${id}`); | ||
| } | ||
| return `${key}: wrapMiddlewaresWithSentry(${objContents})`; | ||
| } | ||
| // Track middlewares that couldn't be auto-wrapped | ||
| if (contents.trim()) { | ||
| skippedMiddlewares.push(key); | ||
| } | ||
| return match; | ||
| }, | ||
| ); | ||
|
|
||
| // Warn about middlewares that couldn't be auto-wrapped | ||
| if (skippedMiddlewares.length > 0) { | ||
| // eslint-disable-next-line no-console | ||
| console.warn( | ||
| `[Sentry] Could not auto-instrument ${skippedMiddlewares.join(' and ')} in ${id}. ` + | ||
| 'To instrument these middlewares, use wrapMiddlewaresWithSentry() manually. ', | ||
| ); | ||
| } | ||
|
|
||
| if (needsImport) { | ||
| const sentryImport = "import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\n"; | ||
|
|
||
| // Check for 'use server' or 'use client' directive at the start | ||
| const directiveMatch = transformed.match(/^(['"])use (client|server)\1;?\s*\n?/); | ||
| if (directiveMatch) { | ||
| // Insert import after the directive | ||
| const directive = directiveMatch[0]; | ||
| transformed = directive + sentryImport + transformed.slice(directive.length); | ||
| } else { | ||
| transformed = sentryImport + transformed; | ||
| } | ||
nicohrubec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return { code: transformed, map: null }; | ||
| } | ||
|
|
||
| return null; | ||
| }, | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * Convert array contents to object shorthand syntax. | ||
| * e.g., "foo, bar, baz" → "{ foo, bar, baz }" | ||
| * | ||
| * Returns null if contents contain non-identifier expressions (function calls, etc.) | ||
| * which cannot be converted to object shorthand. | ||
| */ | ||
| export function arrayToObjectShorthand(contents: string): string | null { | ||
| const items = contents | ||
| .split(',') | ||
| .map(s => s.trim()) | ||
| .filter(Boolean); | ||
|
|
||
| // Only convert if all items are valid identifiers (no complex expressions) | ||
| const allIdentifiers = items.every(item => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(item)); | ||
| if (!allIdentifiers || items.length === 0) { | ||
| return null; | ||
| } | ||
|
|
||
| // Deduplicate to avoid invalid syntax like { foo, foo } | ||
| const uniqueItems = [...new Set(items)]; | ||
|
|
||
| return `{ ${uniqueItems.join(', ')} }`; | ||
| } | ||
nicohrubec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| export { sentryTanstackStart } from './sentryTanstackStart'; | ||
| export type { SentryTanstackStartOptions } from './sentryTanstackStart'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.