1
+ import * as path from 'node:path'
2
+ import * as url from 'node:url'
3
+ import * as fs from 'node:fs'
4
+ import * as assert from 'node:assert/strict'
5
+ import * as threads from 'node:worker_threads'
6
+ import * as esb from 'esbuild'
7
+ import ts from 'typescript'
8
+
9
+ type Worker_Data = {
10
+ is_dev : boolean ,
11
+ dist_dirname : string ,
12
+ ts_entries : string [ ] ,
13
+ }
14
+
15
+ const filename = url . fileURLToPath ( import . meta. url )
16
+ // const dirname = path.dirname(filename)
17
+
18
+ export const DEFAULT_EXTERNAL_DEPS : string [ ] = [
19
+ 'solid-js' ,
20
+ 'solid-js/*' ,
21
+ '@solid-devtools/shared/*' ,
22
+ ]
23
+
24
+ export function get_external_deps_from_pkg ( pkg_filename : string ) : string [ ] {
25
+ let pkg = JSON . parse ( fs . readFileSync ( pkg_filename , 'utf-8' ) ) as any
26
+ return [
27
+ ...DEFAULT_EXTERNAL_DEPS ,
28
+ ...Object . keys ( { ...pkg ?. peerDependencies , ...pkg ?. dependencies } ) ,
29
+ ]
30
+ }
31
+
32
+ export function get_is_dev_from_args ( ) : boolean {
33
+ return process . argv . includes ( '--watch' )
34
+ }
35
+
36
+ export function get_common_esbuild_options ( is_dev : boolean , dist_dirname : string ) : esb . BuildOptions {
37
+ return {
38
+ platform : 'browser' ,
39
+ format : 'esm' ,
40
+ target : 'esnext' ,
41
+ sourcemap : is_dev ,
42
+ outdir : dist_dirname ,
43
+ bundle : true ,
44
+ splitting : true ,
45
+ treeShaking : ! is_dev ,
46
+ logLevel : is_dev ? 'debug' : 'warning' ,
47
+ }
48
+ }
49
+
50
+ function main ( ) {
51
+
52
+ if ( threads . isMainThread )
53
+ return
54
+
55
+ /* Worker - runs the ts program */
56
+
57
+ const data = threads . workerData as Worker_Data
58
+
59
+ const port = threads . parentPort
60
+ assert . ok ( port != null )
61
+
62
+ const options = get_tsc_options ( data . dist_dirname )
63
+
64
+ /* Watch - never terminates */
65
+ if ( data . is_dev ) {
66
+ const host = ts . createWatchCompilerHost (
67
+ data . ts_entries ,
68
+ options ,
69
+ ts . sys ,
70
+ undefined ,
71
+ report_diagnostic ,
72
+ report_watch_status_changed ,
73
+ )
74
+ ts . createWatchProgram ( host )
75
+ }
76
+ /* Emit once and exit */
77
+ else {
78
+ let begin = performance . now ( )
79
+ ts . createProgram ( data . ts_entries , options ) . emit ( )
80
+ // eslint-disable-next-line no-console
81
+ console . log ( `DTS complete in ${ ( performance . now ( ) - begin ) . toFixed ( 2 ) } ms` )
82
+ process . exit ( 0 )
83
+ }
84
+ }
85
+
86
+ export async function build (
87
+ options : esb . BuildOptions [ ] ,
88
+ ts_entries : string [ ] ,
89
+ is_dev : boolean ,
90
+ dist_dirname : string = path . join ( process . cwd ( ) , `dist` ) ,
91
+ ) : Promise < void > {
92
+
93
+ /* Clear dist when building to prod */
94
+ if ( ! is_dev ) {
95
+ fs . rmSync ( dist_dirname , { recursive : true , force : true } )
96
+ }
97
+
98
+ const worker = new threads . Worker ( filename , {
99
+ workerData : { is_dev, dist_dirname, ts_entries} satisfies Worker_Data
100
+ } )
101
+
102
+ worker . on ( 'error' , ( error ) => {
103
+ // eslint-disable-next-line no-console
104
+ console . error ( `Worker error:` , error )
105
+ } )
106
+
107
+ /* Watch - never terminates */
108
+ if ( is_dev ) {
109
+ for ( const option of options ) {
110
+ esb . context ( option )
111
+ . then ( ctx => ctx . watch ( ) )
112
+ }
113
+ }
114
+ /* Build once - wait for all to finish */
115
+ else {
116
+ let begin = performance . now ( )
117
+ await Promise . all ( options . map ( option => esb . build ( option ) ) )
118
+ // eslint-disable-next-line no-console
119
+ console . log ( `JS built in ${ ( performance . now ( ) - begin ) . toFixed ( 2 ) } ms` )
120
+ }
121
+ }
122
+
123
+ const format_host : ts . FormatDiagnosticsHost = {
124
+ getCurrentDirectory : ( ) => process . cwd ( ) ,
125
+ getCanonicalFileName : ( fileName ) => fileName ,
126
+ getNewLine : ( ) => ts . sys . newLine
127
+ }
128
+
129
+ function report_diagnostic ( diagnostic : ts . Diagnostic ) {
130
+ // eslint-disable-next-line no-console
131
+ console . error ( ts . formatDiagnostic ( diagnostic , format_host ) )
132
+ }
133
+ function report_diagnostics ( diagnostics : ts . Diagnostic [ ] ) {
134
+ // eslint-disable-next-line no-console
135
+ console . error ( ts . formatDiagnostics ( diagnostics , format_host ) )
136
+ }
137
+ function report_watch_status_changed ( diagnostic : ts . Diagnostic ) {
138
+ // eslint-disable-next-line no-console
139
+ console . info ( ts . formatDiagnostic ( diagnostic , format_host ) )
140
+ }
141
+
142
+ export function get_tsc_options ( dist_dirname : string ) : ts . CompilerOptions {
143
+
144
+ let ts_config_file = ts . findConfigFile ( process . cwd ( ) , ts . sys . fileExists , 'tsconfig.json' )
145
+ if ( ! ts_config_file ) throw Error ( 'tsconfig.json not found' )
146
+
147
+ let { config, error} = ts . readConfigFile ( ts_config_file , ts . sys . readFile )
148
+ if ( error ) {
149
+ report_diagnostic ( error )
150
+ }
151
+
152
+ let { options, errors} = ts . parseJsonConfigFileContent ( config , ts . sys , process . cwd ( ) )
153
+ if ( errors . length > 0 ) {
154
+ report_diagnostics ( errors )
155
+ }
156
+
157
+ return {
158
+ ...options ,
159
+ outDir : dist_dirname ,
160
+ emitDeclarationOnly : true ,
161
+ noEmit : false ,
162
+ noEmitOnError : false ,
163
+ declaration : true ,
164
+ sourceMap : true ,
165
+ }
166
+ }
167
+
168
+
169
+ main ( )
0 commit comments