@@ -10,10 +10,9 @@ import type {
1010import fs from 'node:fs' ;
1111import { cpus as nodeCpus } from 'node:os' ;
1212import { Worker } from 'node:worker_threads' ;
13- import { isAbsolute , resolve } from 'node:path' ;
13+ import { dirname , extname , isAbsolute , join , resolve } from 'node:path' ;
1414import { ensureDir } from './node-system' ;
1515import { normalizePath } from '../../utils/fs' ;
16- import { createSingleThreadWorker } from '../worker-thread' ;
1716
1817export async function createNodeMainProcess ( sys : System , opts : StaticGenerateOptions ) {
1918 const ssgWorkers : StaticGeneratorWorker [ ] = [ ] ;
@@ -50,45 +49,37 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
5049 sitemapOutFile = resolve ( outDir , sitemapOutFile ) ;
5150 }
5251 }
53-
54- const singleThreadWorker = await createSingleThreadWorker ( sys ) ;
55-
56- const createWorker = ( workerIndex : number ) => {
57- if ( workerIndex === 0 ) {
58- // same thread worker, don't start a new process
59- const ssgSameThreadWorker : StaticGeneratorWorker = {
60- activeTasks : 0 ,
61- totalTasks : 0 ,
62-
63- render : async ( staticRoute ) => {
64- ssgSameThreadWorker . activeTasks ++ ;
65- ssgSameThreadWorker . totalTasks ++ ;
66- const result = await singleThreadWorker ( staticRoute ) ;
67- ssgSameThreadWorker . activeTasks -- ;
68- return result ;
69- } ,
70-
71- terminate : async ( ) => { } ,
72- } ;
73- return ssgSameThreadWorker ;
74- }
75-
52+ const createWorker = ( ) => {
7653 let terminateResolve : ( ( ) => void ) | null = null ;
7754 const mainTasks = new Map < string , WorkerMainTask > ( ) ;
7855
7956 let workerFilePath : string | URL ;
57+ let terminateTimeout : number | null = null ;
8058
59+ // Launch the worker using the package's index module, which bootstraps the worker thread.
8160 if ( typeof __filename === 'string' ) {
82- workerFilePath = __filename ;
61+ // CommonJS path
62+ const ext = extname ( __filename ) || '.js' ;
63+ workerFilePath = join ( dirname ( __filename ) , `index${ ext } ` ) ;
8364 } else {
84- workerFilePath = import . meta. url ;
65+ // ESM path (import.meta.url)
66+ const thisUrl = new URL ( import . meta. url ) ;
67+ const pathname = thisUrl . pathname || '' ;
68+ let ext = '.js' ;
69+ if ( pathname . endsWith ( '.ts' ) ) {
70+ ext = '.ts' ;
71+ } else if ( pathname . endsWith ( '.mjs' ) ) {
72+ ext = '.mjs' ;
73+ }
74+ workerFilePath = new URL ( `./index${ ext } ` , thisUrl ) ;
8575 }
8676
8777 if ( typeof workerFilePath === 'string' && workerFilePath . startsWith ( 'file://' ) ) {
8878 workerFilePath = new URL ( workerFilePath ) ;
8979 }
9080
9181 const nodeWorker = new Worker ( workerFilePath , { workerData : opts } ) ;
82+ nodeWorker . unref ( ) ;
9283
9384 const ssgWorker : StaticGeneratorWorker = {
9485 activeTasks : 0 ,
@@ -116,7 +107,9 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
116107 terminateResolve = resolve ;
117108 nodeWorker . postMessage ( msg ) ;
118109 } ) ;
119- await nodeWorker . terminate ( ) ;
110+ terminateTimeout = setTimeout ( async ( ) => {
111+ await nodeWorker . terminate ( ) ;
112+ } , 1000 ) as unknown as number ;
120113 } ,
121114 } ;
122115
@@ -146,7 +139,11 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
146139 } ) ;
147140
148141 nodeWorker . on ( 'exit' , ( code ) => {
149- if ( code !== 1 ) {
142+ if ( terminateTimeout ) {
143+ clearTimeout ( terminateTimeout ) ;
144+ terminateTimeout = null ;
145+ }
146+ if ( code !== 0 ) {
150147 console . error ( `worker exit ${ code } ` ) ;
151148 }
152149 } ) ;
@@ -200,9 +197,15 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
200197 console . error ( e ) ;
201198 }
202199 }
203- ssgWorkers . length = 0 ;
204200
205201 await Promise . all ( promises ) ;
202+ ssgWorkers . length = 0 ;
203+
204+ // On Windows, give extra time for all workers to fully exit
205+ // This prevents resource conflicts in back-to-back builds
206+ if ( process . platform === 'win32' ) {
207+ await new Promise ( ( resolve ) => setTimeout ( resolve , 300 ) ) ;
208+ }
206209 } ;
207210
208211 if ( sitemapOutFile ) {
@@ -214,7 +217,11 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
214217 }
215218
216219 for ( let i = 0 ; i < maxWorkers ; i ++ ) {
217- ssgWorkers . push ( createWorker ( i ) ) ;
220+ ssgWorkers . push ( createWorker ( ) ) ;
221+ // On Windows, add delay between worker creation to avoid resource contention
222+ if ( process . platform === 'win32' && i < maxWorkers - 1 ) {
223+ await new Promise ( ( resolve ) => setTimeout ( resolve , 100 ) ) ;
224+ }
218225 }
219226
220227 const mainCtx : MainContext = {
0 commit comments