Skip to content

Commit

Permalink
WIP: uglify - use workerpool
Browse files Browse the repository at this point in the history
  • Loading branch information
matz3 committed Sep 25, 2020
1 parent d81d1a1 commit 2d82905
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 35 deletions.
59 changes: 28 additions & 31 deletions lib/processors/uglifier.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,42 @@
const terser = require("terser");
/**
* Preserve comments which contain:
* <ul>
* <li>copyright notice</li>
* <li>license terms</li>
* <li>"@ui5-bundle"</li>
* <li>"@ui5-bundle-raw-include"</li>
* </ul>
*
* @type {RegExp}
*/
const copyrightCommentsAndBundleCommentPattern = /copyright|\(c\)(?:[0-9]+|\s+[0-9A-za-z])|released under|license|\u00a9|^@ui5-bundle-raw-include |^@ui5-bundle /i;
const workerpool = require("workerpool");
let _pool;

// Use up to 5 workers, depending on available CPUs
// Using more workers doesn't seem to improve overall performance
const maxWorkers = Math.max(Math.min((require("os").cpus().length || 4) - 1, 5), 1);

function pool({taskUtil}) {
if (!_pool) {
_pool = workerpool.pool(__dirname + "/uglifier_worker.js", {
workerType: "auto",
maxWorkers
});
taskUtil.registerCleanupTask(() => {
_pool.terminate();
_pool = null;
});
}
return _pool;
}

/**
* Minifies the supplied resources.
*
* @public
* @alias module:@ui5/builder.processors.uglifier
* @param {module:@ui5/builder.tasks.TaskUtil|object} [parameters.taskUtil] TaskUtil
* @param {object} parameters Parameters
* @param {module:@ui5/fs.Resource[]} parameters.resources List of resources to be processed
* @returns {Promise<module:@ui5/fs.Resource[]>} Promise resolving with uglified resources
*/
module.exports = function({resources}) {
module.exports = function({resources, taskUtil}) {
return Promise.all(resources.map(async (resource) => {
const code = await resource.getString();
try {
const result = await terser.minify({
[resource.getPath()]: code
}, {
output: {
comments: copyrightCommentsAndBundleCommentPattern,
wrap_func_args: false
},
compress: false
});
resource.setString(result.code);
return resource;
} catch (err) {
throw new Error(
`Uglification failed with error: ${err.message} in file ${err.filename} ` +
`(line ${err.line}, col ${err.col}, pos ${err.pos})`);
}
const uglifiedCode = await pool({taskUtil}).exec("uglify", [{
filePath: resource.getPath(),
code
}]);
resource.setString(uglifiedCode);
return resource;
}));
};
39 changes: 39 additions & 0 deletions lib/processors/uglifier_worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const workerpool = require("workerpool");
const terser = require("terser");
/**
* Preserve comments which contain:
* <ul>
* <li>copyright notice</li>
* <li>license terms</li>
* <li>"@ui5-bundle"</li>
* <li>"@ui5-bundle-raw-include"</li>
* </ul>
*
* @type {RegExp}
*/
const copyrightCommentsAndBundleCommentPattern =
/copyright|\(c\)(?:[0-9]+|\s+[0-9A-za-z])|released under|license|\u00a9|^@ui5-bundle-raw-include |^@ui5-bundle /i;

async function uglify({filePath, code}) {
try {
const result = terser.minify({
[filePath]: code
}, {
output: {
comments: copyrightCommentsAndBundleCommentPattern,
wrap_func_args: false
},
compress: false
});
return result.code;
} catch (error) {
throw new Error(
`Uglification failed with error: ${error.message} in file ${error.filename} ` +
`(line ${error.line}, col ${error.col}, pos ${error.pos})`);
}
}

// create a worker and register public functions
workerpool.worker({
uglify
});
6 changes: 4 additions & 2 deletions lib/tasks/uglify.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ const uglifyProcessor = require("../processors/uglifier");
* @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files
* @param {object} parameters.options Options
* @param {string} parameters.options.pattern Pattern to locate the files to be processed
* @param {module:@ui5/builder.tasks.TaskUtil|object} parameters.taskUtil TaskUtil
* @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
*/
module.exports = function({workspace, options: {pattern}}) {
module.exports = function({workspace, options: {pattern}, taskUtil}) {
return workspace.byGlobSource(pattern)
.then((allResources) => {
return uglifyProcessor({
resources: allResources
resources: allResources,
taskUtil
});
})
.then((processedResources) => {
Expand Down
3 changes: 2 additions & 1 deletion lib/types/application/ApplicationBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ class ApplicationBuilder extends AbstractBuilder {
workspace: resourceCollections.workspace,
options: {
pattern: "/**/*.js"
}
},
taskUtil
});
});

Expand Down
3 changes: 2 additions & 1 deletion lib/types/library/LibraryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ class LibraryBuilder extends AbstractBuilder {
workspace: resourceCollections.workspace,
options: {
pattern: "/resources/**/*.js"
}
},
taskUtil
});
});

Expand Down
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
"semver": "^7.3.2",
"slash": "^3.0.0",
"terser": "^5.3.2",
"workerpool": "^6.0.1",
"xml2js": "^0.4.23",
"yazl": "^2.5.1"
},
Expand Down

0 comments on commit 2d82905

Please sign in to comment.