Skip to content

Commit e46cf7d

Browse files
committed
[BREAKING] Update node version requirement to 14+
- refactored DeployPlugin to ES6 class - update various dependencies and docs
1 parent f858445 commit e46cf7d

File tree

5 files changed

+3181
-2155
lines changed

5 files changed

+3181
-2155
lines changed

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
root: true,
33
parserOptions: {
4-
ecmaVersion: 6,
4+
ecmaVersion: 2022,
55
sourceType: 'module'
66
},
77
extends: 'eslint:recommended',

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Run the following command in your terminal:
2121
ember install ember-cli-deploy-compress
2222
```
2323

24-
Note that this addon requires at least node.js 8!
24+
Note that this addon requires at least node.js 14!
2525

2626
## ember-cli-deploy Hooks Implemented
2727

index.js

Lines changed: 166 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/*eslint-env node*/
22
'use strict';
33

4-
var RSVP = require('rsvp');
54
var fs = require('fs');
65
var path = require('path');
76
var zlib = require('zlib');
@@ -14,181 +13,183 @@ var renameFile = denodeify(fs.rename);
1413
var DeployPluginBase = require('ember-cli-deploy-plugin');
1514
var validCompressions = ['best', 'gzip', 'brotli'];
1615

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;
3829
},
30+
distFiles(context){
31+
return context.distFiles;
32+
}
33+
};
34+
}
3935

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+
}
4440

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 });
11989
});
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+
}
13693

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+
});
141109

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+
}
143117

144-
return zlib.createBrotliCompress({ params: brotliOptions });
145-
}
118+
this.log('✔ ' + outFilePath, { verbose: true });
119+
return outFilePath;
120+
}
146121

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;
149127

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+
}
183131

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}"`);
190170
}
191171
});
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);
193194
}
194195
};

0 commit comments

Comments
 (0)