11import { join } from "node:path" ;
22import { pathToFileURL } from "node:url" ;
33
4- import { discoverModule , discoverWorkspace , getDependencies } from "@calmdownval/workspaces-util" ;
4+ import { discoverModule , discoverWorkspace , getDependencies , type GraphNode , type Module , type TraversalResult } from "@calmdownval/workspaces-util" ;
55import { rollup , type InputOptions , type OutputOptions } from "rollup" ;
66
77import type { Configurator } from "./Entity" ;
8+ import { createStatusReporter , formatTime , print } from "./StatusReporter" ;
89
910export interface BuildContext {
1011 readonly cwd : string ;
@@ -17,13 +18,14 @@ export type TargetEnv =
1718 | "stag"
1819 | "prod" ;
1920
20- export function inEnvs ( ...envs : TargetEnv [ ] ) : Configurator < any > {
21+ export function inEnv ( ...envs : TargetEnv [ ] ) : Configurator < any > {
2122 return ( _ , context ) => envs . includes ( context . targetEnv ) ;
2223}
2324
2425
2526/** @internal */
2627export interface BuildTarget {
28+ readonly name : string ;
2729 readonly input : InputOptions ;
2830 readonly outputs : readonly OutputOptions [ ] ;
2931}
@@ -55,6 +57,7 @@ const ENV_MAP: { readonly [K in string]?: TargetEnv } = {
5557} ;
5658
5759export async function build ( cwd : string = process . cwd ( ) ) {
60+ const buildStartTime = Date . now ( ) ;
5861 try {
5962 // get the origin module to build
6063 const originModule = await discoverModule ( cwd ) ;
@@ -64,56 +67,99 @@ export async function build(cwd: string = process.cwd()) {
6467
6568 // get an ordered queue of dependencies that need to be built
6669 const workspace = await discoverWorkspace ( { cwd } ) ;
67- const moduleQueue = workspace
70+ const tree = workspace
6871 ? getDependencies ( {
6972 workspace,
7073 moduleName : originModule . declaration . name ,
74+ exclude : [ "build-logic" ] ,
7175 } )
72- : [ originModule ] ;
76+ : singleTree ( originModule ) ;
77+
78+ const status = createStatusReporter ( tree . root , "queued" ) ;
7379
7480 // get the target environment
7581 const targetEnv : TargetEnv = process . env . BUILD_ENV
7682 ? ENV_MAP [ process . env . BUILD_ENV ] ?? "prod"
7783 : "prod" ;
7884
7985 // build!
80- for ( const currentModule of moduleQueue ) {
86+ for ( const currentNode of tree . buildOrder ) {
87+ const moduleStartTime = Date . now ( ) ;
88+ status . update ( currentNode , { kind : "pending" } ) ;
89+
8190 const context : BuildContext = {
82- cwd : currentModule . baseDir ,
83- moduleName : currentModule . declaration . name ,
91+ cwd : currentNode . module . baseDir ,
92+ moduleName : currentNode . module . declaration . name ,
8493 targetEnv,
8594 } ;
8695
87- // import the build.targets.mjs definition file
88- currentTasks = [ ] ;
89- process . chdir ( context . cwd ) ;
96+ let target : BuildTarget | null = null ;
9097 try {
91- const url = pathToFileURL ( join ( context . cwd , "build.targets.mjs" ) ) . href ;
98+ // import the build.config.mjs definition file
99+ currentTasks = [ ] ;
100+ process . chdir ( context . cwd ) ;
101+
102+ const url = pathToFileURL ( join ( context . cwd , "build.config.mjs" ) ) . href ;
92103 await import ( url ) ;
93- }
94- catch {
95- // likely no such file exists, skip it...?
96- continue ;
97- }
98104
99- // run queued tasks
100- const targets = (
101- await Promise . all (
102- currentTasks . map ( task => task ( context ) ) ,
105+ // process queued tasks
106+ const targets = (
107+ await Promise . all (
108+ currentTasks . map ( task => task ( context ) ) ,
109+ )
103110 )
104- )
105- . flat ( 1 ) ;
106-
107- // build the targets sequentially
108- for ( const target of targets ) {
109- const bundle = await rollup ( target . input ) ;
110- for ( const output of target . outputs ) {
111- await bundle . write ( output ) ;
111+ . flat ( 1 ) ;
112+
113+ // build targets sequentially
114+ for ( target of targets ) {
115+ const bundle = await rollup ( {
116+ ...target . input ,
117+ onLog ( level , log ) {
118+ if ( level !== "debug" ) {
119+ status . log ( currentNode , log . message ) ;
120+ }
121+ }
122+ } ) ;
123+
124+ for ( const output of target . outputs ) {
125+ await bundle . write ( output ) ;
126+ }
112127 }
128+
129+ const moduleTimeTaken = Date . now ( ) - moduleStartTime ;
130+ status . update ( currentNode , {
131+ kind : "success" ,
132+ timeMs : moduleTimeTaken ,
133+ } ) ;
134+ }
135+ catch ( ex ) {
136+ const moduleTimeTaken = Date . now ( ) - moduleStartTime ;
137+ status . update ( currentNode , {
138+ kind : "error" ,
139+ timeMs : moduleTimeTaken ,
140+ } ) ;
141+
142+ status . log ( currentNode , ( ex as Error ) . toString ( ) ) ;
113143 }
114144 }
115145 }
116146 finally {
117147 currentTasks = null ;
148+
149+ const buildTimeTaken = Date . now ( ) - buildStartTime ;
150+ print ( `\nDone in ${ formatTime ( buildTimeTaken ) } !\n` ) ;
118151 }
119152}
153+
154+ function singleTree ( module : Module ) : TraversalResult {
155+ const node : GraphNode = {
156+ module,
157+ dependencies : [ ] ,
158+ dependents : [ ] ,
159+ } ;
160+
161+ return {
162+ buildOrder : [ node ] ,
163+ root : node ,
164+ } ;
165+ }
0 commit comments