123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- "use strict";
- var _fs = _interopRequireDefault(require("fs"));
- var _module = _interopRequireDefault(require("module"));
- var _querystring = _interopRequireDefault(require("querystring"));
- var _loaderRunner = _interopRequireDefault(require("loader-runner"));
- var _queue = _interopRequireDefault(require("neo-async/queue"));
- var _jsonParseBetterErrors = _interopRequireDefault(require("json-parse-better-errors"));
- var _schemaUtils = require("schema-utils");
- var _readBuffer = _interopRequireDefault(require("./readBuffer"));
- var _serializer = require("./serializer");
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- /* eslint-disable no-console */
- const writePipe = _fs.default.createWriteStream(null, {
- fd: 3
- });
- const readPipe = _fs.default.createReadStream(null, {
- fd: 4
- });
- writePipe.on('finish', onTerminateWrite);
- readPipe.on('end', onTerminateRead);
- writePipe.on('close', onTerminateWrite);
- readPipe.on('close', onTerminateRead);
- readPipe.on('error', onError);
- writePipe.on('error', onError);
- const PARALLEL_JOBS = +process.argv[2] || 20;
- let terminated = false;
- let nextQuestionId = 0;
- const callbackMap = Object.create(null);
- function onError(error) {
- console.error(error);
- }
- function onTerminateRead() {
- terminateRead();
- }
- function onTerminateWrite() {
- terminateWrite();
- }
- function writePipeWrite(...args) {
- if (!terminated) {
- writePipe.write(...args);
- }
- }
- function writePipeCork() {
- if (!terminated) {
- writePipe.cork();
- }
- }
- function writePipeUncork() {
- if (!terminated) {
- writePipe.uncork();
- }
- }
- function terminateRead() {
- terminated = true;
- readPipe.removeAllListeners();
- }
- function terminateWrite() {
- terminated = true;
- writePipe.removeAllListeners();
- }
- function terminate() {
- terminateRead();
- terminateWrite();
- }
- function toErrorObj(err) {
- return {
- message: err.message,
- details: err.details,
- stack: err.stack,
- hideStack: err.hideStack
- };
- }
- function toNativeError(obj) {
- if (!obj) return null;
- const err = new Error(obj.message);
- err.details = obj.details;
- err.missing = obj.missing;
- return err;
- }
- function writeJson(data) {
- writePipeCork();
- process.nextTick(() => {
- writePipeUncork();
- });
- const lengthBuffer = Buffer.alloc(4);
- const messageBuffer = Buffer.from(JSON.stringify(data, _serializer.replacer), 'utf-8');
- lengthBuffer.writeInt32BE(messageBuffer.length, 0);
- writePipeWrite(lengthBuffer);
- writePipeWrite(messageBuffer);
- }
- const queue = (0, _queue.default)(({
- id,
- data
- }, taskCallback) => {
- try {
- const resolveWithOptions = (context, request, callback, options) => {
- callbackMap[nextQuestionId] = callback;
- writeJson({
- type: 'resolve',
- id,
- questionId: nextQuestionId,
- context,
- request,
- options
- });
- nextQuestionId += 1;
- };
- const buildDependencies = [];
- _loaderRunner.default.runLoaders({
- loaders: data.loaders,
- resource: data.resource,
- readResource: _fs.default.readFile.bind(_fs.default),
- context: {
- version: 2,
- fs: _fs.default,
- loadModule: (request, callback) => {
- callbackMap[nextQuestionId] = (error, result) => callback(error, ...result);
- writeJson({
- type: 'loadModule',
- id,
- questionId: nextQuestionId,
- request
- });
- nextQuestionId += 1;
- },
- resolve: (context, request, callback) => {
- resolveWithOptions(context, request, callback);
- },
- // eslint-disable-next-line consistent-return
- getResolve: options => (context, request, callback) => {
- if (callback) {
- resolveWithOptions(context, request, callback, options);
- } else {
- return new Promise((resolve, reject) => {
- resolveWithOptions(context, request, (err, result) => {
- if (err) {
- reject(err);
- } else {
- resolve(result);
- }
- }, options);
- });
- }
- },
- // Not an arrow function because it uses this
- getOptions(schema) {
- // loaders, loaderIndex will be defined by runLoaders
- const loader = this.loaders[this.loaderIndex]; // Verbatim copy from
- // https://github.com/webpack/webpack/blob/v5.31.2/lib/NormalModule.js#L471-L508
- // except eslint/prettier differences
- // -- unfortunate result of getOptions being synchronous functions.
- let {
- options
- } = loader;
- if (typeof options === 'string') {
- if (options.substr(0, 1) === '{' && options.substr(-1) === '}') {
- try {
- options = (0, _jsonParseBetterErrors.default)(options);
- } catch (e) {
- throw new Error(`Cannot parse string options: ${e.message}`);
- }
- } else {
- options = _querystring.default.parse(options, '&', '=', {
- maxKeys: 0
- });
- }
- } // eslint-disable-next-line no-undefined
- if (options === null || options === undefined) {
- options = {};
- }
- if (schema) {
- let name = 'Loader';
- let baseDataPath = 'options';
- let match; // eslint-disable-next-line no-cond-assign
- if (schema.title && (match = /^(.+) (.+)$/.exec(schema.title))) {
- [, name, baseDataPath] = match;
- }
- (0, _schemaUtils.validate)(schema, options, {
- name,
- baseDataPath
- });
- }
- return options;
- },
- emitWarning: warning => {
- writeJson({
- type: 'emitWarning',
- id,
- data: toErrorObj(warning)
- });
- },
- emitError: error => {
- writeJson({
- type: 'emitError',
- id,
- data: toErrorObj(error)
- });
- },
- exec: (code, filename) => {
- const module = new _module.default(filename, void 0);
- module.paths = _module.default._nodeModulePaths((void 0).context); // eslint-disable-line no-underscore-dangle
- module.filename = filename;
- module._compile(code, filename); // eslint-disable-line no-underscore-dangle
- return module.exports;
- },
- addBuildDependency: filename => {
- buildDependencies.push(filename);
- },
- options: {
- context: data.optionsContext
- },
- webpack: true,
- 'thread-loader': true,
- sourceMap: data.sourceMap,
- target: data.target,
- minimize: data.minimize,
- resourceQuery: data.resourceQuery,
- rootContext: data.rootContext
- }
- }, (err, lrResult) => {
- const {
- result,
- cacheable,
- fileDependencies,
- contextDependencies,
- missingDependencies
- } = lrResult;
- const buffersToSend = [];
- const convertedResult = Array.isArray(result) && result.map(item => {
- const isBuffer = Buffer.isBuffer(item);
- if (isBuffer) {
- buffersToSend.push(item);
- return {
- buffer: true
- };
- }
- if (typeof item === 'string') {
- const stringBuffer = Buffer.from(item, 'utf-8');
- buffersToSend.push(stringBuffer);
- return {
- buffer: true,
- string: true
- };
- }
- return {
- data: item
- };
- });
- writeJson({
- type: 'job',
- id,
- error: err && toErrorObj(err),
- result: {
- result: convertedResult,
- cacheable,
- fileDependencies,
- contextDependencies,
- missingDependencies,
- buildDependencies
- },
- data: buffersToSend.map(buffer => buffer.length)
- });
- buffersToSend.forEach(buffer => {
- writePipeWrite(buffer);
- });
- setImmediate(taskCallback);
- });
- } catch (e) {
- writeJson({
- type: 'job',
- id,
- error: toErrorObj(e)
- });
- taskCallback();
- }
- }, PARALLEL_JOBS);
- function dispose() {
- terminate();
- queue.kill();
- process.exit(0);
- }
- function onMessage(message) {
- try {
- const {
- type,
- id
- } = message;
- switch (type) {
- case 'job':
- {
- queue.push(message);
- break;
- }
- case 'result':
- {
- const {
- error,
- result
- } = message;
- const callback = callbackMap[id];
- if (callback) {
- const nativeError = toNativeError(error);
- callback(nativeError, result);
- } else {
- console.error(`Worker got unexpected result id ${id}`);
- }
- delete callbackMap[id];
- break;
- }
- case 'warmup':
- {
- const {
- requires
- } = message; // load modules into process
- requires.forEach(r => require(r)); // eslint-disable-line import/no-dynamic-require, global-require
- break;
- }
- default:
- {
- console.error(`Worker got unexpected job type ${type}`);
- break;
- }
- }
- } catch (e) {
- console.error(`Error in worker ${e}`);
- }
- }
- function readNextMessage() {
- (0, _readBuffer.default)(readPipe, 4, (lengthReadError, lengthBuffer) => {
- if (lengthReadError) {
- console.error(`Failed to communicate with main process (read length) ${lengthReadError}`);
- return;
- }
- const length = lengthBuffer.length && lengthBuffer.readInt32BE(0);
- if (length === 0) {
- // worker should dispose and exit
- dispose();
- return;
- }
- (0, _readBuffer.default)(readPipe, length, (messageError, messageBuffer) => {
- if (terminated) {
- return;
- }
- if (messageError) {
- console.error(`Failed to communicate with main process (read message) ${messageError}`);
- return;
- }
- const messageString = messageBuffer.toString('utf-8');
- const message = JSON.parse(messageString, _serializer.reviver);
- onMessage(message);
- setImmediate(() => readNextMessage());
- });
- });
- } // start reading messages from main process
- readNextMessage();
|