@@ -7,8 +7,8 @@ const Preload = require('./Preload');
77const { noHeadException } = require ( './Messages/Exception' ) ;
88
99/** @typedef {import('webpack').Compilation } Compilation */
10- /** @typedef {import(" webpack/lib/Entrypoint" ) } Entrypoint */
11- /** @typedef {import(" webpack/lib/ChunkGroup" ) } ChunkGroup */
10+ /** @typedef {import(' webpack/lib/Entrypoint' ) } Entrypoint */
11+ /** @typedef {import(' webpack/lib/ChunkGroup' ) } ChunkGroup */
1212
1313/**
1414 * @typedef {Object } CollectionData
@@ -57,6 +57,10 @@ class Collection {
5757 /** @type {Dependency } */
5858 dependency = null ;
5959
60+ /**
61+ * Map of assets by source file.
62+ * @type {Map<string, any> }
63+ */
6064 assets = new Map ( ) ;
6165
6266 /** @type {Map<string, {entry: AssetEntryOptions, assets: Array<{}>} > } Entries data */
@@ -913,10 +917,15 @@ class Collection {
913917 return Promise . resolve ( ) ;
914918 }
915919
920+ /**
921+ * Map of assets by output file.
922+ * @type {Map<string, any> }
923+ */
924+ const assetsCache = new Map ( ) ;
925+
916926 const entryDirname = path . dirname ( entryFilename ) ;
917927 const importedStyles = [ ] ;
918928 const parseOptions = new Map ( ) ;
919- const assetIntegrity = new Map ( ) ;
920929 let hasInlineSvg = false ;
921930 let content = rawSource . source ( ) ;
922931
@@ -1004,35 +1013,40 @@ class Collection {
10041013
10051014 const assetContent = compilation . assets [ pathname ] . source ( ) ;
10061015 asset . integrity = Integrity . getIntegrity ( compilation , assetContent , pathname ) ;
1007- assetIntegrity . set ( asset . assetFile , asset . integrity ) ;
1016+ assetsCache . set ( asset . assetFile , asset ) ;
10081017
10091018 if ( ! parseOptions . has ( type ) ) {
10101019 parseOptions . set ( type , {
10111020 tag : 'link' ,
10121021 attributes : [ 'href' ] ,
1013- filter : ( { attribute, attributes } ) =>
1014- ! attributes . hasOwnProperty ( 'integrity' ) &&
1015- attribute === 'href' &&
1016- attributes . rel === 'stylesheet' ,
1022+ // disable ignoring tags already containing integrity attribute
1023+ // filter: ({ attribute, attributes }) =>
1024+ // !attributes.hasOwnProperty('integrity') &&
1025+ // attribute === 'href' &&
1026+ // attributes.rel === 'stylesheet',
10171027 } ) ;
10181028 }
10191029 }
10201030 break ;
10211031 case Collection . type . script :
10221032 // 1.2 compute JS integrity
10231033 if ( hasIntegrity ) {
1024- for ( const chunk of asset . chunks ) {
1034+ // combine sync and async (dynamic imported) chunks into one array
1035+ const chunks = [ ...asset . chunks , ...asset . children ] ;
1036+
1037+ // sync chunks
1038+ for ( const chunk of chunks ) {
10251039 if ( ! chunk . inline ) {
10261040 const assetContent = compilation . assets [ chunk . chunkFile ] . source ( ) ;
10271041 chunk . integrity = Integrity . getIntegrity ( compilation , assetContent , chunk . chunkFile ) ;
1028- assetIntegrity . set ( chunk . assetFile , chunk . integrity ) ;
1042+ assetsCache . set ( chunk . assetFile , chunk ) ;
10291043
10301044 if ( ! parseOptions . has ( type ) ) {
10311045 parseOptions . set ( type , {
10321046 tag : 'script' ,
10331047 attributes : [ 'src' ] ,
1034- filter : ( { attribute , attributes } ) =>
1035- ! attributes . hasOwnProperty ( 'integrity' ) && attribute === 'src' ,
1048+ // disable ignoring tags already containing integrity attribute
1049+ // filter: ({ attribute, attributes }) => !attributes.hasOwnProperty('integrity') && attribute === 'src',
10361050 } ) ;
10371051 }
10381052 }
@@ -1057,18 +1071,12 @@ class Collection {
10571071 hasInlineSvg ? this . assetInline . inlineSvg ( content , entryFilename ) : content
10581072 ) ;
10591073
1060- // 7. inject preloads
1061- if ( this . pluginOption . isPreload ( ) ) {
1062- promise = promise . then (
1063- ( content ) => this . preload . insertPreloadAssets ( content , entry . filename , this . data ) || content
1064- ) ;
1065- }
1066-
1067- // 8. inject integrity
1074+ // 7. inject integrity
10681075 if ( hasIntegrity ) {
10691076 promise = promise . then ( ( content ) => {
10701077 // 2. parse generated html for `link` and `script` tags
10711078 const parsedResults = [ ] ;
1079+ const crossorigin = this . pluginOption . getCrossorigin ( ) ;
10721080
10731081 for ( const opts of parseOptions . values ( ) ) {
10741082 parsedResults . push ( ...HtmlParser . parseTag ( content , opts ) ) ;
@@ -1079,15 +1087,23 @@ class Collection {
10791087 let pos = 0 ;
10801088 let output = '' ;
10811089
1082- for ( const { tag, parsedAttrs, attrs, startPos, endPos } of parsedResults ) {
1090+ for ( const { type , tag, parsedAttrs, attrs, startPos, endPos } of parsedResults ) {
10831091 if ( ! attrs || parsedAttrs . length < 1 ) continue ;
10841092
10851093 const assetFile = attrs . href || attrs . src ;
1086- const integrity = assetIntegrity . get ( assetFile ) ;
1094+ const asset = assetsCache . get ( assetFile ) || { } ;
1095+ const { integrity } = asset ;
1096+ const integrityOrigin = attrs . integrity ;
1097+
1098+ // update the integrity that was calculated to the original value parsed in HTML
1099+ if ( integrityOrigin ) {
1100+ asset . integrity = integrityOrigin ;
1101+ continue ;
1102+ }
10871103
10881104 if ( integrity ) {
10891105 attrs . integrity = integrity ;
1090- attrs . crossorigin = this . pluginOption . webpackOptions . output . crossOriginLoading || 'anonymous' ;
1106+ attrs . crossorigin = crossorigin ;
10911107
10921108 let attrsStr = '' ;
10931109 for ( const attrName in attrs ) {
@@ -1104,6 +1120,13 @@ class Collection {
11041120 } ) ;
11051121 }
11061122
1123+ // 8. inject preloads containing integrity attribute
1124+ if ( this . pluginOption . isPreload ( ) ) {
1125+ promise = promise . then (
1126+ ( content ) => this . preload . insertPreloadAssets ( content , entry . filename , this . data ) || content
1127+ ) ;
1128+ }
1129+
11071130 // 9. beforeEmit hook allows plugins to change the html after chunks and inlined assets are injected
11081131 promise = promise . then ( ( content ) => hooks . beforeEmit . promise ( content , compileEntry ) || content ) ;
11091132
0 commit comments