Skip to content

Commit

Permalink
fix: parallel in multi compilation mode
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi authored May 6, 2020
1 parent c0f45e2 commit 2b5961c
Show file tree
Hide file tree
Showing 4 changed files with 364 additions and 20 deletions.
34 changes: 14 additions & 20 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,20 +428,13 @@ class TerserPlugin {
yield task;
}

async runTask(task) {
if (this.worker) {
return this.worker.transform(serialize(task));
}

return minifyFn(task);
}

async runTasks() {
const availableNumberOfCores = TerserPlugin.getAvailableNumberOfCores(
this.options.parallel
);

let concurrency = Infinity;
let worker;

if (availableNumberOfCores > 0) {
// Do not create unnecessary workers when the number of files is less than the available cores, it saves memory
Expand All @@ -452,18 +445,18 @@ class TerserPlugin {

concurrency = numWorkers;

this.worker = new Worker(require.resolve('./minify'), { numWorkers });
worker = new Worker(require.resolve('./minify'), { numWorkers });

// https://github.com/facebook/jest/issues/8872#issuecomment-524822081
const workerStdout = this.worker.getStdout();
const workerStdout = worker.getStdout();

if (workerStdout) {
workerStdout.on('data', (chunk) => {
return process.stdout.write(chunk);
});
}

const workerStderr = this.worker.getStderr();
const workerStderr = worker.getStderr();

if (workerStderr) {
workerStderr.on('data', (chunk) => {
Expand All @@ -480,7 +473,11 @@ class TerserPlugin {
let taskResult;

try {
taskResult = await this.runTask(task);
if (worker) {
taskResult = await worker.transform(serialize(task));
} else {
taskResult = minifyFn(task);
}
} catch (error) {
taskResult = { error };
}
Expand Down Expand Up @@ -518,15 +515,13 @@ class TerserPlugin {
);
}

return Promise.all(scheduledTasks);
}
return Promise.all(scheduledTasks).then(() => {
if (worker) {
return worker.end();
}

async exitTasks() {
if (!this.worker) {
return Promise.resolve();
}

return this.worker.end();
});
}

apply(compiler) {
Expand Down Expand Up @@ -610,7 +605,6 @@ class TerserPlugin {
);

await this.runTasks();
await this.exitTasks();

Object.keys(allExtractedComments).forEach((commentsFilename) => {
const extractedComments = new Set([
Expand Down
73 changes: 73 additions & 0 deletions test/TerserPlugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,79 @@ describe('TerserPlugin', () => {
});
});

it('should work in multi compiler mode with the one plugin', async () => {
const plugins = [new TerserPlugin()];
const multiCompiler = getCompiler([
{
mode: 'production',
bail: true,
cache: getCompiler.isWebpack4() ? false : { type: 'memory' },
entry: `${__dirname}/fixtures/entry.js`,
output: {
path: `${__dirname}/dist`,
filename: '[name]-1.js',
chunkFilename: '[id]-1.[name].js',
},
optimization: {
minimize: false,
},
},
{
mode: 'production',
bail: true,
cache: getCompiler.isWebpack4() ? false : { type: 'memory' },
entry: `${__dirname}/fixtures/entry.js`,
output: {
path: `${__dirname}/dist`,
filename: '[name]-2.js',
chunkFilename: '[id]-2.[name].js',
},
optimization: {
minimize: false,
},
plugins,
},
{
mode: 'production',
bail: true,
cache: getCompiler.isWebpack4() ? false : { type: 'memory' },
entry: `${__dirname}/fixtures/import-export/entry.js`,
output: {
path: `${__dirname}/dist-MultiCompiler`,
filename: '[name]-3.js',
chunkFilename: '[id]-3.[name].js',
},
optimization: {
minimize: false,
},
plugins,
},
]);

const emptyPluginCount = countPlugins(multiCompiler.compilers[0]);
const expectedPluginCount = countPlugins(multiCompiler.compilers[1]);

expect(emptyPluginCount).not.toEqual(expectedPluginCount);

multiCompiler.compilers.slice(2).forEach((compiler) => {
const pluginCount = countPlugins(compiler);

expect(pluginCount).not.toEqual(emptyPluginCount);
expect(pluginCount).toEqual(expectedPluginCount);
expect(pluginCount).toMatchSnapshot('compiler plugin count');
});

const multiStats = await compile(multiCompiler);

multiStats.stats.forEach((stats, index) => {
expect(
readsAssets(multiCompiler.compilers[index], stats)
).toMatchSnapshot('assets');
expect(getErrors(stats)).toMatchSnapshot('errors');
expect(getWarnings(stats)).toMatchSnapshot('warnings');
});
});

it('should work as a plugin', async () => {
const compiler = getCompiler({
plugins: [new TerserPlugin()],
Expand Down
164 changes: 164 additions & 0 deletions test/__snapshots__/TerserPlugin.test.js.snap.webpack4
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,170 @@ exports[`TerserPlugin should work as a plugin: errors 1`] = `Array []`;

exports[`TerserPlugin should work as a plugin: warnings 1`] = `Array []`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: assets 1`] = `
Object {
"main-1.js": "/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = \\"\\";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {

// foo
/* @preserve*/
// bar
const a = 2 + 2;

module.exports = function Foo() {
const b = 2 + 2;
console.log(b + 1 + 2);
};


/***/ })
/******/ ]);",
}
`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: assets 2`] = `
Object {
"main-2.js": "!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&\\"object\\"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,\\"default\\",{enumerable:!0,value:e}),2&t&&\\"string\\"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,\\"a\\",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p=\\"\\",n(n.s=0)}([function(e,t){e.exports=function(){console.log(7)}}]);",
}
`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: assets 3`] = `
Object {
"main-3.js": "!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&\\"object\\"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,\\"default\\",{enumerable:!0,value:e}),2&t&&\\"string\\"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,\\"a\\",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p=\\"\\",r(r.s=0)}([function(e,t,r){\\"use strict\\";r.r(t);t.default=function(){const e=\\"baz\\"+Math.random();return()=>({a:\\"foobar\\"+e,b:\\"foo\\",baz:e})}}]);",
}
`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: compiler plugin count 1`] = `
Object {
"additionalPass": 0,
"afterCompile": 0,
"afterEmit": 1,
"afterEnvironment": 0,
"afterPlugins": 0,
"afterResolvers": 2,
"assetEmitted": 0,
"beforeCompile": 0,
"beforeRun": 1,
"compilation": 42,
"compile": 0,
"contextModuleFactory": 0,
"done": 1,
"emit": 0,
"entryOption": 1,
"environment": 0,
"failed": 0,
"infrastructureLog": 0,
"infrastructurelog": 0,
"invalid": 1,
"make": 1,
"normalModuleFactory": 1,
"run": 0,
"shouldEmit": 1,
"thisCompilation": 3,
"watchClose": 0,
"watchRun": 0,
}
`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: errors 1`] = `Array []`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: errors 2`] = `Array []`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: errors 3`] = `Array []`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: warnings 1`] = `Array []`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: warnings 2`] = `Array []`;

exports[`TerserPlugin should work in multi compiler mode with the one plugin: warnings 3`] = `Array []`;

exports[`TerserPlugin should work in multi compiler mode: assets 1`] = `
Object {
"main-1.js": "/******/ (function(modules) { // webpackBootstrap
Expand Down
Loading

0 comments on commit 2b5961c

Please sign in to comment.