diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c87ef1782865..42ebcf71a681 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -896,7 +896,7 @@ jobs: yarn test job_remix_integration_tests: - name: Remix v${{ matrix.remix }} (Node ${{ matrix.node }}) Tests + name: Remix v${{ matrix.remix }} (Node ${{ matrix.node }}) ${{ matrix.tracingIntegration && 'TracingIntegration'}} Tests needs: [job_get_metadata, job_build] if: needs.job_get_metadata.outputs.changed_remix == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-20.04 @@ -912,6 +912,8 @@ jobs: remix: 1 - node: 16 remix: 1 + - tracingIntegration: true + remix: 2 steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v4 @@ -929,6 +931,7 @@ jobs: env: NODE_VERSION: ${{ matrix.node }} REMIX_VERSION: ${{ matrix.remix }} + TRACING_INTEGRATION: ${{ matrix.tracingIntegration }} run: | cd packages/remix yarn test:integration:ci diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/remix.config.js b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/remix.config.js index cb3c8c7a9fb7..92ed1ddc32eb 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/remix.config.js +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/remix.config.js @@ -6,4 +6,5 @@ module.exports = { // serverBuildPath: 'build/index.js', // publicPath: '/build/', serverModuleFormat: 'cjs', + entry, }; diff --git a/packages/remix/README.md b/packages/remix/README.md index c51820980e91..ae2dfbeff53a 100644 --- a/packages/remix/README.md +++ b/packages/remix/README.md @@ -12,27 +12,26 @@ ## General -This package is a wrapper around `@sentry/node` for the server and `@sentry/react` for the client, with added functionality related to Remix. +This package is a wrapper around `@sentry/node` for the server and `@sentry/react` for the client, with added +functionality related to Remix. To use this SDK, initialize Sentry in your Remix entry points for both the client and server. ```ts // entry.client.tsx -import { useLocation, useMatches } from "@remix-run/react"; -import * as Sentry from "@sentry/remix"; -import { useEffect } from "react"; +import { useLocation, useMatches } from '@remix-run/react'; +import * as Sentry from '@sentry/remix'; +import { useEffect } from 'react'; Sentry.init({ - dsn: "__DSN__", + dsn: '__DSN__', tracesSampleRate: 1, integrations: [ - new Sentry.BrowserTracing({ - routingInstrumentation: Sentry.remixRouterInstrumentation( - useEffect, - useLocation, - useMatches, - ), + Sentry.browserTracingIntegration({ + useEffect, + useLocation, + useMatches, }), ], // ... @@ -42,19 +41,20 @@ Sentry.init({ ```ts // entry.server.tsx -import { prisma } from "~/db.server"; +import { prisma } from '~/db.server'; -import * as Sentry from "@sentry/remix"; +import * as Sentry from '@sentry/remix'; Sentry.init({ - dsn: "__DSN__", + dsn: '__DSN__', tracesSampleRate: 1, integrations: [new Sentry.Integrations.Prisma({ client: prisma })], // ... }); ``` -Also, wrap your Remix root with `withSentry` to catch React component errors and to get parameterized router transactions. +Also, wrap your Remix root with `withSentry` to catch React component errors and to get parameterized router +transactions. ```ts // root.tsx @@ -139,8 +139,11 @@ Sentry.captureEvent({ ## Sourcemaps and Releases -The Remix SDK provides a script that automatically creates a release and uploads sourcemaps. To generate sourcemaps with Remix, you need to call `remix build` with the `--sourcemap` option. +The Remix SDK provides a script that automatically creates a release and uploads sourcemaps. To generate sourcemaps with +Remix, you need to call `remix build` with the `--sourcemap` option. -On release, call `sentry-upload-sourcemaps` to upload source maps and create a release. To see more details on how to use the command, call `sentry-upload-sourcemaps --help`. +On release, call `sentry-upload-sourcemaps` to upload source maps and create a release. To see more details on how to +use the command, call `sentry-upload-sourcemaps --help`. -For more advanced configuration, [directly use `sentry-cli` to upload source maps.](https://github.com/getsentry/sentry-cli). +For more advanced configuration, +[directly use `sentry-cli` to upload source maps.](https://github.com/getsentry/sentry-cli). diff --git a/packages/remix/package.json b/packages/remix/package.json index b9e22128ece4..2133813e857a 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -70,11 +70,12 @@ "fix": "eslint . --format stylish --fix", "lint": "eslint . --format stylish", "test": "yarn test:unit", - "test:integration": "run-s test:integration:v1 test:integration:v2", + "test:integration": "run-s test:integration:v1 test:integration:v2 test:integration:tracingIntegration", "test:integration:v1": "run-s test:integration:clean test:integration:prepare test:integration:client test:integration:server", "test:integration:v2": "export REMIX_VERSION=2 && run-s test:integration:v1", + "test:integration:tracingIntegration": "export TRACING_INTEGRATION=true && run-s test:integration:v2", "test:integration:ci": "run-s test:integration:clean test:integration:prepare test:integration:client:ci test:integration:server", - "test:integration:prepare": "(cd test/integration && yarn)", + "test:integration:prepare": "(cd test/integration && yarn install)", "test:integration:clean": "(cd test/integration && rimraf .cache node_modules build)", "test:integration:client": "yarn playwright install-deps && yarn playwright test test/integration/test/client/ --project='chromium'", "test:integration:client:ci": "yarn test:integration:client --reporter='line'", diff --git a/packages/remix/src/client/browserTracingIntegration.ts b/packages/remix/src/client/browserTracingIntegration.ts new file mode 100644 index 000000000000..c0eb1a97148d --- /dev/null +++ b/packages/remix/src/client/browserTracingIntegration.ts @@ -0,0 +1,41 @@ +import { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/react'; +import type { Integration } from '@sentry/types'; +import { setGlobals, startPageloadSpan } from './performance'; +import type { RemixBrowserTracingIntegrationOptions } from './performance'; +/** + * Creates a browser tracing integration for Remix applications. + * This integration will create pageload and navigation spans. + */ +export function browserTracingIntegration(options: RemixBrowserTracingIntegrationOptions): Integration { + if (options.instrumentPageLoad === undefined) { + options.instrumentPageLoad = true; + } + + if (options.instrumentNavigation === undefined) { + options.instrumentNavigation = true; + } + + setGlobals({ + useEffect: options.useEffect, + useLocation: options.useLocation, + useMatches: options.useMatches, + instrumentNavigation: options.instrumentNavigation, + }); + + const browserTracingIntegrationInstance = originalBrowserTracingIntegration({ + ...options, + instrumentPageLoad: false, + instrumentNavigation: false, + }); + + return { + ...browserTracingIntegrationInstance, + afterAllSetup(client) { + browserTracingIntegrationInstance.afterAllSetup(client); + + if (options.instrumentPageLoad) { + startPageloadSpan(); + } + }, + }; +} diff --git a/packages/remix/src/client/performance.tsx b/packages/remix/src/client/performance.tsx index fc395e8ddedc..10e91837149d 100644 --- a/packages/remix/src/client/performance.tsx +++ b/packages/remix/src/client/performance.tsx @@ -1,46 +1,58 @@ -import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core'; -import type { ErrorBoundaryProps } from '@sentry/react'; -import { WINDOW, withErrorBoundary } from '@sentry/react'; -import type { Transaction, TransactionContext } from '@sentry/types'; +import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getActiveSpan, getRootSpan } from '@sentry/core'; +import type { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/react'; +import type { BrowserClient, ErrorBoundaryProps } from '@sentry/react'; +import { + WINDOW, + getClient, + startBrowserTracingNavigationSpan, + startBrowserTracingPageLoadSpan, + withErrorBoundary, +} from '@sentry/react'; +import type { Span, StartSpanOptions, Transaction, TransactionContext } from '@sentry/types'; import { isNodeEnv, logger } from '@sentry/utils'; import * as React from 'react'; import { DEBUG_BUILD } from '../utils/debug-build'; import { getFutureFlagsBrowser, readRemixVersionFromLoader } from '../utils/futureFlags'; -const DEFAULT_TAGS = { - 'routing.instrumentation': 'remix-router', -} as const; - -type Params = { +export type Params = { readonly [key in Key]: string | undefined; }; -interface RouteMatch { +export interface RouteMatch { params: Params; pathname: string; id: string; handle: unknown; } +export type UseEffect = (cb: () => void, deps: unknown[]) => void; -type UseEffect = (cb: () => void, deps: unknown[]) => void; -type UseLocation = () => { +export type UseLocation = () => { pathname: string; search?: string; hash?: string; state?: unknown; key?: unknown; }; -type UseMatches = () => RouteMatch[] | null; -let activeTransaction: Transaction | undefined; +export type UseMatches = () => RouteMatch[] | null; + +export type RemixBrowserTracingIntegrationOptions = Partial[0]> & { + useEffect?: UseEffect; + useLocation?: UseLocation; + useMatches?: UseMatches; +}; + +const DEFAULT_TAGS = { + 'routing.instrumentation': 'remix-router', +} as const; -let _useEffect: UseEffect; -let _useLocation: UseLocation; -let _useMatches: UseMatches; +let _useEffect: UseEffect | undefined; +let _useLocation: UseLocation | undefined; +let _useMatches: UseMatches | undefined; -let _customStartTransaction: (context: TransactionContext) => Transaction | undefined; -let _startTransactionOnLocationChange: boolean; +let _customStartTransaction: ((context: TransactionContext) => Span | undefined) | undefined; +let _instrumentNavigation: boolean | undefined; function getInitPathName(): string | undefined { if (WINDOW && WINDOW.location) { @@ -54,7 +66,65 @@ function isRemixV2(remixVersion: number | undefined): boolean { return remixVersion === 2 || getFutureFlagsBrowser()?.v2_errorBoundary || false; } +export function startPageloadSpan(): void { + const initPathName = getInitPathName(); + + if (!initPathName) { + return; + } + + const spanContext: StartSpanOptions = { + name: initPathName, + op: 'pageload', + origin: 'auto.pageload.remix', + tags: DEFAULT_TAGS, + metadata: { + source: 'url', + }, + }; + + // If _customStartTransaction is not defined, we know that we are using the browserTracingIntegration + if (!_customStartTransaction) { + const client = getClient(); + + if (!client) { + return; + } + + startBrowserTracingPageLoadSpan(client, spanContext); + } else { + _customStartTransaction(spanContext); + } +} + +function startNavigationSpan(matches: RouteMatch[]): void { + const spanContext: StartSpanOptions = { + name: matches[matches.length - 1].id, + op: 'navigation', + origin: 'auto.navigation.remix', + tags: DEFAULT_TAGS, + metadata: { + source: 'route', + }, + }; + + // If _customStartTransaction is not defined, we know that we are using the browserTracingIntegration + if (!_customStartTransaction) { + const client = getClient(); + + if (!client) { + return; + } + + startBrowserTracingNavigationSpan(client, spanContext); + } else { + _customStartTransaction(spanContext); + } +} + /** + * @deprecated Use `browserTracingIntegration` instead. + * * Creates a react-router v6 instrumention for Remix applications. * * This implementation is slightly different (and simpler) from the react-router instrumentation @@ -66,25 +136,17 @@ export function remixRouterInstrumentation(useEffect: UseEffect, useLocation: Us startTransactionOnPageLoad = true, startTransactionOnLocationChange = true, ): void => { - const initPathName = getInitPathName(); - if (startTransactionOnPageLoad && initPathName) { - activeTransaction = customStartTransaction({ - name: initPathName, - op: 'pageload', - origin: 'auto.pageload.remix', - tags: DEFAULT_TAGS, - metadata: { - source: 'url', - }, - }); - } - - _useEffect = useEffect; - _useLocation = useLocation; - _useMatches = useMatches; + setGlobals({ + useEffect, + useLocation, + useMatches, + instrumentNavigation: startTransactionOnLocationChange, + customStartTransaction, + }); - _customStartTransaction = customStartTransaction; - _startTransactionOnLocationChange = startTransactionOnLocationChange; + if (startTransactionOnPageLoad) { + startPageloadSpan(); + } }; } @@ -109,7 +171,7 @@ export function withSentry

, R extends React.Co ): R { const SentryRoot: React.FC

= (props: P) => { // Early return when any of the required functions is not available. - if (!_useEffect || !_useLocation || !_useMatches || !_customStartTransaction) { + if (!_useEffect || !_useLocation || !_useMatches) { DEBUG_BUILD && !isNodeEnv() && logger.warn('Remix SDK was unable to wrap your root because of one or more missing parameters.'); @@ -125,37 +187,37 @@ export function withSentry

, R extends React.Co const matches = _useMatches(); _useEffect(() => { - if (activeTransaction && matches && matches.length) { - activeTransaction.updateName(matches[matches.length - 1].id); - activeTransaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route'); + const activeRootSpan = getActiveSpan(); + + if (activeRootSpan && matches && matches.length) { + const transaction = getRootSpan(activeRootSpan); + + if (transaction) { + transaction.updateName(matches[matches.length - 1].id); + transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route'); + } } isBaseLocation = true; }, []); _useEffect(() => { + const activeRootSpan = getActiveSpan(); + if (isBaseLocation) { - if (activeTransaction) { - activeTransaction.end(); + if (activeRootSpan) { + activeRootSpan.end(); } return; } - if (_startTransactionOnLocationChange && matches && matches.length) { - if (activeTransaction) { - activeTransaction.end(); + if (_instrumentNavigation && matches && matches.length) { + if (activeRootSpan) { + activeRootSpan.end(); } - activeTransaction = _customStartTransaction({ - name: matches[matches.length - 1].id, - op: 'navigation', - origin: 'auto.navigation.remix', - tags: DEFAULT_TAGS, - metadata: { - source: 'route', - }, - }); + startNavigationSpan(matches); } }, [location]); @@ -175,3 +237,23 @@ export function withSentry

, R extends React.Co // will break advanced type inference done by react router params return SentryRoot; } + +export function setGlobals({ + useEffect, + useLocation, + useMatches, + instrumentNavigation, + customStartTransaction, +}: { + useEffect?: UseEffect; + useLocation?: UseLocation; + useMatches?: UseMatches; + instrumentNavigation?: boolean; + customStartTransaction?: (context: TransactionContext) => Span | undefined; +}): void { + _useEffect = useEffect; + _useLocation = useLocation; + _useMatches = useMatches; + _instrumentNavigation = instrumentNavigation; + _customStartTransaction = customStartTransaction; +} diff --git a/packages/remix/src/index.client.tsx b/packages/remix/src/index.client.tsx index 9c619ff1d851..3842e9a3701d 100644 --- a/packages/remix/src/index.client.tsx +++ b/packages/remix/src/index.client.tsx @@ -1,16 +1,26 @@ import { applySdkMetadata } from '@sentry/core'; import { getCurrentScope, init as reactInit } from '@sentry/react'; - import type { RemixOptions } from './utils/remixOptions'; -export { remixRouterInstrumentation, withSentry } from './client/performance'; export { captureRemixErrorBoundaryError } from './client/errors'; +export { + // eslint-disable-next-line deprecation/deprecation + remixRouterInstrumentation, + withSentry, +} from './client/performance'; + +export { browserTracingIntegration } from './client/browserTracingIntegration'; + export * from '@sentry/react'; export function init(options: RemixOptions): void { - applySdkMetadata(options, 'remix', ['remix', 'react']); - options.environment = options.environment || process.env.NODE_ENV; + const opts = { + ...options, + environment: options.environment || process.env.NODE_ENV, + }; + + applySdkMetadata(opts, 'remix', ['remix', 'react']); - reactInit(options); + reactInit(opts); getCurrentScope().setTag('runtime', 'browser'); } diff --git a/packages/remix/src/index.server.ts b/packages/remix/src/index.server.ts index 674beed61ee6..a34250100287 100644 --- a/packages/remix/src/index.server.ts +++ b/packages/remix/src/index.server.ts @@ -111,8 +111,10 @@ export * from '@sentry/node'; export { captureRemixServerException, wrapRemixHandleError } from './utils/instrumentServer'; export { ErrorBoundary, withErrorBoundary } from '@sentry/react'; +// eslint-disable-next-line deprecation/deprecation export { remixRouterInstrumentation, withSentry } from './client/performance'; export { captureRemixErrorBoundaryError } from './client/errors'; +export { browserTracingIntegration } from './client/browserTracingIntegration'; export { wrapExpressCreateRequestHandler } from './utils/serverAdapters/express'; export type { SentryMetaArgs } from './utils/types'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/entry.client.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/entry.client.tsx new file mode 100644 index 000000000000..7273433127ac --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/entry.client.tsx @@ -0,0 +1,12 @@ +import { RemixBrowser, useLocation, useMatches } from '@remix-run/react'; +import * as Sentry from '@sentry/remix'; +import { useEffect } from 'react'; +import { hydrate } from 'react-dom'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + tracesSampleRate: 1, + integrations: [Sentry.browserTracingIntegration({ useEffect, useLocation, useMatches })], +}); + +hydrate(, document); diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/entry.server.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/entry.server.tsx new file mode 100644 index 000000000000..bba366801092 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/entry.server.tsx @@ -0,0 +1,30 @@ +import type { EntryContext } from '@remix-run/node'; +import { RemixServer } from '@remix-run/react'; +import * as Sentry from '@sentry/remix'; +import { renderToString } from 'react-dom/server'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + tracesSampleRate: 1, + tracePropagationTargets: ['example.org'], + // Disabling to test series of envelopes deterministically. + autoSessionTracking: false, +}); + +export const handleError = Sentry.wrapRemixHandleError; + +export default function handleRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, +) { + let markup = renderToString(); + + responseHeaders.set('Content-Type', 'text/html'); + + return new Response('' + markup, { + status: responseStatusCode, + headers: responseHeaders, + }); +} diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/root.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/root.tsx new file mode 100644 index 000000000000..15b78b8a6325 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/root.tsx @@ -0,0 +1,73 @@ +import { LoaderFunction, V2_MetaFunction, defer, json, redirect } from '@remix-run/node'; +import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration, useRouteError } from '@remix-run/react'; +import { V2_ErrorBoundaryComponent } from '@remix-run/react/dist/routeModules'; +import { captureRemixErrorBoundaryError, withSentry } from '@sentry/remix'; + +export const ErrorBoundary: V2_ErrorBoundaryComponent = () => { + const error = useRouteError(); + + captureRemixErrorBoundaryError(error); + + return

error
; +}; + +export const meta: V2_MetaFunction = ({ data }) => [ + { charset: 'utf-8' }, + { title: 'New Remix App' }, + { name: 'viewport', content: 'width=device-width,initial-scale=1' }, + { name: 'sentry-trace', content: data.sentryTrace }, + { name: 'baggage', content: data.sentryBaggage }, +]; + +export const loader: LoaderFunction = async ({ request }) => { + const url = new URL(request.url); + const type = url.searchParams.get('type'); + + switch (type) { + case 'empty': + return {}; + case 'plain': + return { + data_one: [], + data_two: 'a string', + }; + case 'json': + return json({ data_one: [], data_two: 'a string' }, { headers: { 'Cache-Control': 'max-age=300' } }); + case 'defer': + return defer({ data_one: [], data_two: 'a string' }); + case 'null': + return null; + case 'undefined': + return undefined; + case 'throwRedirect': + throw redirect('/?type=plain'); + case 'returnRedirect': + return redirect('/?type=plain'); + case 'throwRedirectToExternal': + throw redirect('https://example.com'); + case 'returnRedirectToExternal': + return redirect('https://example.com'); + default: { + return {}; + } + } +}; + +function App() { + return ( + + + + + + + + + + + + + ); +} + +export default withSentry(App); diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/action-json-response.$id.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/action-json-response.$id.tsx new file mode 100644 index 000000000000..7a00bfb2bfe7 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/action-json-response.$id.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/action-json-response.$id'; +export { default } from '../../common/routes/action-json-response.$id'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/capture-exception.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/capture-exception.tsx new file mode 100644 index 000000000000..1ba745d2e63d --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/capture-exception.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/capture-exception'; +export { default } from '../../common/routes/capture-exception'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/capture-message.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/capture-message.tsx new file mode 100644 index 000000000000..9dae2318cc14 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/capture-message.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/capture-message'; +export { default } from '../../common/routes/capture-message'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/error-boundary-capture.$id.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/error-boundary-capture.$id.tsx new file mode 100644 index 000000000000..011f92462069 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/error-boundary-capture.$id.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/error-boundary-capture.$id'; +export { default } from '../../common/routes/error-boundary-capture.$id'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/index.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/index.tsx new file mode 100644 index 000000000000..22c086a4c2cf --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/index.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/index'; +export { default } from '../../common/routes/index'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/loader-defer-response.$id.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/loader-defer-response.$id.tsx new file mode 100644 index 000000000000..69499e594ccc --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/loader-defer-response.$id.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/loader-defer-response.$id'; +export { default } from '../../common/routes/loader-defer-response.$id'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/loader-json-response.$id.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/loader-json-response.$id.tsx new file mode 100644 index 000000000000..7761875bdb76 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/loader-json-response.$id.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/loader-json-response.$id'; +export { default } from '../../common/routes/loader-json-response.$id'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/loader-throw-response.$id.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/loader-throw-response.$id.tsx new file mode 100644 index 000000000000..6b9a6a85cbef --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/loader-throw-response.$id.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/loader-throw-response.$id'; +export { default } from '../../common/routes/loader-throw-response.$id'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/manual-tracing.$id.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/manual-tracing.$id.tsx new file mode 100644 index 000000000000..a7cfebe4ed46 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/manual-tracing.$id.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/manual-tracing.$id'; +export { default } from '../../common/routes/manual-tracing.$id'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/scope-bleed.$id.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/scope-bleed.$id.tsx new file mode 100644 index 000000000000..5ba2376f0339 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/scope-bleed.$id.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/scope-bleed.$id'; +export { default } from '../../common/routes/scope-bleed.$id'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/server-side-unexpected-errors.$id.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/server-side-unexpected-errors.$id.tsx new file mode 100644 index 000000000000..d9571c68ddd5 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/server-side-unexpected-errors.$id.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/server-side-unexpected-errors.$id'; +export { default } from '../../common/routes/server-side-unexpected-errors.$id'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/ssr-error.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/ssr-error.tsx new file mode 100644 index 000000000000..627f7e126871 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/ssr-error.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/ssr-error'; +export { default } from '../../common/routes/ssr-error'; diff --git a/packages/remix/test/integration/app_v2_tracingIntegration/routes/throw-redirect.tsx b/packages/remix/test/integration/app_v2_tracingIntegration/routes/throw-redirect.tsx new file mode 100644 index 000000000000..4425f3432b58 --- /dev/null +++ b/packages/remix/test/integration/app_v2_tracingIntegration/routes/throw-redirect.tsx @@ -0,0 +1,2 @@ +export * from '../../common/routes/throw-redirect'; +export { default } from '../../common/routes/throw-redirect'; diff --git a/packages/remix/test/integration/remix.config.js b/packages/remix/test/integration/remix.config.js index b4c7ac0837b8..418d3690f696 100644 --- a/packages/remix/test/integration/remix.config.js +++ b/packages/remix/test/integration/remix.config.js @@ -1,8 +1,9 @@ /** @type {import('@remix-run/dev').AppConfig} */ const useV2 = process.env.REMIX_VERSION === '2'; +const useBrowserTracing = process.env.TRACING_INTEGRATION === 'true'; module.exports = { - appDirectory: useV2 ? 'app_v2' : 'app_v1', + appDirectory: useBrowserTracing ? 'app_v2_tracingIntegration' : useV2 ? 'app_v2' : 'app_v1', assetsBuildDirectory: 'public/build', serverBuildPath: 'build/index.js', publicPath: '/build/',