@@ -9,6 +9,7 @@ extern crate serde_json;
9
9
extern crate rocket;
10
10
extern crate rust_team_data;
11
11
extern crate sass_rs;
12
+ extern crate siphasher;
12
13
extern crate toml;
13
14
14
15
extern crate rocket_contrib;
@@ -32,8 +33,10 @@ mod teams;
32
33
33
34
use production:: User ;
34
35
36
+ use std:: collections:: hash_map:: DefaultHasher ;
35
37
use std:: fs;
36
38
use std:: fs:: File ;
39
+ use std:: hash:: Hasher ;
37
40
use std:: io:: prelude:: * ;
38
41
use std:: iter:: FromIterator ;
39
42
use std:: path:: { Path , PathBuf } ;
@@ -44,6 +47,7 @@ use rocket::{
44
47
http:: Status ,
45
48
response:: { NamedFile , Redirect } ,
46
49
} ;
50
+
47
51
use rocket_contrib:: templates:: Template ;
48
52
49
53
use sass_rs:: { compile_file, Options } ;
@@ -52,6 +56,20 @@ use category::Category;
52
56
53
57
use i18n:: { I18NHelper , SupportedLocale , TeamHelper } ;
54
58
59
+ lazy_static ! {
60
+ static ref CSS : CSSNames = {
61
+ let app_css_file = compile_sass( "app" ) ;
62
+ let fonts_css_file = compile_sass( "fonts" ) ;
63
+ let vendor_css_file = concat_vendor_css( vec![ "skeleton" , "tachyons" ] ) ;
64
+
65
+ CSSNames {
66
+ app: app_css_file,
67
+ fonts: fonts_css_file,
68
+ vendor: vendor_css_file,
69
+ }
70
+ } ;
71
+ }
72
+
55
73
#[ derive( Serialize ) ]
56
74
struct Context < T : :: serde:: Serialize > {
57
75
page : String ,
@@ -61,6 +79,14 @@ struct Context<T: ::serde::Serialize> {
61
79
data : T ,
62
80
lang : String ,
63
81
baseurl : String ,
82
+ css : CSSNames ,
83
+ }
84
+
85
+ #[ derive( Clone , Serialize ) ]
86
+ struct CSSNames {
87
+ app : String ,
88
+ fonts : String ,
89
+ vendor : String ,
64
90
}
65
91
66
92
static LAYOUT : & str = "components/layout" ;
@@ -209,6 +235,7 @@ fn not_found() -> Template {
209
235
data : ( ) ,
210
236
lang : ENGLISH . to_string ( ) ,
211
237
baseurl : String :: new ( ) ,
238
+ css : CSS . clone ( ) ,
212
239
} ;
213
240
Template :: render ( page, & context)
214
241
}
@@ -218,26 +245,43 @@ fn catch_error() -> Template {
218
245
not_found ( )
219
246
}
220
247
221
- fn compile_sass ( filename : & str ) {
248
+ fn hash_css ( css : & str ) -> String {
249
+ let mut hasher = DefaultHasher :: new ( ) ;
250
+ hasher. write ( css. as_bytes ( ) ) ;
251
+ hasher. finish ( ) . to_string ( )
252
+ }
253
+
254
+ fn compile_sass ( filename : & str ) -> String {
222
255
let scss_file = format ! ( "./src/styles/{}.scss" , filename) ;
223
- let css_file = format ! ( "./static/styles/{}.css" , filename) ;
224
256
225
257
let css = compile_file ( & scss_file, Options :: default ( ) )
226
258
. expect ( & format ! ( "couldn't compile sass: {}" , & scss_file) ) ;
259
+
260
+ let css_sha = format ! ( "{}_{}" , filename, hash_css( & css) ) ;
261
+ let css_file = format ! ( "./static/styles/{}.css" , css_sha) ;
262
+
227
263
let mut file =
228
264
File :: create ( & css_file) . expect ( & format ! ( "couldn't make css file: {}" , & css_file) ) ;
229
265
file. write_all ( & css. into_bytes ( ) )
230
266
. expect ( & format ! ( "couldn't write css file: {}" , & css_file) ) ;
267
+
268
+ String :: from ( & css_file[ 1 ..] )
231
269
}
232
270
233
- fn concat_vendor_css ( files : Vec < & str > ) {
271
+ fn concat_vendor_css ( files : Vec < & str > ) -> String {
234
272
let mut concatted = String :: new ( ) ;
235
273
for filestem in files {
236
274
let vendor_path = format ! ( "./static/styles/{}.css" , filestem) ;
237
275
let contents = fs:: read_to_string ( vendor_path) . expect ( "couldn't read vendor css" ) ;
238
276
concatted. push_str ( & contents) ;
239
277
}
240
- fs:: write ( "./static/styles/vendor.css" , & concatted) . expect ( "couldn't write vendor css" ) ;
278
+
279
+ let css_sha = format ! ( "vendor_{}" , hash_css( & concatted) ) ;
280
+ let css_path = format ! ( "./static/styles/{}.css" , & css_sha) ;
281
+
282
+ fs:: write ( & css_path, & concatted) . expect ( "couldn't write vendor css" ) ;
283
+
284
+ String :: from ( & css_path[ 1 ..] )
241
285
}
242
286
243
287
fn render_index ( lang : String ) -> Template {
@@ -263,6 +307,7 @@ fn render_index(lang: String) -> Template {
263
307
} ,
264
308
baseurl : baseurl ( & lang) ,
265
309
lang,
310
+ css : CSS . clone ( ) ,
266
311
} ;
267
312
Template :: render ( page, & context)
268
313
}
@@ -278,6 +323,7 @@ fn render_category(category: Category, lang: String) -> Template {
278
323
data : ( ) ,
279
324
baseurl : baseurl ( & lang) ,
280
325
lang,
326
+ css : CSS . clone ( ) ,
281
327
} ;
282
328
Template :: render ( page, & context)
283
329
}
@@ -293,6 +339,7 @@ fn render_production(lang: String) -> Template {
293
339
data : load_users_data ( ) ,
294
340
baseurl : baseurl ( & lang) ,
295
341
lang,
342
+ css : CSS . clone ( ) ,
296
343
} ;
297
344
Template :: render ( page, & context)
298
345
}
@@ -310,6 +357,7 @@ fn render_governance(lang: String) -> Result<Template, Status> {
310
357
data,
311
358
baseurl : baseurl ( & lang) ,
312
359
lang,
360
+ css : CSS . clone ( ) ,
313
361
} ;
314
362
Ok ( Template :: render ( page, & context) )
315
363
}
@@ -337,6 +385,7 @@ fn render_team(
337
385
data,
338
386
baseurl : baseurl ( & lang) ,
339
387
lang,
388
+ css : CSS . clone ( ) ,
340
389
} ;
341
390
Ok ( Template :: render ( page, & context) )
342
391
}
@@ -368,15 +417,12 @@ fn render_subject(category: Category, subject: String, lang: String) -> Template
368
417
data : ( ) ,
369
418
baseurl : baseurl ( & lang) ,
370
419
lang,
420
+ css : CSS . clone ( ) ,
371
421
} ;
372
422
Template :: render ( page, & context)
373
423
}
374
424
375
425
fn main ( ) {
376
- compile_sass ( "app" ) ;
377
- compile_sass ( "fonts" ) ;
378
- concat_vendor_css ( vec ! [ "skeleton" , "tachyons" ] ) ;
379
-
380
426
let templating = Template :: custom ( |engine| {
381
427
engine
382
428
. handlebars
0 commit comments