1
1
#!/usr/bin/env node
2
2
import program from 'commander' ;
3
3
import path from 'path' ;
4
+ import signale from 'signale' ;
5
+ import { ProjectConfig } from '../config/project.config.default' ;
6
+ import { ServerConfig } from '../config/server.config.default' ;
7
+ import { Build } from '../scripts/Build' ;
8
+ import { Server } from '../scripts/Server' ;
4
9
5
10
/* tslint:disable:no-require-imports no-var-requires */
6
11
const pkg = require ( '../../package.json' ) ;
@@ -43,16 +48,68 @@ program
43
48
'-s, --server-config [path]' ,
44
49
'Path to server config. If it differs from ./wpackio.server.js'
45
50
)
46
- . action ( options => {
47
- isValidCommand = true ;
48
- console . log ( 'should start script.' , options . context ) ;
49
- // Set process.env.NODE_ENV to development
50
- // Set process.env.BABEL_ENV to development
51
- // Get project and server config JSONs.
52
- // Start the webpack/browserSync server
53
- // Listen for SIGTERM and quit properly
54
- // Listen for keyinput <r> and invalidate webpack builds.
55
- } ) ;
51
+ . action (
52
+ (
53
+ options :
54
+ | {
55
+ context ?: string ;
56
+ projectConfig ?: string ;
57
+ serverConfig ?: string ;
58
+ }
59
+ | undefined
60
+ ) => {
61
+ isValidCommand = true ;
62
+ signale . start ( 'Starting up wpack.io development server' ) ;
63
+ // Set process.env.NODE_ENV to development
64
+ process . env . NODE_ENV = 'development' ;
65
+ // Set process.env.BABEL_ENV to development
66
+ process . env . BABEL_ENV = 'development' ;
67
+ // Get project and server config JSONs.
68
+ const cwd = resolveCWD ( options ) ;
69
+ signale . info ( `Using startup path: ${ cwd } ` ) ;
70
+ try {
71
+ const {
72
+ projectConfig,
73
+ serverConfig,
74
+ projectConfigPath,
75
+ serverConfigPath,
76
+ } = getProjectAndServerConfig ( cwd , options ) ;
77
+ signale . info ( `Using project config from ${ projectConfigPath } ` ) ;
78
+ signale . info ( `Using server config from ${ serverConfigPath } ` ) ;
79
+ // Start the webpack/browserSync server
80
+ const server : Server = new Server (
81
+ projectConfig ,
82
+ serverConfig ,
83
+ cwd
84
+ ) ;
85
+ server . serve ( ) ;
86
+ // Listen for SIGINT and quit properly
87
+ process . on ( 'SIGINT' , ( ) => {
88
+ signale . complete ( 'Gracefully ending development server' ) ;
89
+ server . stop ( ) ;
90
+ signale . success (
91
+ 'To create production build, run `yarn build` or `npm run build`'
92
+ ) ;
93
+ signale . star ( 'Thank you for using https://wpack.io.' ) ;
94
+ signale . star ( 'To spread the ❤️ please tweet.' ) ;
95
+ process . exit ( 0 ) ;
96
+ } ) ;
97
+ process . on ( 'SIGKILL' , ( ) => {
98
+ server . stop ( ) ;
99
+ } ) ;
100
+ process . on ( 'SIGTERM' , ( ) => {
101
+ server . stop ( ) ;
102
+ } ) ;
103
+ } catch ( e ) {
104
+ signale . error (
105
+ 'Could not start development server. Please check the log below.'
106
+ ) ;
107
+ signale . fatal ( e ) ;
108
+ process . exit ( 1 ) ;
109
+ }
110
+ // Listen for keyinput <r> and invalidate webpack builds.
111
+ }
112
+ ) ;
56
113
57
114
// Build the script
58
115
program
@@ -69,21 +126,166 @@ program
69
126
)
70
127
. action ( options => {
71
128
isValidCommand = true ;
72
- console . log ( 'should build the script' , options . context ) ;
129
+ signale . start ( 'Creating production builds...' ) ;
73
130
// Set process.env.NODE_ENV to production
131
+ process . env . NODE_ENV = 'production' ;
74
132
// Set process.env.BABEL_ENV to production
133
+ process . env . BABEL_ENV = 'production' ;
75
134
// Get project and server config JSONs.
76
- // Compile scripts using webpack
135
+ const cwd = resolveCWD ( options ) ;
136
+ signale . info ( `Using startup path: ${ cwd } ` ) ;
137
+ try {
138
+ const {
139
+ projectConfig,
140
+ serverConfig,
141
+ projectConfigPath,
142
+ serverConfigPath,
143
+ } = getProjectAndServerConfig ( cwd , options ) ;
144
+ signale . info ( `Using project config from ${ projectConfigPath } ` ) ;
145
+ signale . info ( `Using server config from ${ serverConfigPath } ` ) ;
146
+ // Start the webpack/browserSync server
147
+ const build : Build = new Build ( projectConfig , serverConfig , cwd ) ;
148
+ build
149
+ . build ( )
150
+ . then ( log => {
151
+ signale . success (
152
+ 'Build Successful. Please check the log below'
153
+ ) ;
154
+ console . log ( log ) ;
155
+ process . exit ( 0 ) ;
156
+ } )
157
+ . catch ( err => {
158
+ signale . fatal (
159
+ 'Could not create production build. Please check the log below'
160
+ ) ;
161
+ console . log ( err ) ;
162
+ process . exit ( 1 ) ;
163
+ } ) ;
164
+ } catch ( e ) {
165
+ signale . error (
166
+ 'Could not start development server. Please check the log below.'
167
+ ) ;
168
+ signale . fatal ( e ) ;
169
+ process . exit ( 1 ) ;
170
+ }
77
171
} ) ;
78
172
79
173
// Init
80
174
program . parse ( process . argv ) ;
81
175
82
176
// error on unknown commands
83
177
if ( ! isValidCommand ) {
84
- console . error (
85
- 'Invalid command: %s\nSee --help for a list of available commands. ' ,
178
+ signale . error (
179
+ 'Invalid command: %s\nSee usage below.\n\n ' ,
86
180
program . args . join ( ' ' )
87
181
) ;
88
- process . exit ( 1 ) ;
182
+ program . help ( ) ;
89
183
}
184
+
185
+ /**
186
+ * Resolve `cwd`, a.k.a, current working directory or context from user input.
187
+ * It takes into account the `--context [path]` option from CLI and uses process
188
+ * cwd, if not provided.
189
+ *
190
+ * @param options Options as received from CLI
191
+ */
192
+ function resolveCWD (
193
+ options : { context ?: string | undefined } | undefined
194
+ ) : string {
195
+ let cwd = process . cwd ( ) ;
196
+ // If user has provided cwd, then use that instead
197
+ if ( options && options . context ) {
198
+ const { context } = options ;
199
+ if ( path . isAbsolute ( options . context ) ) {
200
+ cwd = context ;
201
+ } else {
202
+ cwd = path . resolve ( cwd , context ) ;
203
+ }
204
+ }
205
+
206
+ return cwd ;
207
+ }
208
+
209
+ // tslint:disable: non-literal-require
210
+ function getProjectAndServerConfig (
211
+ cwd : string ,
212
+ options : { projectConfig ?: string ; serverConfig ?: string } | undefined
213
+ ) : {
214
+ projectConfig : ProjectConfig ;
215
+ serverConfig : ServerConfig ;
216
+ projectConfigPath : string ;
217
+ serverConfigPath : string ;
218
+ } {
219
+ // Get the config file paths from options
220
+ // If user is passing relative path, then it will be used along with cwd
221
+ // If it is absolute path, then the absolute would be used instead
222
+ // This is how path.resolve works.
223
+ const projectConfigPath = path . resolve (
224
+ cwd ,
225
+ options && options . projectConfig
226
+ ? options . projectConfig
227
+ : 'wpackio.project.js'
228
+ ) ;
229
+
230
+ const serverConfigPath = path . resolve (
231
+ cwd ,
232
+ options && options . serverConfig
233
+ ? options . serverConfig
234
+ : 'wpackio.server.js'
235
+ ) ;
236
+
237
+ // Now create the configuration objects
238
+ let projectConfig : ProjectConfig ;
239
+ let serverConfig : ServerConfig ;
240
+
241
+ // First check to see if the files are present
242
+ try {
243
+ projectConfig = require ( projectConfigPath ) as ProjectConfig ;
244
+ } catch ( e ) {
245
+ throw new Error (
246
+ `Could not find project configuration at:\n${ projectConfigPath } \nPlease make sure the file exists or adjust your --context or --project-config parameters.`
247
+ ) ;
248
+ }
249
+ try {
250
+ serverConfig = require ( serverConfigPath ) as ServerConfig ;
251
+ } catch ( e ) {
252
+ throw new Error (
253
+ `Could not find server configuration at:\n${ serverConfigPath } \nPlease make sure the file exists or adjust your --context or --server-config parameters.`
254
+ ) ;
255
+ }
256
+
257
+ // Now validate them
258
+ if ( typeof projectConfig !== 'object' ) {
259
+ throw new Error (
260
+ `Project configuration must export an object literal. Right now it is ${ typeof projectConfig } `
261
+ ) ;
262
+ }
263
+ if ( typeof serverConfig !== 'object' ) {
264
+ throw new Error (
265
+ `Server configuration must export an object literal. Right now it is ${ typeof serverConfig } `
266
+ ) ;
267
+ }
268
+ // @todo
269
+ // Also validate the config, but let's leave it for now
270
+ // Make sure to do it in future
271
+
272
+ return { projectConfig , serverConfig , projectConfigPath , serverConfigPath } ;
273
+ }
274
+
275
+ // Error out on force close
276
+ process . on ( 'SIGKILL' , ( ) => {
277
+ signale . fatal (
278
+ 'The operation failed because the process exited too early. ' +
279
+ 'This probably means the system ran out of memory or someone called ' +
280
+ '`kill -9` on the process.'
281
+ ) ;
282
+ process . exit ( 1 ) ;
283
+ } ) ;
284
+ process . on ( 'SIGTERM' , ( ) => {
285
+ signale . fatal (
286
+ 'The operation failed because the process exited too early. ' +
287
+ 'Someone might have called `kill` or `killall`, or the system could ' +
288
+ 'be shutting down.'
289
+ ) ;
290
+ process . exit ( 1 ) ;
291
+ } ) ;
0 commit comments