@@ -7,6 +7,12 @@ import * as esbuild from 'esbuild';
7
7
import svgr from 'esbuild-plugin-svgr' ;
8
8
import { sassPlugin } from 'esbuild-sass-plugin' ;
9
9
import * as fs from 'fs/promises' ;
10
+ import * as glob from 'glob' ;
11
+ import { createRequire } from 'module' ;
12
+ import * as path from 'path' ;
13
+ import { fileURLToPath } from 'url' ;
14
+
15
+ const require = createRequire ( import . meta. url ) ;
10
16
11
17
const webviews = [
12
18
'cluster' ,
@@ -26,14 +32,138 @@ const webviews = [
26
32
'openshift-terminal' ,
27
33
] ;
28
34
29
- await Promise . all ( [
30
- esbuild . build ( {
31
- entryPoints : webviews . map ( webview => `./src/webview/${ webview } /app/index.tsx` ) ,
32
- bundle : true ,
33
- outdir : 'out' ,
35
+ const production = process . argv . includes ( '--production' ) ;
36
+
37
+ // eslint-disable no-console
38
+ console . log ( `esbuild: building for production: ${ production ? 'Yes' : 'No' } ` ) ;
39
+
40
+ const __filename = fileURLToPath ( import . meta. url ) ; // get the resolved path to the file
41
+ const __dirname = path . resolve ( path . dirname ( __filename ) , '..' ) ; // get the name of the directory
42
+ const srcDir = 'src' ; // Input source directory
43
+ const outDir = 'out' ; // Output dist directory
44
+
45
+ function detectGoal ( entryPoints ) {
46
+ if ( production ) {
47
+ const isExtension = entryPoints . filter ( ( ep ) => `${ ep } ` . includes ( 'extension.ts' ) ) . length > 0 ;
48
+ const isWebviews = entryPoints . filter ( ( ep ) => `${ ep } ` . includes ( '.tsx' ) ) . length > 0 ;
49
+ return isExtension ? 'Extension' : isWebviews ? 'the Webviews' : '' ;
50
+ }
51
+ return 'Extension and the Webviews for testing/debugging' ;
52
+ }
53
+
54
+ /**
55
+ * @type {import('esbuild').Plugin }
56
+ */
57
+ const esbuildProblemMatcherPlugin = {
58
+ name : 'esbuild-problem-matcher' ,
59
+
60
+ setup ( build ) {
61
+ build . onStart ( ( ) => {
62
+ const goal = detectGoal ( build . initialOptions . entryPoints ) ;
63
+ console . log ( `[watch] build started${ goal ? ' for ' + goal : '' } ...` ) ;
64
+ } ) ;
65
+ build . onEnd ( result => {
66
+ result . errors . forEach ( ( { text, location } ) => {
67
+ console . error ( `✘ [ERROR] ${ text } ` ) ;
68
+ if ( location ) {
69
+ console . error ( ` ${ location . file } :${ location . line } :${ location . column } :` ) ;
70
+ }
71
+ } ) ;
72
+ const goal = detectGoal ( build . initialOptions . entryPoints ) ;
73
+ console . log ( `[watch] build finished${ goal ? ' for ' + goal : '' } ` ) ;
74
+ } ) ;
75
+ }
76
+ } ;
77
+
78
+ const nativeNodeModulesPlugin = {
79
+ name : 'native-node-modules' ,
80
+ setup ( build ) {
81
+ try {
82
+ // If a ".node" file is imported within a module in the "file" namespace, resolve
83
+ // it to an absolute path and put it into the "node-file" virtual namespace.
84
+ build . onResolve ( { filter : / \. n o d e $ / , namespace : 'file' } , args => ( {
85
+ path : require . resolve ( args . path , { paths : [ args . resolveDir ] } ) ,
86
+ namespace : 'node-file' ,
87
+ } ) ) ;
88
+
89
+ // Files in the "node-file" virtual namespace call "require()" on the
90
+ // path from esbuild of the ".node" file in the output directory.
91
+ build . onLoad ( { filter : / .* / , namespace : 'node-file' } , args => ( {
92
+ contents : `
93
+ import path from ${ JSON . stringify ( args . path ) }
94
+ try {
95
+ module.exports = require(path)
96
+ } catch {}
97
+ ` ,
98
+ } ) )
99
+
100
+ // If a ".node" file is imported within a module in the "node-file" namespace, put
101
+ // it in the "file" namespace where esbuild's default loading behavior will handle
102
+ // it. It is already an absolute path since we resolved it to one above.
103
+ build . onResolve ( { filter : / \. n o d e $ / , namespace : 'node-file' } , args => ( {
104
+ path : args . path ,
105
+ namespace : 'file' ,
106
+ } ) ) ;
107
+
108
+ // Tell esbuild's default loading behavior to use the "file" loader for
109
+ // these ".node" files.
110
+ let opts = build . initialOptions
111
+ opts . loader = opts . loader || { }
112
+ opts . loader [ '.node' ] = 'file'
113
+ } catch ( err ) {
114
+ console . error ( `native-node-modules: ERROR: ${ err } ` ) ;
115
+ }
116
+ } ,
117
+ } ;
118
+
119
+ const baseConfig = {
120
+ bundle : true ,
121
+ target : 'chrome108' ,
122
+ minify : production ,
123
+ sourcemap : ! production ,
124
+ logLevel : 'warning' ,
125
+ } ;
126
+
127
+ if ( production ) {
128
+ // Build the extension.js
129
+ const extConfig = {
130
+ ...baseConfig ,
131
+ platform : 'node' ,
132
+ entryPoints : [ `./${ srcDir } /extension.ts` ] ,
133
+ outfile : `${ outDir } /${ srcDir } /extension.js` ,
134
+ external : [ 'vscode' , 'shelljs' ] ,
135
+ plugins : [
136
+ nativeNodeModulesPlugin ,
137
+ esbuildProblemMatcherPlugin // this one is to be added to the end of plugins array
138
+ ]
139
+ } ;
140
+ await esbuild . build ( extConfig ) ;
141
+
142
+ // Build the Webviews
143
+ const webviewsConfig = {
144
+ ...baseConfig ,
145
+ platform : 'browser' ,
146
+ entryPoints : [ ...webviews . map ( webview => `./${ srcDir } /webview/${ webview } /app/index.tsx` ) ] ,
147
+ outdir : `${ outDir } ` ,
148
+ loader : {
149
+ '.png' : 'file' ,
150
+ } ,
151
+ plugins : [
152
+ sassPlugin ( ) ,
153
+ svgr ( {
154
+ plugins : [ '@svgr/plugin-jsx' ]
155
+ } ) ,
156
+ esbuildProblemMatcherPlugin // this one is to be added to the end of plugins array
157
+ ]
158
+ } ;
159
+ await esbuild . build ( webviewsConfig ) ;
160
+ } else {
161
+ // Build the Webviews
162
+ const devConfig = {
163
+ ...baseConfig ,
34
164
platform : 'browser' ,
35
- target : 'chrome108' ,
36
- sourcemap : true ,
165
+ entryPoints : [ ... webviews . map ( webview => `./ ${ srcDir } /webview/ ${ webview } /app/index.tsx` ) ] ,
166
+ outdir : ` ${ outDir } ` ,
37
167
loader : {
38
168
'.png' : 'file' ,
39
169
} ,
@@ -42,9 +172,32 @@ await Promise.all([
42
172
svgr ( {
43
173
plugins : [ '@svgr/plugin-jsx' ]
44
174
} ) ,
175
+ esbuildProblemMatcherPlugin // this one is to be added to the end of plugins array
45
176
]
46
- } ) ,
47
- ...webviews . map ( webview =>
48
- fs . cp ( `./src/webview/${ webview } /app/index.html` , `./out/${ webview } /app/index.html` )
49
- ) ,
50
- ] ) ;
177
+ } ;
178
+ await esbuild . build ( devConfig ) ;
179
+ }
180
+
181
+ async function dirExists ( path ) {
182
+ try {
183
+ if ( ( await fs . stat ( path ) ) . isDirectory ( ) ) {
184
+ return true ;
185
+ }
186
+ } catch {
187
+ // Ignore
188
+ }
189
+ return false ;
190
+ }
191
+
192
+ // Copy webview's 'index.html's to the output webview dirs
193
+ await Promise . all ( [
194
+ ...webviews . map ( async webview => {
195
+ const targetDir = path . join ( __dirname , `${ outDir } /${ webview } /app` ) ;
196
+ if ( ! dirExists ( targetDir ) ) {
197
+ await fs . mkdir ( targetDir , { recursive : true , mode : 0o750 } ) ;
198
+ }
199
+ glob . sync ( [ `${ srcDir } /webview/${ webview } /app/index.html` ] ) . map ( async srcFile => {
200
+ await fs . cp ( path . join ( __dirname , srcFile ) , path . join ( targetDir , `${ path . basename ( srcFile ) } ` ) )
201
+ } ) ;
202
+ } )
203
+ ] ) ;
0 commit comments