1
+ import { createHash , Hash } from 'crypto' ;
1
2
import * as path from 'path' ;
2
3
import color from 'kleur' ;
3
4
import relative from 'require-relative' ;
@@ -9,6 +10,7 @@ import {
9
10
OutputChunk ,
10
11
Plugin ,
11
12
PluginContext ,
13
+ PreRenderedChunk ,
12
14
RenderedChunk ,
13
15
RollupError
14
16
} from 'rollup' ;
@@ -154,11 +156,52 @@ export default class RollupCompiler {
154
156
155
157
const that = this ;
156
158
157
- // TODO this is hacky. refactor out into an external rollup plugin
158
- ( mod . plugins || ( mod . plugins = [ ] ) ) . push ( css_chunks ( { injectImports : true } ) ) ;
159
- if ( ! / [ \\ / ] c l i e n t \. / . test ( entry_point ) ) {
160
- return mod ;
161
- }
159
+ /**
160
+ * Track css code hashes for proper chunk hashing
161
+ */
162
+ const css_hashing = ( ) => {
163
+ const css_hashes : Record < string , string > = { } ;
164
+ return < Plugin > {
165
+ name : 'sapper-css-hashing' ,
166
+ augmentChunkHash ( this : PluginContext , chunk : PreRenderedChunk ) {
167
+ let hash : Hash ;
168
+
169
+ const module_files = Object . keys ( chunk . modules ) . map ( module_id => {
170
+ /**
171
+ * Save `module_file` which represents the id without file extension. This way it's easy to determine
172
+ * svelte generated css files as this will be the same for the svelte and corresponding css ids
173
+ */
174
+ const modulePath = path . parse ( module_id ) ;
175
+ return { module_id, module_file : `${ modulePath . dir } /${ modulePath . name } ` } ;
176
+ } ) ;
177
+ module_files . forEach ( ( { module_id, module_file } ) => {
178
+ if ( css_hashes [ module_id ] ) {
179
+ /**
180
+ * Ignore svelte css files created with `emitCss` enabled. These css files are generated out
181
+ * of svelte's `<style>` and already part of the code that was used to generate the chunk hash
182
+ */
183
+ const is_svelte_css = module_files . some ( ( { module_id : id , module_file : file } ) => id !== module_id && file === module_file ) ;
184
+ if ( ! is_svelte_css ) {
185
+ if ( ! hash ) {
186
+ hash = createHash ( 'sha256' ) ;
187
+ }
188
+ hash . update ( css_hashes [ module_id ] ) ;
189
+ }
190
+ }
191
+ } ) ;
192
+ if ( hash ) {
193
+ return hash . digest ( 'hex' ) ;
194
+ }
195
+ } ,
196
+ transform ( this : PluginContext , code : string , id : string ) {
197
+ if ( path . extname ( id ) === '.css' ) {
198
+ // save css code based hashes before `rollup-plugin-css-chunks` clears the code
199
+ css_hashes [ id ] = createHash ( 'sha256' ) . update ( code ) . digest ( 'hex' ) ;
200
+ }
201
+ return { code, map : null } ;
202
+ }
203
+ } ;
204
+ } ;
162
205
163
206
/**
164
207
* Finds dynamic imports and rewrites them to import the component and its CSS in parallel
@@ -300,6 +343,12 @@ export default class RollupCompiler {
300
343
}
301
344
} ;
302
345
346
+ // TODO this is hacky. refactor out into an external rollup plugin
347
+ ( mod . plugins || ( mod . plugins = [ ] ) ) . push ( css_hashing ( ) ) ;
348
+ mod . plugins . push ( css_chunks ( { injectImports : true } ) ) ;
349
+ if ( ! / [ \\ / ] c l i e n t \. / . test ( entry_point ) ) {
350
+ return mod ;
351
+ }
303
352
mod . plugins . push ( css_injection ) ;
304
353
mod . plugins . push ( sapper_internal ) ;
305
354
0 commit comments