diff --git a/packages/bundler-plugin-core/src/index.ts b/packages/bundler-plugin-core/src/index.ts index 18f3d607..e6028c56 100644 --- a/packages/bundler-plugin-core/src/index.ts +++ b/packages/bundler-plugin-core/src/index.ts @@ -371,6 +371,12 @@ export function createRollupReleaseInjectionHooks(injectionCode: string) { }; } +// We need to be careful not to inject the snippet before any `"use strict";`s. +// As an additional complication `"use strict";`s may come after any number of comments. +const COMMENT_USE_STRICT_REGEX = + // Note: CodeQL complains that this regex potentially has n^2 runtime. This likely won't affect realistic files. + /^(?:\s*|\/\*(?:.|\r|\n)*?\*\/|\/\/.*[\n\r])*(?:"[^"]*";|'[^']*';)?/; + export function createRollupDebugIdInjectionHooks() { return { renderChunk(code: string, chunk: { fileName: string }) { @@ -382,13 +388,7 @@ export function createRollupDebugIdInjectionHooks() { const ms = new MagicString(code, { filename: chunk.fileName }); - // We need to be careful not to inject the snippet before any `"use strict";`s. - // As an additional complication `"use strict";`s may come after any number of comments. - const commentUseStrictRegex = - // Note: CodeQL complains that this regex potentially has n^2 runtime. This likely won't affect realistic files. - /^(?:\s*|\/\*(?:.|\r|\n)*?\*\/|\/\/.*[\n\r])*(?:"[^"]*";|'[^']*';)?/; - - const match = code.match(commentUseStrictRegex)?.[0]; + const match = code.match(COMMENT_USE_STRICT_REGEX)?.[0]; if (match) { // Add injected code after any comments or "use strict" at the beginning of the bundle. @@ -411,6 +411,37 @@ export function createRollupDebugIdInjectionHooks() { }; } +export function createRollupModuleMetadataInjectionHooks(injectionCode: string) { + return { + renderChunk(code: string, chunk: { fileName: string }) { + if ( + [".js", ".mjs", ".cjs"].some((ending) => chunk.fileName.endsWith(ending)) // chunks could be any file (html, md, ...) + ) { + const ms = new MagicString(code, { filename: chunk.fileName }); + + const match = code.match(COMMENT_USE_STRICT_REGEX)?.[0]; + + if (match) { + // Add injected code after any comments or "use strict" at the beginning of the bundle. + ms.appendLeft(match.length, injectionCode); + } else { + // ms.replace() doesn't work when there is an empty string match (which happens if + // there is neither, a comment, nor a "use strict" at the top of the chunk) so we + // need this special case here. + ms.prepend(injectionCode); + } + + return { + code: ms.toString(), + map: ms.generateMap({ file: chunk.fileName }), + }; + } else { + return null; // returning null means not modifying the chunk at all + } + }, + }; +} + export function createRollupDebugIdUploadHooks( upload: (buildArtifacts: string[]) => Promise ) { diff --git a/packages/integration-tests/fixtures/metadata-injection/metadata-injection.test.ts b/packages/integration-tests/fixtures/metadata-injection/metadata-injection.test.ts index 83640d1b..ec1e245a 100644 --- a/packages/integration-tests/fixtures/metadata-injection/metadata-injection.test.ts +++ b/packages/integration-tests/fixtures/metadata-injection/metadata-injection.test.ts @@ -23,4 +23,12 @@ describe("metadata injection", () => { test("webpack 5 bundle", () => { checkBundle(path.join(__dirname, "out", "webpack5", "bundle.js")); }); + + test("rollup bundle", () => { + checkBundle(path.join(__dirname, "out", "rollup", "bundle.js")); + }); + + test("vite bundle", () => { + checkBundle(path.join(__dirname, "out", "vite", "bundle.js")); + }); }); diff --git a/packages/integration-tests/fixtures/metadata-injection/setup.ts b/packages/integration-tests/fixtures/metadata-injection/setup.ts index 1a7fc221..0a7a5e61 100644 --- a/packages/integration-tests/fixtures/metadata-injection/setup.ts +++ b/packages/integration-tests/fixtures/metadata-injection/setup.ts @@ -13,5 +13,5 @@ createCjsBundles( moduleMetadata: { team: "frontend" }, }, }, - ["webpack4", "webpack5"] + ["webpack4", "webpack5", "rollup", "vite"] ); diff --git a/packages/rollup-plugin/src/index.ts b/packages/rollup-plugin/src/index.ts index 8357e5c8..dab98730 100644 --- a/packages/rollup-plugin/src/index.ts +++ b/packages/rollup-plugin/src/index.ts @@ -2,6 +2,7 @@ import { sentryUnpluginFactory, Options, createRollupReleaseInjectionHooks, + createRollupModuleMetadataInjectionHooks, createRollupDebugIdInjectionHooks, createRollupDebugIdUploadHooks, } from "@sentry/bundler-plugin-core"; @@ -21,6 +22,13 @@ function rollupDebugIdInjectionPlugin(): UnpluginOptions { }; } +function rollupModuleMetadataInjectionPlugin(injectionCode: string): UnpluginOptions { + return { + name: "sentry-rollup-module-metadata-injection-plugin", + rollup: createRollupModuleMetadataInjectionHooks(injectionCode), + }; +} + function rollupDebugIdUploadPlugin( upload: (buildArtifacts: string[]) => Promise ): UnpluginOptions { @@ -33,6 +41,7 @@ function rollupDebugIdUploadPlugin( const sentryUnplugin = sentryUnpluginFactory({ releaseInjectionPlugin: rollupReleaseInjectionPlugin, debugIdInjectionPlugin: rollupDebugIdInjectionPlugin, + moduleMetadataInjectionPlugin: rollupModuleMetadataInjectionPlugin, debugIdUploadPlugin: rollupDebugIdUploadPlugin, }); diff --git a/packages/vite-plugin/src/index.ts b/packages/vite-plugin/src/index.ts index 9b41a210..5ee62797 100644 --- a/packages/vite-plugin/src/index.ts +++ b/packages/vite-plugin/src/index.ts @@ -2,6 +2,7 @@ import { sentryUnpluginFactory, Options, createRollupReleaseInjectionHooks, + createRollupModuleMetadataInjectionHooks, createRollupDebugIdInjectionHooks, createRollupDebugIdUploadHooks, } from "@sentry/bundler-plugin-core"; @@ -22,6 +23,13 @@ function viteDebugIdInjectionPlugin(): UnpluginOptions { }; } +function viteModuleMetadataInjectionPlugin(injectionCode: string): UnpluginOptions { + return { + name: "sentry-vite-module-metadata-injection-plugin", + vite: createRollupModuleMetadataInjectionHooks(injectionCode), + }; +} + function viteDebugIdUploadPlugin( upload: (buildArtifacts: string[]) => Promise ): UnpluginOptions { @@ -34,6 +42,7 @@ function viteDebugIdUploadPlugin( const sentryUnplugin = sentryUnpluginFactory({ releaseInjectionPlugin: viteReleaseInjectionPlugin, debugIdInjectionPlugin: viteDebugIdInjectionPlugin, + moduleMetadataInjectionPlugin: viteModuleMetadataInjectionPlugin, debugIdUploadPlugin: viteDebugIdUploadPlugin, });