js.js (3806B)
1 const globby = require('globby'); 2 const path = require('path'); 3 const os = require('os'); 4 const fs = require('fs-extra'); 5 const cluster = require('cluster'); 6 const { getSignatures, compareSignatures, getFileSignature, writeSignatures, cleanUp, onSuccess, onError, onProgress } = require('./utils'); 7 const { jsFiles, ignoreMask } = require('./config'); 8 9 const NODE_ENV = process.env.NODE_ENV; 10 const ROOT = path.resolve(__dirname, '..'); 11 12 async function getJS(source, options, signatures) { 13 const t1 = Date.now(); 14 const matchingJSFiles = await globby(source, Object.assign({ cwd: ROOT }, options)); 15 const cpuCount = os.cpus().length; 16 const totalCount = matchingJSFiles.length; 17 var count = 0; 18 var isError = false; 19 20 cluster.setupMaster({ 21 exec: path.join(__dirname, 'babel-worker.js') 22 }); 23 24 // check signatures, collect signatures for files to be processes 25 const newFilesSignatures = {}; 26 const filesForProcessing = []; 27 var f; 28 while ((f = matchingJSFiles.pop()) != null) { 29 const newFileSignature = await getFileSignature(f); 30 const dest = path.join('build', f); 31 f = path.normalize(f); 32 if (f in signatures) { 33 if (compareSignatures(newFileSignature, signatures[f])) { 34 try { 35 await fs.access(dest, fs.constants.F_OK); 36 continue; 37 } catch (_) { 38 // file does not exists in build, fallback to browserifing 39 } 40 } 41 } 42 filesForProcessing.push(f); 43 newFilesSignatures[f] = newFileSignature; 44 } 45 46 // shortcut if no files need rebuilding 47 if (Object.keys(filesForProcessing).length === 0) { 48 const t2 = Date.now(); 49 return Promise.resolve({ 50 action: 'js', 51 count, 52 totalCount, 53 processingTime: t2 - t1 54 }); 55 } 56 57 // distribute processing among workers 58 const workerCount = Math.min(cpuCount, filesForProcessing.length); 59 var workersActive = workerCount; 60 NODE_ENV == 'debug' && console.log(`Will process ${filesForProcessing.length} files using ${workerCount} processes`); 61 return new Promise((resolve, reject) => { 62 for (let i = 0; i < workerCount; i++) { 63 var worker = cluster.fork(); 64 65 worker.on('message', function(ev) { 66 if (ev.error) { 67 isError = true; 68 let errorMsg = `Failed while processing ${ev.sourcefile}: ${ev.error}`; 69 reject(errorMsg); 70 } else { 71 signatures[ev.sourcefile] = newFilesSignatures[ev.sourcefile]; 72 73 if (ev.isSkipped) { 74 NODE_ENV == 'debug' && console.log(`process ${this.id} SKIPPED ${ev.sourcefile}`); 75 } else { 76 NODE_ENV == 'debug' && console.log(`process ${this.id} took ${ev.processingTime} ms to process ${ev.sourcefile} into ${ev.outfile}`); 77 NODE_ENV != 'debug' && onProgress(ev.sourcefile, ev.outfile, 'js'); 78 count++; 79 } 80 } 81 82 let nextFile = filesForProcessing.pop(); 83 84 if (!isError && nextFile) { 85 NODE_ENV == 'debug' && console.log(`process ${this.id} scheduled to process ${nextFile}`); 86 this.send({ 87 file: nextFile 88 }); 89 } else { 90 if (this.isConnected()) { 91 this.kill(); 92 } 93 NODE_ENV == 'debug' && console.log(`process ${this.id} has terminated`); 94 if (!--workersActive) { 95 const t2 = Date.now(); 96 resolve({ 97 action: 'js', 98 count, 99 totalCount, 100 processingTime: t2 - t1 101 }); 102 } 103 } 104 }); 105 106 let nextFile = filesForProcessing.pop(); 107 NODE_ENV == 'debug' && console.log(`process ${worker.id} scheduled to process ${nextFile}`); 108 worker.send({ 109 file: nextFile 110 }); 111 } 112 }); 113 } 114 115 module.exports = getJS; 116 117 if (require.main === module) { 118 (async () => { 119 try { 120 const signatures = await getSignatures(); 121 onSuccess(await getJS(jsFiles, { ignore: ignoreMask }, signatures)); 122 onSuccess(await cleanUp(signatures)); 123 await writeSignatures(signatures); 124 } catch (err) { 125 process.exitCode = 1; 126 global.isError = true; 127 onError(err); 128 } 129 })(); 130 }