@@ -2,10 +2,49 @@ import { execSync, spawn } from "node:child_process";
2
2
import fs , { type WatchEventType } from "node:fs" ;
3
3
import path from "node:path" ;
4
4
import { fileURLToPath } from "node:url" ;
5
- import { createSpinner , type ProgressBar } from "archons" ;
5
+ import { createSpinner , defineCommand , type ProgressBar , run } from "archons" ;
6
6
import chalk from "chalk" ;
7
7
8
- function isIgnored ( filename : string ) {
8
+ export interface WatchConfig {
9
+ paths : { path : string ; cmd : string } [ ] ;
10
+ dev : {
11
+ exec : string ;
12
+ options : string [ ] ;
13
+ } ;
14
+ }
15
+ const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
16
+ const watchMap : Record < string , WatchConfig > = {
17
+ core : {
18
+ paths : [ { path : path . join ( __dirname , "../src" ) , cmd : "pnpm build" } ] ,
19
+ dev : {
20
+ exec : "pnpm" ,
21
+ options : [ "run" , "--silent" , "preview" , "--clearScreen" , "false" ] ,
22
+ } ,
23
+ } ,
24
+ docs : {
25
+ paths : [ { path : path . join ( __dirname , "../src" ) , cmd : "pnpm build" } ] ,
26
+ dev : {
27
+ exec : "pnpm" ,
28
+ options : [ "run" , "--silent" , "--filter" , "@matechat/react-docs" , "dev" ] ,
29
+ } ,
30
+ } ,
31
+ } ;
32
+ const ignored = [
33
+ "node_modules" ,
34
+ ".git" ,
35
+ ".github" ,
36
+ ".vscode" ,
37
+ "dist" ,
38
+ "build" ,
39
+ "bin" ,
40
+ ".md" ,
41
+ ".d.ts" ,
42
+ "target" ,
43
+ ".cjs" ,
44
+ "doc_build" ,
45
+ ] ;
46
+
47
+ function isIgnored ( filename : string , ignored : string [ ] ) {
9
48
for ( const pattern of ignored ) {
10
49
if ( filename . includes ( pattern ) ) {
11
50
return true ;
@@ -31,68 +70,36 @@ function createArchonsSpinner() {
31
70
return spinner ;
32
71
}
33
72
34
- const cwd = process . cwd ( ) ;
35
- const watchMap = new Map < string , string > ( [
36
- [
37
- path . join ( path . dirname ( fileURLToPath ( import . meta. url ) ) , "../src" ) ,
38
- "pnpm build" ,
39
- ] ,
40
- ] ) ;
41
- const displayPaths = Array . from ( watchMap . keys ( ) )
42
- . map ( ( dirPath ) => chalk . cyan ( path . relative ( cwd , dirPath ) ) )
43
- . join ( ", " ) ;
44
-
45
- const ignored = [
46
- "node_modules" ,
47
- ".git" ,
48
- ".github" ,
49
- ".vscode" ,
50
- "dist" ,
51
- "build" ,
52
- "bin" ,
53
- ".md" ,
54
- ".d.ts" ,
55
- "target" ,
56
- ".cjs" ,
57
- ] ;
58
- const greenPrefix = chalk . green ( "[MateChat]" ) ;
59
-
60
- const spinner = createArchonsSpinner ( ) ;
61
- spinner . enableSteadyTick ( 100 ) ;
62
- spinner . setMessage ( "Initial building..." ) ;
63
- for ( const cmd of watchMap . values ( ) ) {
64
- tryBuild ( cmd , "Building..." , spinner ) ;
73
+ export interface WatchOptions {
74
+ coloredPrefix : string ;
75
+ options : WatchConfig ;
76
+ displayPaths : string ;
77
+ ignoredPaths : string [ ] ;
65
78
}
66
- spinner . finishAndClear ( ) ;
67
- console . clear ( ) ;
68
- console . log ( `${ greenPrefix } Build complete.\n` ) ;
69
- console . log ( `${ greenPrefix } Watching on ${ displayPaths } for changes...` ) ;
79
+ function watch ( {
80
+ coloredPrefix,
81
+ options,
82
+ displayPaths,
83
+ ignoredPaths,
84
+ } : WatchOptions ) {
85
+ let lastBuild = Date . now ( ) ;
70
86
71
- function watch ( ) {
72
87
function createDevProcess ( ) {
73
- let devProcess = spawn (
74
- "pnpm" ,
75
- [ "run" , "--silent" , "preview" , "--clearScreen" , "false" ] ,
76
- {
77
- stdio : "inherit" ,
78
- shell : true ,
79
- } ,
80
- ) ;
88
+ let devProcess = spawn ( options . dev . exec , options . dev . options , {
89
+ stdio : "inherit" ,
90
+ shell : true ,
91
+ } ) ;
81
92
return ( ) => {
82
93
const spinner = createArchonsSpinner ( ) ;
83
- spinner . println ( `${ greenPrefix } Restarting Vite dev server...` ) ;
94
+ spinner . println ( `${ coloredPrefix } Restarting dev server...` ) ;
84
95
while ( ! devProcess . kill ( "SIGINT" ) ) ;
85
96
devProcess . on ( "close" , ( ) => {
86
- devProcess = spawn (
87
- "pnpm" ,
88
- [ "run" , "--silent" , "preview" , "--clearScreen" , "false" ] ,
89
- {
90
- stdio : "inherit" ,
91
- shell : true ,
92
- } ,
93
- ) ;
97
+ devProcess = spawn ( options . dev . exec , options . dev . options , {
98
+ stdio : "inherit" ,
99
+ shell : true ,
100
+ } ) ;
94
101
devProcess . on ( "error" , ( err ) => {
95
- console . error ( `${ greenPrefix } Error restarting dev process:` , err ) ;
102
+ console . error ( `${ coloredPrefix } Error restarting dev process:` , err ) ;
96
103
} ) ;
97
104
spinner . finishAndClear ( ) ;
98
105
} ) ;
@@ -111,29 +118,77 @@ function watch() {
111
118
112
119
restartServer ( ) ;
113
120
114
- if ( filename && ! isIgnored ( filename ) ) {
121
+ if ( filename && ! isIgnored ( filename , ignoredPaths ) ) {
115
122
const spinner = createArchonsSpinner ( ) ;
116
123
spinner . println (
117
- `${ greenPrefix } File ${ chalk . cyan ( filename ) } was ${ eventType } d, rebuilding...` ,
124
+ `${ coloredPrefix } File ${ chalk . cyan (
125
+ filename ,
126
+ ) } was ${ eventType } d, rebuilding...`,
118
127
) ;
119
128
spinner . enableSteadyTick ( 100 ) ;
120
129
if ( [ ".ts" , ".tsx" , ".css" ] . some ( ( ext ) => filename . endsWith ( ext ) ) ) {
121
130
tryBuild ( command , "Rebuilding..." , spinner ) ;
122
131
}
123
132
console . clear ( ) ;
124
- spinner . println ( `${ greenPrefix } Build complete.\n\n` ) ;
133
+ spinner . println ( `${ coloredPrefix } Build complete.\n\n` ) ;
125
134
spinner . println (
126
- `${ greenPrefix } Watching on ${ displayPaths } for changes...` ,
135
+ `${ coloredPrefix } Watching on ${ displayPaths } for changes...` ,
127
136
) ;
128
137
spinner . finishAndClear ( ) ;
129
138
lastBuild = Date . now ( ) ;
130
139
}
131
140
}
132
141
133
- for ( const [ dirPath , cmd ] of watchMap ) {
134
- fs . watch ( dirPath , { recursive : true } , rebuild . bind ( null , cmd ) ) ;
142
+ for ( const { cmd, path } of options . paths ) {
143
+ fs . watch ( path , { recursive : true } , rebuild . bind ( null , cmd ) ) ;
135
144
}
136
145
}
137
146
138
- let lastBuild = Date . now ( ) ;
139
- watch ( ) ;
147
+ const main = defineCommand ( {
148
+ meta : {
149
+ name : "watch" ,
150
+ about : "Watch files and rebuild when changed" ,
151
+ styled : true ,
152
+ } ,
153
+ options : {
154
+ project : {
155
+ type : "option" ,
156
+ default : "core" ,
157
+ short : "p" ,
158
+ help : "Project to watch" ,
159
+ } ,
160
+ } ,
161
+ callback : async ( ctx ) => {
162
+ const cwd = process . cwd ( ) ;
163
+ const project = ctx . args . project as string ;
164
+ if ( ! watchMap [ project ] ) {
165
+ throw new Error ( `Project ${ project } not found` ) ;
166
+ }
167
+
168
+ const displayPaths = watchMap [ project ] . paths
169
+ . map ( ( opts ) => chalk . cyan ( path . relative ( cwd , opts . path ) ) )
170
+ . join ( ", " ) ;
171
+
172
+ const coloredPrefix = chalk . green ( "[MateChat]" ) ;
173
+
174
+ const spinner = createArchonsSpinner ( ) ;
175
+ spinner . enableSteadyTick ( 100 ) ;
176
+ spinner . setMessage ( "Initial building..." ) ;
177
+ for ( const { cmd } of watchMap [ project ] . paths ) {
178
+ tryBuild ( cmd , "Building..." , spinner ) ;
179
+ }
180
+ spinner . finishAndClear ( ) ;
181
+ console . clear ( ) ;
182
+ console . log ( `${ coloredPrefix } Build complete.\n` ) ;
183
+ console . log ( `${ coloredPrefix } Watching on ${ displayPaths } for changes...` ) ;
184
+
185
+ watch ( {
186
+ coloredPrefix,
187
+ options : watchMap [ project ] ,
188
+ displayPaths,
189
+ ignoredPaths : ignored ,
190
+ } ) ;
191
+ } ,
192
+ } ) ;
193
+
194
+ run ( main ) ;
0 commit comments