diff --git a/lib/core/engine.js b/lib/core/engine.js index 37706cd2..822ddf6d 100644 --- a/lib/core/engine.js +++ b/lib/core/engine.js @@ -228,6 +228,7 @@ class Engine { } webServerService(_options) { + _options.buildDir = this.config.buildDir; this.registerModule('webserver', _options); } diff --git a/lib/modules/code_generator/index.js b/lib/modules/code_generator/index.js index ecc1aee5..371f6968 100644 --- a/lib/modules/code_generator/index.js +++ b/lib/modules/code_generator/index.js @@ -13,8 +13,7 @@ const Templates = { define_web3_simple: require('./code_templates/define-web3-simple.js.ejs'), web3_connector: require('./code_templates/web3-connector.js.ejs'), do_when_loaded: require('./code_templates/do-when-loaded.js.ejs'), - exec_when_env_loaded: require('./code_templates/exec-when-env-loaded.js.ejs'), - embark_building_placeholder: require('./code_templates/embark-building-placeholder.html.ejs') + exec_when_env_loaded: require('./code_templates/exec-when-env-loaded.js.ejs') }; class CodeGenerator { @@ -94,10 +93,6 @@ class CodeGenerator { cb(self.generateContractCode(contract, gasLimit)); }); - this.events.setCommandHandler('embark-building-placeholder', (cb) => { - self.buildPlaceholderPage(cb); - }); - self.events.setCommandHandler('code-generator:embarkjs:provider-code', (cb) => { cb(self.getEmbarkJsProviderCode()); }); @@ -379,12 +374,6 @@ class CodeGenerator { } ], cb); } - - buildPlaceholderPage(cb) { - let html = Templates.embark_building_placeholder({buildingMsg: __('Embark is building, please wait...')}); - cb(html); - } - } module.exports = CodeGenerator; diff --git a/lib/modules/webserver/index.js b/lib/modules/webserver/index.js index a0b94850..ac346511 100644 --- a/lib/modules/webserver/index.js +++ b/lib/modules/webserver/index.js @@ -1,13 +1,20 @@ +const fs = require('../../core/fs.js'); var {canonicalHost} = require('../../utils/host.js'); var utils = require('../../utils/utils.js'); var Server = require('./server.js'); +const opn = require('opn'); + +require('ejs'); +const Templates = { + embark_building_placeholder: require('./templates/embark-building-placeholder.html.ejs') +}; class WebServer { - constructor(embark, options) { this.embark = embark; this.logger = embark.logger; this.events = embark.events; + this.buildDir = options.buildDir; this.webServerConfig = embark.config.webServerConfig; if (!this.webServerConfig.enabled) { return; @@ -18,7 +25,13 @@ class WebServer { this.events.emit("status", __("Starting Server")); - this.server = new Server({host: this.host, port: this.port}); + this.server = new Server({ + buildDir: this.buildDir, + events: this.events, + host: this.host, + port: this.port + }); + this.testPort(() => { this.listenToCommands(); this.registerConsoleCommands(); @@ -60,25 +73,48 @@ class WebServer { } listenToCommands() { - this.events.setCommandHandler('start-webserver', (callback) => this.server.start(callback)); - this.events.setCommandHandler('stop-webserver', (callback) => this.server.stop(callback)); + this.events.setCommandHandler('build-placeholder', (cb) => this.buildPlaceholderPage(cb)); + this.events.setCommandHandler('open-browser', (cb) => this.openBrowser(cb)); + this.events.setCommandHandler('start-webserver', (cb) => this.server.start(cb)); + this.events.setCommandHandler('stop-webserver', (cb) => this.server.stop(cb)); } registerConsoleCommands() { const self = this; self.embark.registerConsoleCommand((cmd, _options) => { return { - match: () => cmd === "webserver start", - process: (callback) => self.events.request("start-webserver", callback) + match: () => cmd === 'webserver start', + process: (cb) => self.events.request('start-webserver', cb) }; }); self.embark.registerConsoleCommand((cmd, _options) => { return { - match: () => cmd === "webserver stop", - process: (callback) => self.events.request("stop-webserver", callback) + match: () => cmd === 'webserver stop', + process: (cb) => self.events.request('stop-webserver', cb) }; }); + + self.embark.registerConsoleCommand((cmd, _options) => { + return { + match: () => cmd === 'browser open', + process: (cb) => self.events.request('open-browser', cb) + }; + }); + } + + buildPlaceholderPage(cb) { + let html = Templates.embark_building_placeholder({buildingMsg: __('Embark is building, please wait...')}); + fs.mkdirpSync(this.buildDir); // create buildDir if it does not exist + fs.writeFile(utils.joinPath(this.buildDir, 'index.html'), html, cb); + } + + openBrowser(cb) { + const _cb = () => { cb(); }; + return opn( + `http://${canonicalHost(this.server.hostname)}:${this.server.port}`, + {wait: false} + ).then(_cb, _cb); // fail silently, e.g. in a docker container } } diff --git a/lib/modules/webserver/server.js b/lib/modules/webserver/server.js index 340f5307..4f631843 100644 --- a/lib/modules/webserver/server.js +++ b/lib/modules/webserver/server.js @@ -1,4 +1,5 @@ let finalhandler = require('finalhandler'); +const async = require('async'); let http = require('http'); let serveStatic = require('serve-static'); const {canonicalHost, defaultHost, dockerHostSwap} = require('../../utils/host'); @@ -6,31 +7,59 @@ require('http-shutdown').extend(); class Server { constructor(options) { - this.dist = options.dist || 'dist/'; + this.buildDir = options.buildDir; + this.events = options.events; this.port = options.port || 8000; this.hostname = dockerHostSwap(options.host) || defaultHost; + this.isFirstStart = true; + this.opened = false; } start(callback) { if (this.server && this.server.listening) { let message = __("a webserver is already running at") + " " + - ("http://" + canonicalHost(this.hostname) + - ":" + this.port).bold.underline.green; + ("http://" + canonicalHost(this.hostname) + + ":" + this.port).bold.underline.green; return callback(null, message); } - let serve = serveStatic(this.dist, {'index': ['index.html', 'index.htm']}); + let serve = serveStatic(this.buildDir, {'index': ['index.html', 'index.htm']}); this.server = http.createServer(function onRequest(req, res) { serve(req, res, finalhandler(req, res)); }).withShutdown(); + const self = this; - this.server.listen(this.port, this.hostname, () => { - this.port = this.server.address().port; - callback(null, __("webserver available at") + - " " + - ("http://" + canonicalHost(this.hostname) + - ":" + this.port).bold.underline.green, this.port); + async.waterfall([ + function createPlaceholderPage(next) { + if (!self.isFirstStart) { + return next(); + } + self.isFirstStart = false; + self.events.request('build-placeholder', next); + }, + function listen(next) { + self.server.listen(self.port, self.hostname, () => { + self.port = self.server.address().port; + next(); + }); + }, + function openBrowser(next) { + if (self.opened) { + return next(); + } + self.opened = true; + self.events.request('open-browser', next); + } + ], function (err) { + if (err) { + return callback(err); + } + const msg = ( + __('webserver available at') + ' ' + + ('http://' + canonicalHost(self.hostname) + ':' + self.port).bold.underline.green + ); + callback(null, msg, self.port); }); } @@ -42,7 +71,6 @@ class Server { callback(null, __("Webserver stopped")); }); } - } module.exports = Server; diff --git a/lib/modules/code_generator/code_templates/embark-building-placeholder.html.ejs b/lib/modules/webserver/templates/embark-building-placeholder.html.ejs similarity index 100% rename from lib/modules/code_generator/code_templates/embark-building-placeholder.html.ejs rename to lib/modules/webserver/templates/embark-building-placeholder.html.ejs diff --git a/lib/pipeline/pipeline.js b/lib/pipeline/pipeline.js index 1f0a742b..cbb27c40 100644 --- a/lib/pipeline/pipeline.js +++ b/lib/pipeline/pipeline.js @@ -5,7 +5,6 @@ const utils = require('../utils/utils.js'); const constants = require('../constants'); class Pipeline { - constructor(options) { this.env = options.env; this.buildDir = options.buildDir; @@ -16,6 +15,7 @@ class Pipeline { this.plugins = options.plugins; this.webpackConfigName = options.webpackConfigName; this.pipelinePlugins = this.plugins.getPluginsFor('pipeline'); + this.isFirstBuild = true; } build(abi, contractsJSON, path, callback) { @@ -29,10 +29,11 @@ class Pipeline { async.waterfall([ function createPlaceholderPage(next){ - self.events.request('embark-building-placeholder', (html) => { - fs.mkdirpSync(self.buildDir); // create dist/ folder if not already exists - fs.writeFile(utils.joinPath(self.buildDir, 'index.html'), html, next); - }); + if (self.isFirstBuild) { + self.isFirstBuild = false; + return next(); + } + self.events.request('build-placeholder', next); }, function buildTheContracts(next) { self.buildContracts(next); diff --git a/package-lock.json b/package-lock.json index 1282b0a8..a6076bd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5272,6 +5272,11 @@ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -6698,6 +6703,14 @@ "mimic-fn": "^1.0.0" } }, + "opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "requires": { + "is-wsl": "^1.1.0" + } + }, "optimist": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", diff --git a/package.json b/package.json index dad9bcd3..a196ea05 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "netcat": "^1.3.5", "node-ipc": "^9.1.1", "node-netcat": "^1.4.8", + "opn": "^5.3.0", "ora": "^2.1.0", "os-locale": "^2.1.0", "parse-json": "^4.0.0",