UNPKG

3.3 kBJavaScriptView Raw
1var path = require('path');
2var fork = require('child_process').fork;
3var assert = require('assert');
4var HappyLogger = require('./HappyLogger');
5var HappyRPCHandler = require('./HappyRPCHandler');
6var Once = require('./fnOnce');
7var WORKER_BIN = path.resolve(__dirname, 'HappyWorkerChannel.js');
8
9function HappyThread(id) {
10 var fd;
11 var callbacks = {};
12
13 return {
14 open: function(onReady) {
15 var emitReady = Once(onReady);
16
17 fd = fork(WORKER_BIN, [id]);
18
19 fd.on('error', throwError);
20 fd.on('exit', function(exitCode) {
21 if (exitCode !== 0) {
22 emitReady('HappyPack: worker exited abnormally with code ' + exitCode);
23 }
24 });
25
26 fd.on('message', function acceptMessageFromWorker(message) {
27 if (message.name === 'READY') {
28 HappyLogger.info('Happy thread[%d] is now open.', id);
29
30 emitReady();
31 }
32 else if (message.name === 'COMPILED') {
33 var filePath = message.sourcePath;
34
35 HappyLogger.info('Thread[%d]: a file has been compiled.', id, filePath);
36
37 assert(typeof callbacks[filePath] === 'function',
38 "HappyThread: expected loader to be pending on source file '" +
39 filePath + "'" + " (this is likely an internal error!)"
40 );
41
42 callbacks[filePath](message);
43 delete callbacks[filePath];
44 }
45 else if (message.name === 'COMPILER_REQUEST') {
46 HappyLogger.debug('forwarding compiler request from worker to plugin:', message);
47
48 // TODO: DRY alert, see .createForegroundWorker() in HappyPlugin.js
49 HappyRPCHandler.execute(message.data.type, message.data.payload, function(error, result) {
50 // console.log('forwarding compiler response from plugin back to worker:', error, result);
51
52 fd.send({
53 name: 'COMPILER_RESPONSE',
54 data: {
55 id: message.data.id,
56 payload: {
57 error: error || null,
58 result: result || null
59 }
60 }
61 });
62 });
63 }
64 });
65 },
66
67 configure: function(compilerOptions, done) {
68 fd.once('message', function(message) {
69 if (message.name === 'CONFIGURE_DONE') {
70 done();
71 }
72 });
73
74 fd.send({
75 name: 'CONFIGURE',
76 data: {
77 compilerOptions: compilerOptions
78 }
79 });
80 },
81
82 /**
83 * @param {Object} params
84 * @param {String} params.compiledPath
85 * @param {Object} params.loaderContext
86 *
87 * @param {Function} done
88 */
89 compile: function(params, done) {
90 assert(params.compiledPath && typeof params.compiledPath === 'string');
91 assert(params.loaderContext && typeof params.loaderContext === 'object');
92
93 assert(!!fd, "You must launch a compilation thread before attemping to use it!!!");
94
95 callbacks[params.loaderContext.resourcePath] = done;
96
97 fd.send({
98 name: 'COMPILE',
99 data: params,
100 });
101 },
102
103 isOpen: function() {
104 return !!fd;
105 },
106
107 close: function() {
108 fd.kill('SIGINT');
109 fd = null;
110
111 HappyLogger.info('Happy thread[%d] is now closed.', id);
112 },
113 };
114}
115
116module.exports = HappyThread;
117
118function throwError(e) {
119 throw e;
120}