From f2eeb2cffedaf952865b3781e86a5cda8f7d135a Mon Sep 17 00:00:00 2001 From: svelte-triage-bot Date: Wed, 2 Sep 2026 13:13:19 +0000 Subject: [PATCH] fix: exclude relative imports from tracing interception --- .changeset/calm-traces-render.md | 5 +++++ .../docs/30-advanced/68-observability.md | 8 +++++-- packages/kit/test/apps/basics/package.json | 3 ++- .../apps/basics/src/instrumentation.server.js | 21 +++++++++++++++++++ .../src/routes/tracing/async-ssr/+page.svelte | 7 +++++++ .../apps/basics/test/tracing-async.test.js | 11 ++++++++++ pnpm-lock.yaml | 13 ++++++++++++ 7 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 .changeset/calm-traces-render.md create mode 100644 packages/kit/test/apps/basics/src/routes/tracing/async-ssr/+page.svelte create mode 100644 packages/kit/test/apps/basics/test/tracing-async.test.js diff --git a/.changeset/calm-traces-render.md b/.changeset/calm-traces-render.md new file mode 100644 index 000000000000..6f46d8ef8a53 --- /dev/null +++ b/.changeset/calm-traces-render.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: exclude relative imports from tracing interception diff --git a/documentation/docs/30-advanced/68-observability.md b/documentation/docs/30-advanced/68-observability.md index 60033a7c3b42..7a27765a82be 100644 --- a/documentation/docs/30-advanced/68-observability.md +++ b/documentation/docs/30-advanced/68-observability.md @@ -78,7 +78,7 @@ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentation import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; import { register } from 'import-in-the-middle/register-hooks.mjs'; -register(); +register({ shouldInclude: (_url, specifier) => !specifier.startsWith('.') }); const sdk = new NodeSDK({ serviceName: 'test-sveltekit-tracing', @@ -89,6 +89,10 @@ const sdk = new NodeSDK({ sdk.start(); ``` +The `shouldInclude` option limits interception to package imports. It is important to exclude relative +imports, because `import-in-the-middle` does not preserve live bindings when wrapping mutable ESM +exports, which can break bundled application and framework code. + Now, server-side requests will begin generating traces, which you can view in Jaeger's web console at [localhost:16686](http://localhost:16686). > [!NOTE] `import-in-the-middle/register-hooks.mjs` registers the loader via [`module.registerHooks()`](https://nodejs.org/api/module.html#moduleregisterhooksoptions), which runs the hooks synchronously on the application thread. This avoids the inter-thread message channel that the older `module.register()`-based setup required. @@ -106,7 +110,7 @@ Now, server-side requests will begin generating traces, which you can view in Ja > import { register as registerAsync } from 'node:module'; > > if (supportsSyncHooks()) { -> register(); +> register({ shouldInclude: (_url, specifier) => !specifier.startsWith('.') }); > } else { > const { registerOptions } = createAddHookMessageChannel(); > registerAsync('import-in-the-middle/hook.mjs', import.meta.url, registerOptions); diff --git a/packages/kit/test/apps/basics/package.json b/packages/kit/test/apps/basics/package.json index ee230f92f808..2c37c4a0af6b 100644 --- a/packages/kit/test/apps/basics/package.json +++ b/packages/kit/test/apps/basics/package.json @@ -24,12 +24,13 @@ "@opentelemetry/sdk-trace-node": "catalog:", "@sveltejs/kit": "workspace:^", "@sveltejs/vite-plugin-svelte": "catalog:", + "@typescript/native": "catalog:", "@vitest/browser-playwright": "catalog:", + "import-in-the-middle": "3.3.3", "svelte": "catalog:", "svelte-check": "catalog:", "test-redirect-importer": "workspace:*", "typescript": "catalog:", - "@typescript/native": "catalog:", "vite": "catalog:", "vitest": "catalog:" }, diff --git a/packages/kit/test/apps/basics/src/instrumentation.server.js b/packages/kit/test/apps/basics/src/instrumentation.server.js index 35939278b47a..0a4c28d4139a 100644 --- a/packages/kit/test/apps/basics/src/instrumentation.server.js +++ b/packages/kit/test/apps/basics/src/instrumentation.server.js @@ -2,8 +2,29 @@ /** @import {SpanData} from '../../../types' */ import { NodeSDK } from '@opentelemetry/sdk-node'; import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'; +// @ts-expect-error import-in-the-middle does not declare this entry point +import { register, supportsSyncHooks } from 'import-in-the-middle/register-hooks.mjs'; +import { createAddHookMessageChannel } from 'import-in-the-middle'; +import { register as registerAsync } from 'node:module'; import fs from 'node:fs'; +/** + * @param {string} _url + * @param {string} specifier + */ +function should_include(_url, specifier) { + return !specifier.startsWith('.'); +} + +if (process.env.SVELTE_ASYNC === 'true') { + if (supportsSyncHooks()) { + register({ shouldInclude: should_include }); + } else { + const { registerOptions } = createAddHookMessageChannel(); + registerAsync('import-in-the-middle/hook.mjs', import.meta.url, registerOptions); + } +} + /** @implements {SpanExporter} */ class FilesystemSpanExporter { #path; diff --git a/packages/kit/test/apps/basics/src/routes/tracing/async-ssr/+page.svelte b/packages/kit/test/apps/basics/src/routes/tracing/async-ssr/+page.svelte new file mode 100644 index 000000000000..c910486d2ec2 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/tracing/async-ssr/+page.svelte @@ -0,0 +1,7 @@ + + +

rendered

diff --git a/packages/kit/test/apps/basics/test/tracing-async.test.js b/packages/kit/test/apps/basics/test/tracing-async.test.js new file mode 100644 index 000000000000..e1d828e8703b --- /dev/null +++ b/packages/kit/test/apps/basics/test/tracing-async.test.js @@ -0,0 +1,11 @@ +import process from 'node:process'; +import { expect } from '@playwright/test'; +import { test } from '../../../utils.js'; + +test('SSR works with import interception and experimental async', async ({ request }) => { + test.skip(!!process.env.DEV || process.env.SVELTE_ASYNC !== 'true'); + + const response = await request.get('/tracing/async-ssr'); + expect(response.status()).toBe(200); + expect(await response.text()).toContain('

rendered

'); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a998047bea12..4103f4e9be00 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -879,6 +879,9 @@ importers: '@vitest/browser-playwright': specifier: 'catalog:' version: 4.1.10(playwright@1.62.1)(vite@8.2.1(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.4.2)(yaml@2.9.0))(vitest@4.1.10) + import-in-the-middle: + specifier: 3.3.3 + version: 3.3.3 svelte: specifier: 'catalog:' version: 5.56.8(@typescript-eslint/types@8.61.1) @@ -3838,6 +3841,10 @@ packages: resolution: {integrity: sha512-OnGy+eYT7wVejH2XWgLRgbmzujhhVIATQH0ztIeRilwHBjTeG3pD+XnH3PKX0r9gJ0BuJmJ68q/oh9qgXnNDQg==} engines: {node: '>=18'} + import-in-the-middle@3.3.3: + resolution: {integrity: sha512-AiohS3H80sXO6owEltjGX+glb7qXaDhBoJb9XcQVH4UI207xu/bDLUcadVKp7Qe576reg9yr/PXZjV5qx8gfbA==} + engines: {node: '>=18'} + import-meta-resolve@4.2.0: resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} @@ -6495,6 +6502,12 @@ snapshots: cjs-module-lexer: 2.2.0 module-details-from-path: 1.0.4 + import-in-the-middle@3.3.3: + dependencies: + cjs-module-lexer: 2.2.0 + es-module-lexer: 2.3.1 + module-details-from-path: 1.0.4 + import-meta-resolve@4.2.0: {} imurmurhash@0.1.4: {}