@@ -13,6 +13,11 @@ function OutputHash({ validateOutput = false, validateOutputRegex = /^.*$/ } = {
13
13
function replaceStringInAsset ( asset , source , target ) {
14
14
const sourceRE = new RegExp ( source , 'g' ) ;
15
15
16
+ // when optimize-cssnano-plugin disable css sourcemap, map file will be delete,so this may be undefined
17
+ if ( ! asset ) {
18
+ return false ;
19
+ }
20
+
16
21
if ( typeof asset === 'string' ) {
17
22
return asset . replace ( sourceRE , target ) ;
18
23
}
@@ -40,7 +45,18 @@ function replaceStringInAsset(asset, source, target) {
40
45
asset . children = asset . children . map ( child => replaceStringInAsset ( child , source , target ) ) ;
41
46
return asset ;
42
47
}
43
-
48
+ // support config OutputHash after optimize-cssnano-plugin, genrate hash after minify
49
+ if ( asset . source && typeof asset . source === 'function' ) {
50
+ const processedCss = asset . source ( ) . replace ( sourceRE , target ) ;
51
+ return {
52
+ source : function ( ) {
53
+ return processedCss ;
54
+ } ,
55
+ size : function ( ) {
56
+ return processedCss . length ;
57
+ } ,
58
+ } ;
59
+ }
44
60
throw new Error (
45
61
`Unknown asset type (${ asset . constructor . name } )!. ` +
46
62
'Unfortunately this type of asset is not supported yet. ' +
@@ -62,11 +78,13 @@ function reHashChunk(chunk, assets, hashFn, nameMap) {
62
78
const asset = assets [ oldChunkName ] ;
63
79
const { fullHash, shortHash : newHash } = hashFn ( asset . source ( ) ) ;
64
80
65
- let newChunkName ;
81
+ let newChunkName , oldHash ;
66
82
67
83
if ( oldChunkName . includes ( chunk . renderedHash ) ) {
68
84
// Save the hash map for replacing the secondary files
69
85
nameMap [ chunk . renderedHash ] = newHash ;
86
+
87
+ oldHash = chunk . renderedHash ;
70
88
newChunkName = oldChunkName . replace ( chunk . renderedHash , newHash ) ;
71
89
72
90
// Keep the chunk hashes in sync
@@ -94,18 +112,40 @@ function reHashChunk(chunk, assets, hashFn, nameMap) {
94
112
95
113
// Save the hash map for replacing the secondary files
96
114
nameMap [ module . renderedHash ] = newHash ;
115
+
116
+ oldHash = module . renderedHash ;
97
117
newChunkName = oldChunkName . replace ( module . renderedHash , newHash ) ;
98
118
99
119
// Keep the module hashes in sync
100
120
module . hash = fullHash ;
101
121
module . renderedHash = newHash ;
102
122
}
103
123
124
+ // Change inline sourcemap comments to include the new hash
125
+ replaceStringInAsset ( asset , oldHash , newHash ) ;
126
+
104
127
// Change file name to include the new hash
105
128
chunk . files [ index ] = newChunkName ;
106
129
asset . _name = newChunkName ;
107
130
delete assets [ oldChunkName ] ;
108
131
assets [ newChunkName ] = asset ;
132
+
133
+ // replace map file hash
134
+ const oldMapChunkName = oldChunkName + '.map' ;
135
+ const newMapChunkName = newChunkName + '.map' ;
136
+ const mapAsset = assets [ oldMapChunkName ] ;
137
+ if ( ! mapAsset ) {
138
+ return false ;
139
+ }
140
+
141
+ chunk . files . forEach ( ( el , i ) => {
142
+ if ( el == oldMapChunkName ) {
143
+ chunk . files [ i ] = newMapChunkName ;
144
+ }
145
+ } ) ;
146
+
147
+ delete assets [ oldMapChunkName ] ;
148
+ assets [ newMapChunkName ] = mapAsset ;
109
149
} ) ;
110
150
111
151
// Update the content of the rest of the files in the chunk
@@ -150,8 +190,15 @@ OutputHash.prototype.apply = function apply(compiler) {
150
190
compiler . hooks . emit . taps [ 0 ] . name !== 'OutputHash'
151
191
) {
152
192
debugger ;
193
+ let isHasMatchOutputHash = false ;
153
194
const plugins = compiler . hooks . emit . taps
154
- . filter ( plugin => plugin . name != 'OutputHash' )
195
+ . filter ( plugin => {
196
+ if ( isHasMatchOutputHash ) {
197
+ return false ;
198
+ }
199
+ isHasMatchOutputHash = plugin . name === 'OutputHash' ;
200
+ return ! isHasMatchOutputHash ;
201
+ } )
155
202
. map ( plugin => ` * ${ plugin . name } ` )
156
203
. join ( '\n' ) ;
157
204
@@ -173,6 +220,10 @@ OutputHash.prototype.apply = function apply(compiler) {
173
220
174
221
// Reuses webpack options
175
222
hashFn = input => {
223
+ // generate hash of content without sourcemap
224
+ const mapCommentReg = / \s \/ [ \/ | * ] # \s ? s o u r c e M a p p i n g U R L = .* .m a p ( \s \* \/ ) ? / g;
225
+ input = input . replace ( mapCommentReg , '' ) ;
226
+
176
227
const hashObj = crypto . createHash ( hashFunction ) . update ( input ) ;
177
228
if ( hashSalt ) hashObj . update ( hashSalt ) ;
178
229
const fullHash = hashObj . digest ( hashDigest ) ;
0 commit comments