Skip to content

Commit 7285d51

Browse files
authored
feat(): introduce new api for build and watch tasks for app-scripts.
1 parent cdbeef6 commit 7285d51

File tree

9 files changed

+349
-60
lines changed

9 files changed

+349
-60
lines changed

lib/ionic/build.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
var extend = require('../utils/extend');
4+
var npmScripts = require('../utils/npmScripts');
45
var os = require('os');
56
var Q = require('q');
67
var IonicAppLib = require('ionic-app-lib');
@@ -51,6 +52,15 @@ function run(ionic, argv, rawCliArguments) {
5152
[]);
5253

5354
return Q.all(promiseList).then(function() {
55+
return npmScripts.hasIonicScript('build');
56+
})
57+
.then(function(hasBuildCommand) {
58+
if (hasBuildCommand) {
59+
return npmScripts.runIonicScript('build');
60+
}
61+
return Q.resolve();
62+
})
63+
.then(function() {
5464

5565
// ensure the content node was set back to its original
5666
return ConfigXml.setConfigXml(appDirectory, {

lib/ionic/emulate.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
var extend = require('../utils/extend');
4+
var npmScripts = require('../utils/npmScripts');
45
var os = require('os');
56
var Q = require('q');
67
var IonicAppLib = require('ionic-app-lib');
@@ -68,6 +69,15 @@ function run(ionic, argv, rawCliArguments) {
6869
[]);
6970

7071
return Q.all(promiseList).then(function() {
72+
return npmScripts.hasIonicScript('build');
73+
})
74+
.then(function(hasBuildCommand) {
75+
if (hasBuildCommand) {
76+
return npmScripts.runIonicScript('build');
77+
}
78+
return Q.resolve();
79+
})
80+
.then(function() {
7181
if (isLiveReload) {
7282
return cordovaUtils.setupLiveReload(argv, appDirectory);
7383
}

lib/ionic/run.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
var extend = require('../utils/extend');
4+
var npmScripts = require('../utils/npmScripts');
45
var os = require('os');
56
var Q = require('q');
67
var IonicAppLib = require('ionic-app-lib');
@@ -68,6 +69,15 @@ function run(ionic, argv, rawCliArguments) {
6869
[]);
6970

7071
return Q.all(promiseList).then(function() {
72+
return npmScripts.hasIonicScript('build');
73+
})
74+
.then(function(hasBuildCommand) {
75+
if (hasBuildCommand) {
76+
return npmScripts.runIonicScript('build');
77+
}
78+
return Q.resolve();
79+
})
80+
.then(function() {
7181
if (isLiveReload) {
7282
return cordovaUtils.setupLiveReload(argv, appDirectory);
7383
}

lib/ionic/serve.js

Lines changed: 50 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
var extend = require('../utils/extend');
4+
var npmScripts = require('../utils/npmScripts');
45
var IonicAppLib = require('ionic-app-lib');
56
var appLibUtils = IonicAppLib.utils;
67
var events = IonicAppLib.events;
@@ -60,65 +61,68 @@ var settings = {
6061
};
6162

6263
function run(ionic, argv) {
64+
65+
/**
66+
* Before running the internal server check to see if npmscripts has
67+
* a ionic specific serve command. If so then run it instead.
68+
*/
69+
return npmScripts.hasIonicScript('serve')
70+
.then(function(hasServeCommand) {
71+
if (hasServeCommand) {
72+
return npmScripts.runIonicScript('serve', argv);
73+
} else {
74+
return runServer(argv);
75+
}
76+
})
77+
.catch(function(error) {
78+
log.error('There was an error serving your Ionic application:', error);
79+
});
80+
}
81+
82+
function runServer(argv) {
6383
var project = null;
6484
var cwd = process.cwd();
85+
var options = {};
86+
var promise = Q();
6587

66-
try {
67-
project = IonicProject.load(cwd);
68-
} catch (ex) {
69-
log.error('Error occured', ex);
70-
return appLibUtils.fail(ex.message);
71-
}
72-
73-
var options = Serve.loadSettings(argv, project);
88+
project = IonicProject.load(cwd);
7489

90+
options = Serve.loadSettings(argv, project);
7591
options.appDirectory = cwd; // called from cli - ionic serve - cwd is this
76-
7792
options.nogulp = argv.nogulp;
7893

7994
// check if CONNECT_LIVE_RELOAD_PORT is defined and use that instead
8095
if (process.env.CONNECT_LIVE_RELOAD_PORT) {
8196
options.liveReloadPort = process.env.CONNECT_LIVE_RELOAD_PORT;
8297
}
83-
var promise;
84-
85-
try {
86-
if (argv.all || argv.a) {
87-
options.address = '0.0.0.0';
88-
promise = Q();
89-
} else if (argv.address) {
90-
options.address = argv.address;
91-
promise = Q();
92-
} else {
93-
promise = Serve.getAddress(options);
94-
}
9598

96-
return promise
97-
.then(function() {
98-
return Serve.checkPorts(true, options.port, options.address, options);
99-
})
100-
.then(function() {
101-
if (options.runLivereload) {
102-
return Serve.checkPorts(false, options.liveReloadPort, options.address, options);
103-
}
104-
})
105-
.then(function() {
106-
return Serve.start(options);
107-
})
108-
.then(function() {
109-
return Serve.showFinishedServeMessage(options);
110-
})
111-
.then(function() {
112-
events.on('serverlog', log.info);
113-
events.on('consolelog', log.info);
114-
})
115-
.catch(function(error) {
116-
log.info('There was an error serving your Ionic application:', error);
117-
throw error;
118-
});
119-
} catch (ex) {
120-
appLibUtils.fail('Error with serve- ' + ex);
99+
if (argv.all || argv.a) {
100+
options.address = '0.0.0.0';
101+
} else if (argv.address) {
102+
options.address = argv.address;
103+
} else {
104+
promise = Serve.getAddress(options);
121105
}
106+
107+
return promise
108+
.then(function() {
109+
return Serve.checkPorts(true, options.port, options.address, options);
110+
})
111+
.then(function() {
112+
if (options.runLivereload) {
113+
return Serve.checkPorts(false, options.liveReloadPort, options.address, options);
114+
}
115+
})
116+
.then(function() {
117+
return Serve.start(options);
118+
})
119+
.then(function() {
120+
return Serve.showFinishedServeMessage(options);
121+
})
122+
.then(function() {
123+
events.on('serverlog', log.info);
124+
events.on('consolelog', log.info);
125+
});
122126
}
123127

124128
module.exports = extend(settings, {

lib/utils/npmScripts.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
'use strict';
2+
3+
var Q = require('q');
4+
var path = require('path');
5+
var fs = require('fs');
6+
var IonicAppLib = require('ionic-app-lib');
7+
var log = IonicAppLib.logging.logger;
8+
9+
10+
function hasIonicScript(name) {
11+
return getPackageJsonContents().then(function(packageJsonContents) {
12+
return packageJsonContents.hasOwnProperty('scripts') &&
13+
packageJsonContents.scripts.hasOwnProperty('ionic:' + name);
14+
});
15+
}
16+
17+
function runIonicScript(name, argv) {
18+
var spawn = require('cross-spawn-async');
19+
var scriptName = 'ionic:' + name;
20+
var q = Q.defer();
21+
22+
var scriptSpawn = spawn('npm', ['run', scriptName].concat(argv || []), { stdio: 'inherit' })
23+
.on('error', function(err) {
24+
log.debug('Spawn command', scriptName, 'failed');
25+
q.reject('Unable to run spawn command ' + err);
26+
});
27+
28+
scriptSpawn.on('exit', function(code) {
29+
log.debug('Spawn command', scriptName, 'completed');
30+
if (code !== 0) {
31+
return q.reject('There was an error with the spawned command: ' + name);
32+
}
33+
return q.resolve();
34+
});
35+
36+
return q.promise;
37+
}
38+
39+
/**
40+
* Function is memoized so that it should only access the filesystem one time.
41+
* Everytime after that it just returns the saved packageJson wrapped in a resolved promise.
42+
*/
43+
var getPackageJsonContents = (function() {
44+
var packageJson;
45+
46+
return function f() {
47+
var packageJsonPath = path.resolve(process.cwd() + '/package.json');
48+
var q = Q.defer();
49+
50+
if (packageJson) {
51+
Q.resolve(packageJson);
52+
}
53+
54+
try {
55+
fs.readFile(packageJsonPath, 'utf8', function(err, dataString) {
56+
if (!err) {
57+
packageJson = JSON.parse(dataString);
58+
}
59+
q.resolve(packageJson);
60+
});
61+
} catch (e) {
62+
q.resolve(packageJson);
63+
}
64+
65+
return q.promise;
66+
};
67+
})();
68+
69+
module.exports = {
70+
getPackageJsonContents: getPackageJsonContents,
71+
hasIonicScript: hasIonicScript,
72+
runIonicScript: runIonicScript
73+
};

spec/tasks/build.spec.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var IonicAppLib = require('ionic-app-lib');
88
var ConfigXml = IonicAppLib.configXml;
99
var log = IonicAppLib.logging.logger;
1010
var build = require('../../lib/ionic/build');
11+
var npmScripts = require('../../lib/utils/npmScripts');
1112

1213
describe('build command', function() {
1314
beforeEach(function() {
@@ -54,6 +55,7 @@ describe('build command', function() {
5455

5556
spyOn(cordovaUtils, 'isPlatformInstalled').andReturn(true);
5657
spyOn(cordovaUtils, 'arePluginsInstalled').andReturn(true);
58+
spyOn(npmScripts, 'hasIonicScript').andReturn(Q(false));
5759
spyOn(cordovaUtils, 'execCordovaCommand').andReturn(Q(true));
5860
});
5961

@@ -90,6 +92,7 @@ describe('build command', function() {
9092

9193
spyOn(cordovaUtils, 'installPlatform').andReturn(Q(true));
9294
spyOn(cordovaUtils, 'installPlugins').andReturn(Q(true));
95+
spyOn(npmScripts, 'hasIonicScript').andReturn(Q(false));
9396
});
9497

9598
it('should try to install the cordova platform if it is not installed', function(done) {
@@ -161,4 +164,48 @@ describe('build command', function() {
161164
});
162165
});
163166
});
167+
168+
describe('npmScripts check', function() {
169+
var appDirectory = '/ionic/app/path';
170+
var processArguments = ['node', 'ionic', 'build', 'ios', '-n'];
171+
var rawCliArguments = processArguments.slice(2);
172+
var argv = optimist(rawCliArguments).argv;
173+
174+
beforeEach(function() {
175+
spyOn(os, 'platform').andReturn('darwin');
176+
spyOn(process, 'cwd').andReturn(appDirectory);
177+
178+
spyOn(cordovaUtils, 'isPlatformInstalled').andReturn(true);
179+
spyOn(cordovaUtils, 'arePluginsInstalled').andReturn(true);
180+
spyOn(cordovaUtils, 'execCordovaCommand').andReturn(Q(0));
181+
});
182+
183+
it('should not call runIonicScript if hasIonicScript is false', function(done) {
184+
spyOn(npmScripts, 'hasIonicScript').andReturn(Q(false));
185+
spyOn(npmScripts, 'runIonicScript');
186+
187+
build.run(null, argv, rawCliArguments).then(function() {
188+
expect(npmScripts.hasIonicScript).toHaveBeenCalledWith('build');
189+
expect(npmScripts.runIonicScript).not.toHaveBeenCalled();
190+
expect(cordovaUtils.execCordovaCommand).toHaveBeenCalledWith(['build', 'ios', '-n']);
191+
done();
192+
}).catch(function(e) {
193+
console.log(e);
194+
});
195+
});
196+
197+
it('should call runIonicScript if hasIonicScript is true', function(done) {
198+
spyOn(npmScripts, 'hasIonicScript').andReturn(Q(true));
199+
spyOn(npmScripts, 'runIonicScript').andReturn(Q(true));
200+
201+
build.run(null, argv, rawCliArguments).then(function() {
202+
expect(npmScripts.hasIonicScript).toHaveBeenCalledWith('build');
203+
expect(npmScripts.runIonicScript).toHaveBeenCalledWith('build');
204+
expect(cordovaUtils.execCordovaCommand).toHaveBeenCalledWith(['build', 'ios', '-n']);
205+
done();
206+
}).catch(function(e) {
207+
console.log(e);
208+
});
209+
});
210+
});
164211
});

0 commit comments

Comments
 (0)