@@ -18,79 +18,115 @@ var rimrafSync = require('rimraf').sync;
1818var webpack = require ( 'webpack' ) ;
1919var config = require ( '../config/webpack.config.prod' ) ;
2020var paths = require ( '../config/paths' ) ;
21+ var recursive = require ( 'recursive-readdir' ) ;
2122
22- // Remove all content but keep the directory so that
23- // if you're in it, you don't end up in Trash
24- rimrafSync ( paths . appBuild + '/*' ) ;
23+ function removeFileNameHash ( fileName ) {
24+ return fileName . replace ( paths . appBuild , '' )
25+ . replace ( / \/ ? ( .* ) ( \. \w + ) ( \. j s | \. c s s ) / , function ( match , p1 , p2 , p3 ) {
26+ return p1 + p3 ;
27+ } ) ;
28+ }
2529
26- console . log ( 'Creating an optimized production build...' ) ;
27- webpack ( config ) . run ( function ( err , stats ) {
28- if ( err ) {
29- console . error ( 'Failed to create a production build. Reason:' ) ;
30- console . error ( err . message || err ) ;
31- process . exit ( 1 ) ;
30+ function sizeDifference ( currentSize , previousSize ) {
31+ if ( previousSize === undefined ) { return '' ; }
32+ var difference = currentSize - previousSize ;
33+ var fileSize = filesize ( difference ) ;
34+ if ( difference > 0 ) {
35+ return chalk . red ( '+' + fileSize ) ;
36+ } else if ( difference <= 0 ) {
37+ return chalk . green ( ( difference === 0 ? '+' : '' ) + fileSize ) ;
3238 }
39+ }
3340
34- console . log ( chalk . green ( 'Compiled successfully.' ) ) ;
35- console . log ( ) ;
41+ recursive ( paths . appBuild , function ( err , fileNames ) {
42+ fileNames = fileNames || [ ] ;
43+ var previousSizeMap = fileNames . filter ( fileName => / \. ( j s | c s s ) $ / . test ( fileName ) )
44+ . reduce ( ( memo , fileName ) => {
45+ var contents = fs . readFileSync ( fileName ) ;
46+ var key = removeFileNameHash ( fileName ) ;
47+ memo [ key ] = gzipSize ( contents ) ;
48+ return memo ;
49+ } , { } ) ;
3650
37- console . log ( 'File sizes after gzip:' ) ;
38- console . log ( ) ;
39- var assets = stats . toJson ( ) . assets
40- . filter ( asset => / \. ( j s | c s s ) $ / . test ( asset . name ) )
41- . map ( asset => {
42- var fileContents = fs . readFileSync ( paths . appBuild + '/' + asset . name ) ;
43- var size = gzipSize ( fileContents ) ;
44- return {
45- folder : path . join ( 'build' , path . dirname ( asset . name ) ) ,
46- name : path . basename ( asset . name ) ,
47- size : size ,
48- sizeLabel : filesize ( size )
49- } ;
50- } ) ;
51- assets . sort ( ( a , b ) => b . size - a . size ) ;
51+ // Remove all content but keep the directory so that
52+ // if you're in it, you don't end up in Trash
53+ rimrafSync ( paths . appBuild + '/*' ) ;
54+
55+ build ( previousSizeMap ) ;
56+ } ) ;
5257
53- var longestSizeLabelLength = Math . max . apply ( null ,
54- assets . map ( a => a . sizeLabel . length )
55- ) ;
56- assets . forEach ( asset => {
57- var sizeLabel = asset . sizeLabel ;
58- if ( sizeLabel . length < longestSizeLabelLength ) {
59- var rightPadding = ' ' . repeat ( longestSizeLabelLength - sizeLabel . length ) ;
60- sizeLabel += rightPadding ;
58+ function build ( previousSizeMap ) {
59+ console . log ( 'Creating an optimized production build...' ) ;
60+ webpack ( config ) . run ( function ( err , stats ) {
61+ if ( err ) {
62+ console . error ( 'Failed to create a production build. Reason:' ) ;
63+ console . error ( err . message || err ) ;
64+ process . exit ( 1 ) ;
6165 }
62- console . log (
63- ' ' + chalk . green ( sizeLabel ) +
64- ' ' + chalk . dim ( asset . folder + path . sep ) + chalk . cyan ( asset . name )
65- ) ;
66- } ) ;
67- console . log ( ) ;
6866
69- var openCommand = process . platform === 'win32' ? 'start' : 'open' ;
70- var homepagePath = require ( paths . appPackageJson ) . homepage ;
71- if ( homepagePath ) {
72- console . log ( 'You can now publish them at ' + homepagePath + '.' ) ;
73- console . log ( 'For example, if you use GitHub Pages:' ) ;
67+ console . log ( chalk . green ( 'Compiled successfully.' ) ) ;
7468 console . log ( ) ;
75- console . log ( ' git commit -am "Save local changes"' ) ;
76- console . log ( ' git checkout -B gh-pages' ) ;
77- console . log ( ' git add -f build' ) ;
78- console . log ( ' git commit -am "Rebuild website"' ) ;
79- console . log ( ' git filter-branch -f --prune-empty --subdirectory-filter build' ) ;
80- console . log ( ' git push -f origin gh-pages' ) ;
81- console . log ( ' git checkout -' ) ;
69+
70+ console . log ( 'File sizes after gzip:' ) ;
8271 console . log ( ) ;
83- } else {
84- console . log ( 'You can now serve them with any static server.' ) ;
85- console . log ( 'For example:' ) ;
72+ var assets = stats . toJson ( ) . assets
73+ . filter ( asset => / \. ( j s | c s s ) $ / . test ( asset . name ) )
74+ . map ( asset => {
75+ var fileContents = fs . readFileSync ( paths . appBuild + '/' + asset . name ) ;
76+ var size = gzipSize ( fileContents ) ;
77+ var previousSize = previousSizeMap [ removeFileNameHash ( asset . name ) ] ;
78+ var difference = sizeDifference ( size , previousSize ) ;
79+ return {
80+ folder : path . join ( 'build' , path . dirname ( asset . name ) ) ,
81+ name : path . basename ( asset . name ) ,
82+ size : size ,
83+ sizeLabel : filesize ( size ) + ( difference ? ' (' + difference + ')' : '' )
84+ } ;
85+ } ) ;
86+ assets . sort ( ( a , b ) => b . size - a . size ) ;
87+
88+ var longestSizeLabelLength = Math . max . apply ( null ,
89+ assets . map ( a => a . sizeLabel . length )
90+ ) ;
91+ assets . forEach ( asset => {
92+ var sizeLabel = asset . sizeLabel ;
93+ if ( sizeLabel . length < longestSizeLabelLength ) {
94+ var rightPadding = ' ' . repeat ( longestSizeLabelLength - sizeLabel . length ) ;
95+ sizeLabel += rightPadding ;
96+ }
97+ console . log (
98+ ' ' + chalk . yellow ( sizeLabel ) +
99+ ' ' + chalk . dim ( asset . folder + path . sep ) + chalk . cyan ( asset . name )
100+ ) ;
101+ } ) ;
86102 console . log ( ) ;
87- console . log ( ' npm install -g pushstate-server' ) ;
88- console . log ( ' pushstate-server build' ) ;
89- console . log ( ' ' + openCommand + ' http://localhost:9000' ) ;
103+
104+ var openCommand = process . platform === 'win32' ? 'start' : 'open' ;
105+ var homepagePath = require ( paths . appPackageJson ) . homepage ;
106+ if ( homepagePath ) {
107+ console . log ( 'You can now publish them at ' + homepagePath + '.' ) ;
108+ console . log ( 'For example, if you use GitHub Pages:' ) ;
109+ console . log ( ) ;
110+ console . log ( ' git commit -am "Save local changes"' ) ;
111+ console . log ( ' git checkout -B gh-pages' ) ;
112+ console . log ( ' git add -f build' ) ;
113+ console . log ( ' git commit -am "Rebuild website"' ) ;
114+ console . log ( ' git filter-branch -f --prune-empty --subdirectory-filter build' ) ;
115+ console . log ( ' git push -f origin gh-pages' ) ;
116+ console . log ( ' git checkout -' ) ;
117+ console . log ( ) ;
118+ } else {
119+ console . log ( 'You can now serve them with any static server.' ) ;
120+ console . log ( 'For example:' ) ;
121+ console . log ( ) ;
122+ console . log ( ' npm install -g pushstate-server' ) ;
123+ console . log ( ' pushstate-server build' ) ;
124+ console . log ( ' ' + openCommand + ' http://localhost:9000' ) ;
125+ console . log ( ) ;
126+ console . log ( chalk . dim ( 'The project was built assuming it is hosted at the root.' ) ) ;
127+ console . log ( chalk . dim ( 'Set the "homepage" field in package.json to override this.' ) ) ;
128+ console . log ( chalk . dim ( 'For example, "homepage": "http://user.github.io/project".' ) ) ;
129+ }
90130 console . log ( ) ;
91- console . log ( chalk . dim ( 'The project was built assuming it is hosted at the root.' ) ) ;
92- console . log ( chalk . dim ( 'Set the "homepage" field in package.json to override this.' ) ) ;
93- console . log ( chalk . dim ( 'For example, "homepage": "http://user.github.io/project".' ) ) ;
94- }
95- console . log ( ) ;
96- } ) ;
131+ } ) ;
132+ }
0 commit comments