@@ -3,19 +3,17 @@ import {
33 createSentryBuildPluginManager ,
44 generateReleaseInjectorCode ,
55 generateModuleMetadataInjectorCode ,
6- stringToUUID ,
76 createComponentNameAnnotateHooks ,
87 CodeInjection ,
9- getDebugIdSnippet ,
108 createDebugIdUploadFunction ,
119 isJsFile ,
1210 stampDebugId ,
1311} from '../core/index' ;
14- import { getCodeInjectionPosition } from '../core/get-code-injection-position' ;
12+ import { addCodeInjection } from './webpack-code-injection' ;
13+ import type { WebpackCodeInjectionCompiler } from './webpack-code-injection' ;
1514import * as path from 'node:path' ;
1615import { fileURLToPath } from 'node:url' ;
1716import { createRequire } from 'node:module' ;
18- import { randomUUID } from 'node:crypto' ;
1917
2018const _req = createRequire ( import . meta. url ) ;
2119
@@ -54,37 +52,13 @@ type WebpackSources = {
5452 RawSource ?: WebpackRawSource ;
5553} ;
5654
57- type WebpackModule = {
58- resource ?: string ;
59- } ;
60-
61- type WebpackLoaderCallback = ( err : Error | null , content ?: string , sourceMap ?: unknown ) => void ;
62-
63- type WebpackLoaderContext = {
64- callback : WebpackLoaderCallback ;
65- } ;
66-
6755type WebpackCompilationContext = {
6856 chunks : Iterable < {
6957 files : Iterable < string > ;
7058 hash ?: string ;
7159 contentHash ?: { javascript ?: string } ;
7260 } > ;
73- compiler : {
74- webpack ?: {
75- NormalModule ?: {
76- getCompilationHooks : ( compilation : WebpackCompilationContext ) => {
77- loader : {
78- tap : ( name : string , callback : ( loaderContext : WebpackLoaderContext , module : WebpackModule ) => void ) => void ;
79- } ;
80- } ;
81- } ;
82- } ;
83- } ;
8461 hooks : {
85- normalModuleLoader ?: {
86- tap : ( name : string , callback : ( loaderContext : WebpackLoaderContext , module : WebpackModule ) => void ) => void ;
87- } ;
8862 processAssets : {
8963 tap : (
9064 options : { name : string ; stage : number } ,
@@ -113,13 +87,9 @@ type WebpackRawSource = {
11387 new ( source : string ) : WebpackSource ;
11488} ;
11589
116- type WebpackReplaceSource = WebpackSource & {
117- insert : ( position : number , value : string ) => void ;
118- } ;
119-
120- const WEBPACK_JAVASCRIPT_ASSET_REGEX = / \. (?: j s | t s | j s x | t s x | m j s | c j s | m t s | c t s ) (?: \? [ ^ ? ] * ) ? (?: # [ ^ # ] * ) ? $ / ;
90+ type WebpackReplaceSource = WebpackSource & { insert : ( position : number , value : string ) => void } ;
12191
122- type WebpackCompiler = {
92+ type WebpackCompiler = WebpackCodeInjectionCompiler & {
12393 options : {
12494 plugins ?: unknown [ ] ;
12595 mode ?: string ;
@@ -282,59 +252,13 @@ export function sentryWebpackPluginFactory({
282252 const DefinePlugin = compiler ?. webpack ?. DefinePlugin || UnsafeDefinePlugin ;
283253
284254 // Injecting through BannerPlugin would place executable code before directive prologues.
285- if ( ! staticInjectionCode . isEmpty ( ) || sourcemapsEnabled ) {
286- const ReplaceSource = compiler . webpack ?. sources ?. ReplaceSource || unsafeSources ?. ReplaceSource ;
287- const processAssetsStage =
288- compiler . webpack ?. Compilation ?. PROCESS_ASSETS_STAGE_ADDITIONS ??
289- UnsafeCompilation ?. PROCESS_ASSETS_STAGE_ADDITIONS ;
290-
291- if ( ! ReplaceSource || processAssetsStage === undefined ) {
292- logger . warn (
293- 'Webpack sources are not available. Skipping code injection. This usually means webpack is not properly configured.' ,
294- ) ;
295- } else {
296- compiler . hooks . thisCompilation . tap ( 'sentry-webpack-plugin-injection' , compilation => {
297- compilation . hooks . processAssets . tap (
298- {
299- name : 'sentry-webpack-plugin-injection' ,
300- stage : processAssetsStage ,
301- } ,
302- assets => {
303- for ( const chunk of compilation . chunks ) {
304- for ( const assetName of chunk . files ) {
305- if ( ! WEBPACK_JAVASCRIPT_ASSET_REGEX . test ( assetName ) ) {
306- continue ;
307- }
308-
309- const source = assets [ assetName ] ;
310- if ( ! source ) {
311- continue ;
312- }
313-
314- const sourceContents = source . source ( ) ;
315- const codeString =
316- typeof sourceContents === 'string' ? sourceContents : Buffer . from ( sourceContents ) . toString ( ) ;
317- const codeToInject = staticInjectionCode . clone ( ) ;
318- if ( sourcemapsEnabled ) {
319- const hash = chunk . contentHash ?. javascript ?? chunk . hash ;
320- codeToInject . append ( getDebugIdSnippet ( hash ? stringToUUID ( hash ) : randomUUID ( ) ) ) ;
321- }
322-
323- const injectionPosition = getCodeInjectionPosition ( codeString ) ;
324- const injection =
325- injectionPosition === codeString . length
326- ? `\n${ codeToInject . code ( ) } `
327- : `${ codeToInject . code ( ) } \n` ;
328- const updatedSource = new ReplaceSource ( source ) ;
329- updatedSource . insert ( injectionPosition , injection ) ;
330- compilation . updateAsset ( assetName , updatedSource ) ;
331- }
332- }
333- } ,
334- ) ;
335- } ) ;
336- }
337- }
255+ addCodeInjection (
256+ compiler ,
257+ { Compilation : UnsafeCompilation , sources : unsafeSources } ,
258+ staticInjectionCode ,
259+ sourcemapsEnabled ,
260+ logger ,
261+ ) ;
338262
339263 // The upload routine (which stamps debug IDs into temp copies of the artifacts) is skipped
340264 // with `disable-upload`, so the emitted artifacts get stamped in the asset pipeline instead.
0 commit comments