1
1
/*eslint-env node*/
2
2
'use strict' ;
3
3
4
- var RSVP = require ( 'rsvp' ) ;
5
4
var fs = require ( 'fs' ) ;
6
5
var path = require ( 'path' ) ;
7
6
var zlib = require ( 'zlib' ) ;
@@ -14,181 +13,183 @@ var renameFile = denodeify(fs.rename);
14
13
var DeployPluginBase = require ( 'ember-cli-deploy-plugin' ) ;
15
14
var validCompressions = [ 'best' , 'gzip' , 'brotli' ] ;
16
15
17
- module . exports = {
18
- name : 'ember-cli-deploy-compress' ,
19
-
20
- createDeployPlugin ( options ) {
21
- var fs = require ( 'fs' ) ;
22
-
23
- var DeployPlugin = DeployPluginBase . extend ( {
24
- name : options . name ,
25
- canUseBrotli : false ,
26
- defaultConfig : {
27
- filePattern : '**/*.{js,css,json,ico,map,xml,txt,svg,eot,ttf,woff,woff2,appcache,webmanifest}' ,
28
- ignorePattern : null ,
29
- compression : [ 'best' ] ,
30
- zopfli : false ,
31
- keep : false ,
32
- distDir ( context ) {
33
- return context . distDir ;
34
- } ,
35
- distFiles ( context ) {
36
- return context . distFiles ;
37
- }
16
+ class DeployPlugin extends DeployPluginBase {
17
+ constructor ( options ) {
18
+ super ( ) ;
19
+ this . name = options . name ;
20
+ this . canUseBrotli = false ;
21
+ this . defaultConfig = {
22
+ filePattern : '**/*.{js,css,json,ico,map,xml,txt,svg,eot,ttf,woff,woff2,appcache,webmanifest}' ,
23
+ ignorePattern : null ,
24
+ compression : [ 'best' ] ,
25
+ zopfli : false ,
26
+ keep : false ,
27
+ distDir ( context ) {
28
+ return context . distDir ;
38
29
} ,
30
+ distFiles ( context ) {
31
+ return context . distFiles ;
32
+ }
33
+ } ;
34
+ }
39
35
40
- configure ( context ) {
41
- this . _super . configure . call ( this , context ) ;
42
- this . _validateCompressionConfig ( ) ;
43
- } ,
36
+ configure ( context ) {
37
+ super . configure . call ( this , context ) ;
38
+ this . _validateCompressionConfig ( ) ;
39
+ }
44
40
45
- willUpload ( /* context */ ) {
46
- var self = this ;
47
-
48
- var filePattern = this . readConfig ( 'filePattern' ) ;
49
- var ignorePattern = this . readConfig ( 'ignorePattern' ) ;
50
- var distDir = this . readConfig ( 'distDir' ) ;
51
- var distFiles = this . readConfig ( 'distFiles' ) || [ ] ;
52
- var keep = this . readConfig ( 'keep' ) ;
53
-
54
- this . log ( 'compressing `' + filePattern + '`' , { verbose : true } ) ;
55
- this . log ( 'ignoring `' + ignorePattern + '`' , { verbose : true } ) ;
56
-
57
- // Intentionally calling this as late as possible to give other addons a
58
- // chance to influence it somehow, e.g. through ENV variables.
59
- this . _determineBrotliSupport ( ) ;
60
-
61
- let promises = { gzippedFiles : [ ] , brotliCompressedFiles : [ ] } ;
62
- if ( this . _mustCompressWithBrotli ( ) ) {
63
- this . log ( 'Compressing files with brotli' , { verbose : true } ) ;
64
- promises . brotliCompressedFiles = this . _compressFiles ( distDir , distFiles , filePattern , ignorePattern , keep , 'brotli' ) ;
65
- }
66
- if ( this . _mustCompressWithGzip ( ) ) {
67
- this . log ( 'Compressing files with gzip' , { verbose : true } ) ;
68
- promises . gzippedFiles = this . _compressFiles ( distDir , distFiles , filePattern , ignorePattern , keep , 'gzip' ) ;
69
- }
70
- return RSVP . hash ( promises ) . then ( function ( { gzippedFiles, brotliCompressedFiles } ) {
71
- self . log ( `compressed ${ gzippedFiles . length + brotliCompressedFiles . length } files ok` , { verbose : true } ) ;
72
- if ( keep ) {
73
- self . log ( 'keep is enabled, added compressed files to `context.distFiles`' , { verbose : true } ) ;
74
- return {
75
- distFiles : [ ] . concat ( gzippedFiles ) . concat ( brotliCompressedFiles ) , // needs to be a copy
76
- gzippedFiles,
77
- brotliCompressedFiles
78
- } ;
79
- } else {
80
- return { gzippedFiles, brotliCompressedFiles } ;
81
- }
82
- } ) . catch ( this . _errorMessage . bind ( this ) ) ;
83
- } ,
84
- _compressFiles ( distDir , distFiles , filePattern , ignorePattern , keep , format ) {
85
- var filesToCompress = distFiles . filter ( minimatch . filter ( filePattern , { matchBase : true } ) ) ;
86
- if ( ignorePattern != null ) {
87
- filesToCompress = filesToCompress . filter ( function ( path ) {
88
- return ! minimatch ( path , ignorePattern , { matchBase : true } ) ;
89
- } ) ;
90
- }
91
- return RSVP . map ( filesToCompress , this . _compressFile . bind ( this , distDir , keep , format ) ) ;
92
- } ,
93
- _compressFile ( distDir , keep , format , filePath ) {
94
- var self = this ;
95
- var fullPath = path . join ( distDir , filePath ) ;
96
- var fileExtension = format === 'brotli' ? '.br' : '.gz' ;
97
- var outFilePath = fullPath + fileExtension ;
98
-
99
- return new RSVP . Promise ( function ( resolve , reject ) {
100
- var inp = fs . createReadStream ( fullPath ) ;
101
- var out = fs . createWriteStream ( outFilePath ) ;
102
- let compressor = self [ format + 'Compressor' ] ( ) ;
103
- inp . pipe ( compressor ) . pipe ( out ) ;
104
- inp . on ( 'error' , function ( err ) { reject ( err ) ; } ) ;
105
- out . on ( 'error' , function ( err ) { reject ( err ) ; } ) ;
106
- out . on ( 'finish' , function ( ) { resolve ( ) ; } ) ;
107
- } ) . then ( function ( ) {
108
- if ( ! keep ) {
109
- return renameFile ( fullPath + fileExtension , fullPath ) . then ( function ( ) {
110
- return filePath ;
111
- } ) ;
112
- } else {
113
- return filePath + fileExtension ;
114
- }
115
- } ) . then ( function ( outFilePath ) {
116
- self . log ( '✔ ' + outFilePath , { verbose : true } ) ;
117
-
118
- return outFilePath ;
41
+ async willUpload ( /* context */ ) {
42
+ var self = this ;
43
+
44
+ var filePattern = this . readConfig ( 'filePattern' ) ;
45
+ var ignorePattern = this . readConfig ( 'ignorePattern' ) ;
46
+ var distDir = this . readConfig ( 'distDir' ) ;
47
+ var distFiles = this . readConfig ( 'distFiles' ) || [ ] ;
48
+ var keep = this . readConfig ( 'keep' ) ;
49
+
50
+ this . log ( 'compressing `' + filePattern + '`' , { verbose : true } ) ;
51
+ this . log ( 'ignoring `' + ignorePattern + '`' , { verbose : true } ) ;
52
+
53
+ // Intentionally calling this as late as possible to give other addons a
54
+ // chance to influence it somehow, e.g. through ENV variables.
55
+ this . _determineBrotliSupport ( ) ;
56
+
57
+ let promises = { gzippedFiles : [ ] , brotliCompressedFiles : [ ] } ;
58
+ if ( this . _mustCompressWithBrotli ( ) ) {
59
+ this . log ( 'Compressing files with brotli' , { verbose : true } ) ;
60
+ promises . brotliCompressedFiles = this . _compressFiles ( distDir , distFiles , filePattern , ignorePattern , keep , 'brotli' ) ;
61
+ }
62
+ if ( this . _mustCompressWithGzip ( ) ) {
63
+ this . log ( 'Compressing files with gzip' , { verbose : true } ) ;
64
+ promises . gzippedFiles = this . _compressFiles ( distDir , distFiles , filePattern , ignorePattern , keep , 'gzip' ) ;
65
+ }
66
+ try {
67
+ let { gzippedFiles, brotliCompressedFiles } = await RSVP . hash ( promises ) ;
68
+ self . log ( `compressed ${ gzippedFiles . length + brotliCompressedFiles . length } files ok` , { verbose : true } ) ;
69
+ if ( keep ) {
70
+ self . log ( 'keep is enabled, added compressed files to `context.distFiles`' , { verbose : true } ) ;
71
+ return {
72
+ distFiles : [ ] . concat ( gzippedFiles ) . concat ( brotliCompressedFiles ) , // needs to be a copy
73
+ gzippedFiles,
74
+ brotliCompressedFiles
75
+ } ;
76
+ } else {
77
+ return { gzippedFiles, brotliCompressedFiles } ;
78
+ }
79
+ } catch ( e ) {
80
+ this . _errorMessage ( e ) ;
81
+ }
82
+ }
83
+
84
+ async _compressFiles ( distDir , distFiles , filePattern , ignorePattern , keep , format ) {
85
+ var filesToCompress = distFiles . filter ( minimatch . filter ( filePattern , { matchBase : true } ) ) ;
86
+ if ( ignorePattern != null ) {
87
+ filesToCompress = filesToCompress . filter ( function ( path ) {
88
+ return ! minimatch ( path , ignorePattern , { matchBase : true } ) ;
119
89
} ) ;
120
- } ,
121
- gzipCompressor ( ) {
122
- if ( this . readConfig ( 'zopfli' ) ) {
123
- let pkgName =
124
- this . _hasPackage ( 'node-zopfli-es' ) ? 'node-zopfli-es' :
125
- this . _hasPackage ( 'node-zopfli' ) ? 'node-zopfli' : null ;
126
-
127
- if ( pkgName === null ) {
128
- throw new Error ( 'No compatible zopfli package found. Install node-zopfli-es for zopfli support!' ) ;
129
- }
130
-
131
- return this . project . require ( pkgName ) . createGzip ( { format : 'gzip' } )
132
- } else {
133
- return require ( 'zlib' ) . createGzip ( { format : 'gzip' } ) ;
134
- }
135
- } ,
90
+ }
91
+ return RSVP . map ( filesToCompress , this . _compressFile . bind ( this , distDir , keep , format ) ) ;
92
+ }
136
93
137
- brotliCompressor ( ) {
138
- // Use native brotli support on Node >= 11
139
- if ( zlib . createBrotliCompress ) {
140
- var brotliOptions = { } ;
94
+ async _compressFile ( distDir , keep , format , filePath ) {
95
+ var self = this ;
96
+ var fullPath = path . join ( distDir , filePath ) ;
97
+ var fileExtension = format === 'brotli' ? '.br' : '.gz' ;
98
+ var outFilePath = fullPath + fileExtension ;
99
+
100
+ await new RSVP . Promise ( async function ( resolve , reject ) {
101
+ var inp = fs . createReadStream ( fullPath ) ;
102
+ var out = fs . createWriteStream ( outFilePath ) ;
103
+ let compressor = await self [ format + 'Compressor' ] ( ) ;
104
+ inp . pipe ( compressor ) . pipe ( out ) ;
105
+ inp . on ( 'error' , function ( err ) { reject ( err ) ; } ) ;
106
+ out . on ( 'error' , function ( err ) { reject ( err ) ; } ) ;
107
+ out . on ( 'finish' , function ( ) { resolve ( ) ; } ) ;
108
+ } ) ;
141
109
142
- brotliOptions [ zlib . constants . BROTLI_PARAM_QUALITY ] = 11 ;
110
+ if ( ! keep ) {
111
+ outFilePath = await renameFile ( fullPath + fileExtension , fullPath ) . then ( function ( ) {
112
+ return filePath ;
113
+ } ) ;
114
+ } else {
115
+ outFilePath = filePath + fileExtension ;
116
+ }
143
117
144
- return zlib . createBrotliCompress ( { params : brotliOptions } ) ;
145
- }
118
+ this . log ( '✔ ' + outFilePath , { verbose : true } ) ;
119
+ return outFilePath ;
120
+ }
146
121
147
- return require ( 'iltorb' ) . compressStream ( { quality : 11 } ) ;
148
- } ,
122
+ async gzipCompressor ( ) {
123
+ if ( this . readConfig ( 'zopfli' ) ) {
124
+ let pkgName =
125
+ this . _hasPackage ( 'node-zopfli-es' ) ? 'node-zopfli-es' :
126
+ this . _hasPackage ( 'node-zopfli' ) ? 'node-zopfli' : null ;
149
127
150
- _hasPackage ( pkgName ) {
151
- return pkgName in this . project . dependencies ( ) ;
152
- } ,
153
- _determineBrotliSupport ( ) {
154
- let browsers = this . project && this . project . targets && this . project . targets . browsers ;
155
- this . canUseBrotli = ! ! browsers && caniuse . isSupported ( 'brotli' , browsers ) ;
156
- } ,
157
- _mustCompressWithBrotli ( ) {
158
- let compression = this . _getCompression ( ) ;
159
- return compression . indexOf ( 'brotli' ) > - 1 || ( compression . indexOf ( 'best' ) > - 1 && this . canUseBrotli ) ;
160
- } ,
161
- _mustCompressWithGzip ( ) {
162
- let compression = this . _getCompression ( ) ;
163
- return compression . indexOf ( 'gzip' ) > - 1 || ( compression . indexOf ( 'best' ) > - 1 && ! this . canUseBrotli ) ;
164
- } ,
165
- _errorMessage ( error ) {
166
- this . log ( error , { color : 'red' } ) ;
167
- return RSVP . reject ( error ) ;
168
- } ,
169
- _validateCompressionConfig ( ) {
170
- let compression = this . _getCompression ( ) ;
171
- compression . forEach ( function ( value ) {
172
- if ( validCompressions . indexOf ( value ) === - 1 ) {
173
- throw new Error ( `The "compression" config option has a wrong value: "${ value } "` ) ;
174
- }
175
- } ) ;
176
- if ( compression . indexOf ( 'best' ) > - 1 && compression . length > 1 ) {
177
- throw new Error ( 'The "compression" config cannot combine "best" with other values' ) ;
178
- }
179
- if ( compression . length > 1 && ! this . readConfig ( 'keep' ) ) {
180
- throw new Error ( 'You cannot compress using both brotli and gzip unless you enable the `keep` option' ) ;
181
- }
182
- } ,
128
+ if ( pkgName === null ) {
129
+ throw new Error ( 'No compatible zopfli package found. Install node-zopfli-es for zopfli support!' ) ;
130
+ }
183
131
184
- _getCompression ( ) {
185
- let compression = this . readConfig ( 'compression' ) ;
186
- if ( ! Array . isArray ( compression ) ) {
187
- compression = [ compression ] ;
188
- }
189
- return compression ;
132
+ let { default : pkg } = await import ( pkgName ) ;
133
+
134
+ return pkg . createGzip ( { format : 'gzip' } )
135
+ } else {
136
+ return require ( 'zlib' ) . createGzip ( { format : 'gzip' } ) ;
137
+ }
138
+ }
139
+
140
+ async brotliCompressor ( ) {
141
+ var brotliOptions = { } ;
142
+ brotliOptions [ zlib . constants . BROTLI_PARAM_QUALITY ] = 11 ;
143
+ return zlib . createBrotliCompress ( { params : brotliOptions } ) ;
144
+ }
145
+
146
+ _hasPackage ( pkgName ) {
147
+ return pkgName in this . project . dependencies ( ) ;
148
+ }
149
+ _determineBrotliSupport ( ) {
150
+ let browsers = this . project && this . project . targets && this . project . targets . browsers ;
151
+ this . canUseBrotli = ! ! browsers && caniuse . isSupported ( 'brotli' , browsers ) ;
152
+ }
153
+ _mustCompressWithBrotli ( ) {
154
+ let compression = this . _getCompression ( ) ;
155
+ return compression . indexOf ( 'brotli' ) > - 1 || ( compression . indexOf ( 'best' ) > - 1 && this . canUseBrotli ) ;
156
+ }
157
+ _mustCompressWithGzip ( ) {
158
+ let compression = this . _getCompression ( ) ;
159
+ return compression . indexOf ( 'gzip' ) > - 1 || ( compression . indexOf ( 'best' ) > - 1 && ! this . canUseBrotli ) ;
160
+ }
161
+ _errorMessage ( error ) {
162
+ this . log ( error , { color : 'red' } ) ;
163
+ return RSVP . reject ( error ) ;
164
+ }
165
+ _validateCompressionConfig ( ) {
166
+ let compression = this . _getCompression ( ) ;
167
+ compression . forEach ( function ( value ) {
168
+ if ( validCompressions . indexOf ( value ) === - 1 ) {
169
+ throw new Error ( `The "compression" config option has a wrong value: "${ value } "` ) ;
190
170
}
191
171
} ) ;
192
- return new DeployPlugin ( ) ;
172
+ if ( compression . indexOf ( 'best' ) > - 1 && compression . length > 1 ) {
173
+ throw new Error ( 'The "compression" config cannot combine "best" with other values' ) ;
174
+ }
175
+ if ( compression . length > 1 && ! this . readConfig ( 'keep' ) ) {
176
+ throw new Error ( 'You cannot compress using both brotli and gzip unless you enable the `keep` option' ) ;
177
+ }
178
+ }
179
+
180
+ _getCompression ( ) {
181
+ let compression = this . readConfig ( 'compression' ) ;
182
+ if ( ! Array . isArray ( compression ) ) {
183
+ compression = [ compression ] ;
184
+ }
185
+ return compression ;
186
+ }
187
+ }
188
+
189
+ module . exports = {
190
+ name : 'ember-cli-deploy-compress' ,
191
+
192
+ createDeployPlugin ( options ) {
193
+ return new DeployPlugin ( options ) ;
193
194
}
194
195
} ;
0 commit comments