11// @flow
22
3+ // $FlowFixMe
4+ const { Worker} = require ( "worker_threads" ) ;
35const { crawl} = require ( "./helper/crawl" ) ;
46const fs = require ( "fs" ) ;
57const fse = require ( "fs-extra" ) ;
68const hljs = require ( "highlight.js" ) ;
9+ const os = require ( "os" ) ;
710const path = require ( "path" ) ;
811const { traverse} = require ( "@webdoc/model" ) ;
912const {
@@ -150,12 +153,14 @@ exports.publish = async function publish(options /*: PublishOptions */) {
150153 } ) ;
151154
152155 await outStaticFiles ( outDir , config ) ;
153- outSource ( outDir , pipeline , options . config , source ) ;
154- outExplorerData ( outDir , crawlData ) ;
155- outMainPage ( indexRelative ? path . join ( outDir , indexRelative ) : null , pipeline , options . config ) ;
156- outIndexes ( outDir , pipeline , options . config , crawlData . index ) ;
157- outReference ( outDir , pipeline , options . config , docTree , crawlData . reference ) ;
158- outTutorials ( outDir , pipeline , options . config , docTree , crawlData . tutorials ) ;
156+ await Promise . all ( [
157+ outSource ( outDir , pipeline , options . config , source , options . cmdLine . mainThread || false ) ,
158+ outExplorerData ( outDir , crawlData ) ,
159+ outMainPage ( indexRelative ? path . join ( outDir , indexRelative ) : null , pipeline , options . config ) ,
160+ outIndexes ( outDir , pipeline , options . config , crawlData . index ) ,
161+ outReference ( outDir , pipeline , options . config , docTree , crawlData . reference ) ,
162+ outTutorials ( outDir , pipeline , options . config , docTree , crawlData . tutorials ) ,
163+ ] ) ;
159164
160165 pipeline . close ( ) ;
161166} ;
@@ -209,10 +214,13 @@ async function outStaticFiles(
209214}
210215
211216// Write the explorer JSON data in the output directory
212- function outExplorerData ( outDir /*: string */ , crawlData /*: CrawlData */ ) {
217+ async function outExplorerData (
218+ outDir /*: string */ ,
219+ crawlData /*: CrawlData */ ,
220+ ) /*: Promise<void> */ {
213221 const explorerDir = path . join ( outDir , "./explorer" ) ;
214222
215- fse . ensureDir ( explorerDir ) . then ( ( ) => {
223+ return fse . ensureDir ( explorerDir ) . then ( ( ) => new Promise ( ( resolve ) => {
216224 fse . writeFile (
217225 path . join ( explorerDir , "./reference.json" ) ,
218226 JSON . stringify ( crawlData . reference ) ,
@@ -228,18 +236,21 @@ function outExplorerData(outDir /*: string */, crawlData /*: CrawlData */) {
228236 "utf8" ,
229237 ( err ) => {
230238 if ( err ) throw err ;
239+ resolve ( ) ;
231240 } ,
232241 ) ;
242+ } else {
243+ resolve ( ) ;
233244 }
234- } ) ;
245+ } ) ) ;
235246}
236247
237248// Render the main-page into index.tmpl (outputFile)
238249async function outMainPage (
239250 outputFile /*: ?string */ ,
240251 pipeline /*: TemplatePipeline */ ,
241252 config /*: WebdocConfig */ ,
242- ) {
253+ ) /*: Promise<void> */ {
243254 if ( outputFile && config . template . readme ) {
244255 const readmeFile = path . join ( process . cwd ( ) , config . template . readme ) ;
245256
@@ -252,28 +263,97 @@ async function outMainPage(
252263 }
253264}
254265
255- function outSource (
266+ async function outSource (
256267 outDir /*: string */ ,
257268 pipeline /*: TemplatePipeline */ ,
258269 config /*: ConfigSchema */ ,
259270 source /*: ?$ReadOnlyArray<SourceFile> */ ,
260- ) {
261- if ( source ) {
271+ mainThread /*:: ?: boolean */ ,
272+ ) /*: Promise<void> */ {
273+ if ( ! source ) return ;
274+
275+ function renderSource ( file /*: SourceFile */ , raw /*: string */ ) {
276+ const pkgName = file . package . name || "" ;
277+ const pkgRelativePath = path . relative ( file . package . location || "" , file . path ) ;
278+ const outFile = path . join ( pkgName , pkgRelativePath + ".html" ) ;
279+
280+ pipeline . render ( "source.tmpl" , {
281+ appBar : { current : "sources" } ,
282+ env : config ,
283+ raw,
284+ title : path . basename ( file . path ) ,
285+ } , {
286+ outputFile : path . join ( outDir , outFile ) ,
287+ } ) ;
288+ }
289+
290+ const workerCount = Math . min ( os . cpus ( ) . length , 1 + Math . floor ( source . length / 32 ) ) ;
291+
292+ if ( workerCount > 1 && ! mainThread ) {
293+ const workers = new Array ( workerCount ) ;
294+ const renderJobs /*: Array<{
295+ resolve: Function,
296+ reject: Function,
297+ promise: Promise<void>,
298+ }> */ = new Array ( source . length ) ; // eslint-disable-line operator-linebreak
299+
300+ const onMessage = function onMessage (
301+ {
302+ id,
303+ file,
304+ error,
305+ result,
306+ } /*: {
307+ id: number,
308+ file: string,
309+ error: boolean,
310+ result: ?string }
311+ */ ,
312+ ) {
313+ if ( error || typeof result !== "string" ) {
314+ renderJobs [ id ] . reject ( "Error in highlighting worker" ) ;
315+ } else {
316+ const raw = result ;
317+ const sourceFile = source [ id ] ;
318+
319+ renderSource ( sourceFile , raw ) ;
320+ renderJobs [ id ] . resolve ( ) ;
321+ }
322+ } ;
323+
324+ const startTime = Date . now ( ) ;
325+ console . log ( "Creating " + workerCount + " workers for highlighting source code." ) ;
326+
327+ for ( let i = 0 ; i < workers . length ; i ++ ) {
328+ workers [ i ] = new Worker ( path . resolve ( __dirname , "./helper/workers/hl.js" ) ) ;
329+ workers [ i ] . on ( "message" , onMessage ) ;
330+ }
331+
332+ for ( let i = 0 ; i < source . length ; i ++ ) {
333+ let resolveFn /*: () => void */ ;
334+ let rejectFn /*: () => void */ ;
335+ const promise = new Promise ( ( resolve , reject ) => {
336+ resolveFn = resolve ;
337+ rejectFn = reject ;
338+ } ) ;
339+ renderJobs [ i ] = { resolve : resolveFn , reject : rejectFn , promise} ;
340+
341+ workers [ i % workers . length ] . postMessage ( {
342+ id : i ,
343+ file : source [ i ] . path ,
344+ } ) ;
345+ }
346+
347+ await Promise . all ( renderJobs . map ( ( job ) => job . promise ) ) ;
348+ await Promise . all ( workers . map ( ( worker ) => worker . terminate ( ) ) ) ;
349+
350+ console . log ( "Rendering sources took " + ( Date . now ( ) - startTime ) + "ms time!" ) ;
351+ } else {
262352 for ( const file of source ) {
263353 const raw = hljs . highlightAuto (
264354 fs . readFileSync ( path . resolve ( process . cwd ( ) , file . path ) , "utf8" ) ,
265355 ) . value ;
266- const pkgName = file . package . name || "" ;
267- const outFile = path . join ( pkgName , file . path + ".html" ) ;
268-
269- pipeline . render ( "source.tmpl" , {
270- appBar : { current : "sources" } ,
271- env : config ,
272- raw,
273- title : path . basename ( file . path ) ,
274- } , {
275- outputFile : path . join ( outDir , outFile ) ,
276- } ) ;
356+ renderSource ( file , raw ) ;
277357 }
278358 }
279359}
@@ -283,7 +363,7 @@ async function outReadme(
283363 pipeline /*: TemplatePipeline */ ,
284364 config /*: WebdocConfig */ ,
285365 readmeFile /*: string */ ,
286- ) {
366+ ) /*: Promise<void> */ {
287367 if ( ! ( await fse . pathExists ( readmeFile ) ) ) {
288368 return ;
289369 }
@@ -310,12 +390,12 @@ async function outReadme(
310390 } , { outputFile} ) ;
311391}
312392
313- function outIndexes (
393+ async function outIndexes (
314394 outDir /*: string */ ,
315395 pipeline /*: TemplatePipeline */ ,
316396 config /*: WebdocConfig */ ,
317397 index /*: Index */ ,
318- ) {
398+ ) /*: Promise<void> */ {
319399 const KEY_TO_TITLE = {
320400 "classes" : "Class Index" ,
321401 } ;
@@ -341,13 +421,13 @@ function outIndexes(
341421 }
342422}
343423
344- function outReference (
424+ async function outReference (
345425 outDir /*: string */ ,
346426 pipeline /*: TemplatePipeline */ ,
347427 config /*: WebdocConfig */ ,
348428 docTree /*: RootDoc */ ,
349429 explorerData /* any */ ,
350- ) {
430+ ) /*: Promise<void> */ {
351431 // Don't output if nothing's there
352432 if ( ! docTree . members . length ) {
353433 return ;
@@ -397,13 +477,13 @@ function outReference(
397477 }
398478}
399479
400- function outTutorials (
480+ async function outTutorials (
401481 outDir /*: string */ ,
402482 pipeline /*: TemplatePipeline */ ,
403483 config /*: WebdocConfig */ ,
404484 docTree /*: RootDoc */ ,
405485 explorerData /* any */ ,
406- ) {
486+ ) /*: Promise<void> */ {
407487 function out ( parent /*: { members: any[] } */ ) {
408488 return function renderRecursive ( tutorial /*: TutorialDoc */ , i /*: number */ ) {
409489 const uri = linker . getURI ( tutorial , true ) ;
0 commit comments