11#!/usr/bin/env node
22import program from 'commander' ;
33import 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' ;
49
510/* tslint:disable:no-require-imports no-var-requires */
611const pkg = require ( '../../package.json' ) ;
@@ -43,16 +48,68 @@ program
4348 '-s, --server-config [path]' ,
4449 'Path to server config. If it differs from ./wpackio.server.js'
4550 )
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+ ) ;
56113
57114// Build the script
58115program
@@ -69,21 +126,166 @@ program
69126 )
70127 . action ( options => {
71128 isValidCommand = true ;
72- console . log ( 'should build the script' , options . context ) ;
129+ signale . start ( 'Creating production builds...' ) ;
73130 // Set process.env.NODE_ENV to production
131+ process . env . NODE_ENV = 'production' ;
74132 // Set process.env.BABEL_ENV to production
133+ process . env . BABEL_ENV = 'production' ;
75134 // 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+ }
77171 } ) ;
78172
79173// Init
80174program . parse ( process . argv ) ;
81175
82176// error on unknown commands
83177if ( ! 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 ' ,
86180 program . args . join ( ' ' )
87181 ) ;
88- process . exit ( 1 ) ;
182+ program . help ( ) ;
89183}
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