royale-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bigosma...@apache.org
Subject [royale-asjs] 01/02: Add auto reload functionality
Date Thu, 15 Feb 2018 03:20:55 GMT
This is an automated email from the ASF dual-hosted git repository.

bigosmallm pushed a commit to branch feature/royale-cli
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git

commit c8cca4de565d9a2b0ecced5343308ffe66233f80
Author: Om Muppirala <omuppirala@mz.com>
AuthorDate: Wed Feb 14 19:19:51 2018 -0800

    Add auto reload functionality
---
 npm/cli/connect.js                       |  14 +++
 npm/cli/index.js                         |  72 ++++++++++-----
 npm/cli/package.json                     |   8 ++
 npm/cli/server.js                        |  36 ++++++++
 npm/cli/template/reload/reload-client.js | 102 +++++++++++++++++++++
 npm/cli/template/reload/reload-server.js |  79 ++++++++++++++++
 npm/cli/template/reload/reload.js        | 153 +++++++++++++++++++++++++++++++
 7 files changed, 439 insertions(+), 25 deletions(-)

diff --git a/npm/cli/connect.js b/npm/cli/connect.js
new file mode 100644
index 0000000..1ba9adb
--- /dev/null
+++ b/npm/cli/connect.js
@@ -0,0 +1,14 @@
+var path = require('path');
+var connect  = require('connect');
+var static = require('serve-static');
+var fs = require('fs-extra');
+
+var debugDirPath = path.join(process.cwd(), 'bin', 'js-debug');
+
+var server = connect();
+server.use(  static(debugDirPath));
+server.listen(3000);
+
+var livereload = require('livereload');
+var lrserver = livereload.createServer();
+lrserver.watch(debugDirPath);
\ No newline at end of file
diff --git a/npm/cli/index.js b/npm/cli/index.js
index e119845..766dce8 100644
--- a/npm/cli/index.js
+++ b/npm/cli/index.js
@@ -21,9 +21,13 @@
 var fs = require('fs-extra');
 var path = require('path');
 var execSync = require('child_process').execSync;
-var server=require('node-http-server');
+var spawn = require('child_process').spawn;
+var fork = require('child_process').fork;
+//var server=require('node-http-server');
+//var server = require('./server');
 var chokidar = require('chokidar');
 var open = require("open");
+var livereload = require('livereload');
 
 var args = require('yargs')
     .usage('Usage: royale <command>')
@@ -87,46 +91,64 @@ function compileDebug() {
     //Compile project in debug mode
     var command = 'mxmlc ' + path.join(process.cwd(), SOURCE_DIR_NAME , 'Main.mxml -debug=true');
     console.log('Compiling...');
-    execSync(command);
+    try {
+        execSync(command);
+    }
+    catch(e) {
+        console.error(e.message);
+    }
     console.log('Finished compiling');
+    updateIndex();
+    watchFiles();
+    openBrowser('http://localhost:' + DEBUG_PORT);
 }
 
 var debugServerRunning = false;
 // Start server if it is not already running
 function startDebugServer() {
     if(!debugServerRunning) {
-        server.deploy(
-            {
-                port: DEBUG_PORT,
-                root: path.join(process.cwd(), 'bin', 'js-debug')
-            },
-            handleDebugServerReady
-        );
+        var command = 'node ' + path.join(__dirname, 'connect.js');
+        console.log('Starting server on localhost:3000...');
+        fork(path.join(__dirname, 'connect.js'));
     }
 }
 
-function handleDebugServerReady() {
-    debugServerRunning = true;
-    console.log('Your Apache Royale app (debug version) is running on localhost:%s', DEBUG_PORT);
-    watchFiles();
-    openBrowser('http://localhost:' + DEBUG_PORT);
+function updateIndex() {
+    var debugDirPath = path.join(process.cwd(), 'bin', 'js-debug');
+    //Rewrite index.html
+    var indexHTML = fs.readFileSync(path.join(debugDirPath, 'index.html'), 'utf8');
+    indexHTML = indexHTML.replace("</html>", '<script>\n' +
+        '  document.write(\'<script src="http://\' + (location.host || \'localhost\').split(\':\')[0]
+\n' +
+        '  \':35729/livereload.js?snipver=1"></\' + \'script>\')\n' +
+        '</script></html>');
+    fs.writeFile(path.join(debugDirPath, 'index.html'), indexHTML);
 }
 
+var watchingFiles = false;
 function watchFiles() {
-    //Watch the SOURCE_DIR_NAME directory, recompile if anything changes
-    var pathToWatch = path.join(process.cwd(), SOURCE_DIR_NAME);
-    console.log('Watching the directory %s for changes...', pathToWatch);
-    chokidar.watch(pathToWatch)
-        .on('change',
-            function(event, path){
-                console.log('Change detected...');
-                compileDebug();
-            }
-        );
+    if(!watchingFiles) {
+        watchingFiles = true;
+        //Watch the SOURCE_DIR_NAME directory, recompile if anything changes
+        var pathToWatch = path.join(process.cwd(), SOURCE_DIR_NAME);
+        console.log('Watching the directory %s for changes...', pathToWatch);
+        chokidar.watch(pathToWatch)
+            .on('change',
+                function(path){
+                    console.log('Change detected... %s', path);
+
+                    compileDebug();
+                }
+            );
+    }
 }
 
+var browserOpened = false;
 function openBrowser(url) {
-    open(url);
+    if(!browserOpened) {
+        browserOpened = true;
+        console.log('Opening browser: ', url);
+        open(url);
+    }
 }
 
 function serveRelease() {
diff --git a/npm/cli/package.json b/npm/cli/package.json
index 150b0f1..c64ec43 100644
--- a/npm/cli/package.json
+++ b/npm/cli/package.json
@@ -20,10 +20,18 @@
   "author": "Apache Royale <dev@royale.apache.org>",
   "license": "Apache-2.0",
   "dependencies": {
+    "child_process": "1.0.2",
     "chokidar": "2.0.1",
+    "connect": "3.6.5",
+    "express": "4.16.2",
     "fs-extra": "5.0.0",
+    "http": "0.0.0",
+    "livereload": "0.6.3",
+    "morgan": "1.9.0",
     "node-http-server": "8.1.2",
     "open": "0.0.5",
+    "reload": "2.2.2",
+    "serve-static": "1.13.2",
     "yargs": "11.0.0"
   },
   "bin": {
diff --git a/npm/cli/server.js b/npm/cli/server.js
new file mode 100644
index 0000000..4d6ed2a
--- /dev/null
+++ b/npm/cli/server.js
@@ -0,0 +1,36 @@
+var express = require('express');
+var http = require('http');
+var path = require('path');
+var reload = require('reload');
+var logger = require('morgan');
+var app = express();
+var fs = require('fs-extra');
+var chokidar = require('chokidar');
+
+var debugServer = module.exports = Object.create(null);
+debugServer.startDebugServer = function(p, port) {
+    //Rewrite index.html
+    var indexHTML = fs.readFileSync(path.join(p,'index.html'), 'utf8');
+    indexHTML = indexHTML.replace("</html>", '<script src="/reload/reload-client.js"></script></html>');
+    fs.writeFile(path.join(p,'index.html'), indexHTML);
+
+    //Start server
+    app.set('port', port);
+    app.use(logger('dev'));
+    app.use(express.static(p));
+    var server = http.createServer(app);
+    var reloadServer = reload(app);
+
+    //Watch and reload
+    chokidar.watch(p)
+        .on('change',
+            function(event, path){
+                console.log('Change detected...');
+                reloadServer.reload();
+            }
+        );
+
+    server.listen(app.get('port'), function () {
+        console.log('Web server listening on port ' + app.get('port'))
+    })
+}
diff --git a/npm/cli/template/reload/reload-client.js b/npm/cli/template/reload/reload-client.js
new file mode 100644
index 0000000..348c8c6
--- /dev/null
+++ b/npm/cli/template/reload/reload-client.js
@@ -0,0 +1,102 @@
+(function refresh () {
+  var verboseLogging = false
+  var socketUrl = window.location.origin
+  if (!window.location.origin.match(/:[0-9]+/)) {
+    socketUrl = window.location.origin + ':80'
+  }
+  socketUrl = socketUrl.replace() // This is dynamically populated by the reload.js file
before it is sent to the browser
+  var socket
+
+  if (verboseLogging) {
+    console.log('Reload Script Loaded')
+  }
+
+  if (!('WebSocket' in window)) {
+    throw new Error('Reload only works with browsers that support WebSockets')
+  }
+
+  // Explanation of the flags below:
+
+  // The first change flag is used to tell reload to wait until the socket closes at least
once before we allow the page to open on a socket open event. Otherwise reload will go into
a inifite loop, as the page will have a socket on open event once it loads for the first time
+  var firstChangeFlag = false
+
+  // The navigatedAwayFromPageFlag is set to true in the event handler onbeforeunload because
we want to short-circuit reload to prevent it from causing the page to reload before the navigation
occurs.
+  var navigatedAwayFromPageFlag
+
+    // Wait until the page loads for the first time and then call the webSocketWaiter function
so that we can connect the socket for the first time
+  window.addEventListener('load', function () {
+    if (verboseLogging === true) {
+      console.log('Page Loaded - Calling webSocketWaiter')
+    }
+    websocketWaiter()
+  })
+
+  // If the user navigates away from the page, we want to short-circuit reload to prevent
it from causing the page to reload before the navigation occurs.
+  window.addEventListener('beforeunload', function () {
+    if (verboseLogging === true) {
+      console.log('Navigated away from the current URL')
+    }
+
+    navigatedAwayFromPageFlag = true
+  })
+
+  // Check to see if the server sent us reload (meaning a manually reload event was fired)
and then reloads the page
+  var socketOnMessage = function (msg) {
+    if (msg.data === 'reload') {
+      socket.close()
+    }
+  }
+
+  var socketOnOpen = function (msg) {
+    if (verboseLogging) {
+      console.log('Socket Opened')
+    }
+
+    // We only allow the reload on two conditions, one when the socket closed (firstChange
=== true) and two if we didn't navigate to a new page (navigatedAwayFromPageFlag === false)
+    if (firstChangeFlag === true && navigatedAwayFromPageFlag !== true) {
+      if (verboseLogging) {
+        console.log('Reloaded')
+      }
+
+      // Reset the firstChangeFlag to false so that when the socket on open events are being
fired it won't keep reloading the page
+      firstChangeFlag = false
+
+      // Now that everything is set up properly we reload the page
+      window.location.reload()
+    }
+  }
+
+  // Socket on close event that sets flags and calls the webSocketWaiter function
+  var socketOnClose = function (msg) {
+    if (verboseLogging) {
+      console.log('Socket Closed - Calling webSocketWaiter')
+    }
+
+    // We encountered a change so we set firstChangeFlag to true so that as soon as the server
comes back up and the socket opens we can allow the reload
+    firstChangeFlag = true
+
+    // Call the webSocketWaiter function so that we can open a new socket and set the event
handlers
+    websocketWaiter()
+  }
+
+  var socketOnError = function (msg) {
+    if (verboseLogging) {
+      console.log(msg)
+    }
+  }
+
+  // Function that opens a new socket and sets the event handlers for the socket
+  function websocketWaiter () {
+    if (verboseLogging) {
+      console.log('Waiting for socket')
+    }
+    setTimeout(function () {
+      socket = new WebSocket(socketUrl) // eslint-disable-line
+
+      socket.onopen = socketOnOpen
+      socket.onclose = socketOnClose
+      socket.onmessage = socketOnMessage
+      socket.onerror = socketOnError
+    }, 250)
+  }
+})()
diff --git a/npm/cli/template/reload/reload-server.js b/npm/cli/template/reload/reload-server.js
new file mode 100644
index 0000000..c855b60
--- /dev/null
+++ b/npm/cli/template/reload/reload-server.js
@@ -0,0 +1,79 @@
+var http = require('http')
+var reload = require('../lib/reload')
+var fs = require('fs')
+var open = require('open')
+var clc = require('cli-color')
+var argv = require('minimist')(process.argv.slice(2))
+
+var serveStatic = require('serve-static')
+var finalhandler = require('finalhandler')
+var URL = require('url-parse')
+
+var port = argv._[0]
+var dir = argv._[1]
+var openBrowser = (argv._[2] === 'true')
+var hostname = argv._[3]
+var runFile = argv._[4]
+var startPage = argv._[5]
+var verbose = (argv._[6] === 'true')
+
+var reloadOpts = {
+  port: port,
+  verbose: verbose,
+  noExpress: true
+}
+
+var time
+var reloadReturned
+
+var serve = serveStatic(dir, {'index': ['index.html', 'index.htm']})
+
+var server = http.createServer(function (req, res) {
+  var url = new URL(req.url)
+  var pathname = url.pathname.replace(/(\/)(.*)/, '$2') // Strip leading `/` so we can find
files on file system
+
+  var fileEnding = pathname.split('.')[1]
+
+  if (fileEnding === 'html' || pathname === '/' || pathname === '') { // Server side inject
reload code to html files
+    if (pathname === '/' || pathname === '') {
+      pathname = dir + '/' + startPage
+    } else {
+      pathname = dir + '/' + pathname
+    }
+
+    fs.readFile(pathname, 'utf8', function (err, contents) {
+      if (err) {
+        res.writeHead(404, {'Content-Type': 'text/plain'})
+        res.end('File Not Found')
+      } else {
+        contents += '\n\n<!-- Inserted by Reload -->\n<script src="/reload/reload.js"></script>\n<!--
End Reload -->\n'
+
+        res.setHeader('Content-Type', 'text/html')
+        res.end(contents)
+      }
+    })
+  } else if (pathname === 'reload/reload.js') { // Server reload-client.js file from injected
script tag
+    res.setHeader('Content-Type', 'text/javascript')
+
+    res.end(reloadReturned.reloadClientCode())
+  } else { // Serve any other file using serve-static
+    serve(req, res, finalhandler(req, res))
+  }
+})
+
+// Reload call and configurations. Stub app as it isn't used here
+reloadReturned = reload(function () {}, reloadOpts, server)
+
+server.listen(port, function () {
+  if (!fs.existsSync(runFile)) {
+    fs.writeFileSync(runFile)
+
+    // If openBrowser, open the browser with the given start page above, at a hostname (localhost
default or specified).
+    if (openBrowser) {
+      open('http://' + hostname + ':' + port)
+    }
+  } else {
+    time = new Date()
+    console.log(clc.green('Server restarted  at ' + time.toTimeString().slice(0, 8)))
+  }
+})
diff --git a/npm/cli/template/reload/reload.js b/npm/cli/template/reload/reload.js
new file mode 100644
index 0000000..cbb43c4
--- /dev/null
+++ b/npm/cli/template/reload/reload.js
@@ -0,0 +1,153 @@
+module.exports = function reload (app, opts, server) {
+  // Requires
+  var path = require('path')
+  var fs = require('fs')
+
+  // Parameters variables
+  var httpServerOrPort
+  var expressApp
+  var verboseLogging
+  var port
+  var webSocketServerWaitStart
+
+  // Application variables
+  var RELOAD_FILE = path.join(__dirname, './reload-client.js')
+  var reloadCode = fs.readFileSync(RELOAD_FILE, 'utf8')
+  var route
+
+  // Websocket server variables
+  var ws = require('ws')
+  var WebSocketServer = ws.Server
+  var wss
+
+  // General variables
+  var socketPortSpecified
+  var argumentZero = arguments[0]
+  var reloadJsMatch
+  var reloadReturn
+
+  opts = opts || {}
+
+  if (arguments.length > 0 && (typeof (argumentZero) === 'object' || typeof (argumentZero)
=== 'function')) {
+    if (typeof (argumentZero) === 'object') { // If old arguments passed handle old arguments,
the old arguments and their order were: httpServerOrPort, expressApp, and verboseLogging
+      console.warn('Deprecated Warning: You supplied reload old arguments, please upgrade
to the new parameters see: https://github.com/alallier/reload/tree/master#api-for-express')
+      if (arguments.length < 2) {
+        throw new TypeError('Lack of/invalid arguments provided to reload. It is recommended
to update to the new arguments anyways, this would be a good time to do so.', 'reload.js',
7)
+      }
+      httpServerOrPort = argumentZero
+      expressApp = arguments[1]
+      verboseLogging = arguments[2]
+      route = '/reload/reload.js'
+    } else { // Setup options or use defaults
+      expressApp = argumentZero
+      port = opts.port || 9856
+      webSocketServerWaitStart = opts.webSocketServerWaitStart
+      route = opts.route
+
+      if (route) {
+        // If reload.js is found in the route option strip it. We will concat it for user
to ensure no case errors or order problems.
+        reloadJsMatch = route.match(/reload\.js/i)
+        if (reloadJsMatch) {
+          route = route.split(reloadJsMatch)[0]
+        }
+
+        /*
+         * Concat their provided path (minus `reload.js` if they specified it) with a `/`
if they didn't provide one and `reload.js. This allows for us to ensure case, order, and use
of `/` is correct
+         * For example these route's are all valid:
+         * 1. `newRoutePath` -> Their route + `/` + reload.js
+         * 2. `newRoutePath/` -> Their route + reload.js
+         * 3. `newRoutePath/reload.js` -> (Strip reload.js above) so now: Their route
+ reload.js
+         * 4. `newRoutePath/rEload.js` -> (Strip reload.js above) so now: Their route
+ reload.js
+         * 5. `newRoutePathreload.js` -> (Strip reload.js above) so now: Their route +
`/` + reload.js
+         * 6. `newRoutePath/reload.js/rEload.js/... reload.js n number of times -> (Strip
above removes all reload.js occurrences at the end of the specified route) so now: Their route
+ 'reload.js`
+        */
+        route = route + (route.slice(-1) === '/' ? '' : '/') + 'reload.js'
+      } else {
+        route = '/reload/reload.js'
+      }
+
+      verboseLogging = opts.verbose === true || opts.verbose === 'true' || false
+
+      if (port) {
+        socketPortSpecified = port
+        httpServerOrPort = port
+      }
+
+      if (server) {
+        socketPortSpecified = null
+        httpServerOrPort = server
+      }
+    }
+  } else {
+    throw new TypeError('Lack of/invalid arguments provided to reload', 'reload.js', 7)
+  }
+
+  // Application setup
+  if (verboseLogging) {
+    reloadCode = reloadCode.replace('verboseLogging = false', 'verboseLogging = true')
+  }
+  reloadCode = reloadCode.replace('socketUrl.replace()', 'socketUrl.replace(/(^http(s?):\\/\\/)(.*:)(.*)/,'
+ (socketPortSpecified ? '\'ws$2://$3' + socketPortSpecified : '\'ws$2://$3$4') + '\')')
+
+  if (!server) {
+    expressApp.get(route, function (req, res) {
+      res.type('text/javascript')
+      res.send(reloadCode)
+    })
+  }
+
+  if (!webSocketServerWaitStart) {
+    startWebSocketServer()
+  }
+
+  // Websocket server setup
+  function startWebSocketServer () {
+    if (verboseLogging) {
+      console.log('Starting WebSocket Server')
+    }
+
+    if (socketPortSpecified) { // Use custom user specified port
+      wss = new WebSocketServer({ port: httpServerOrPort })
+    } else { // Attach to server, using server's port. Kept here to support legacy arguments.
+      wss = new WebSocketServer({ server: httpServerOrPort })
+    }
+
+    wss.on('connection', (ws) => {
+      if (verboseLogging) {
+        console.log('Reload client connected to server')
+      }
+    })
+  }
+
+  function sendMessage (message) {
+    if (verboseLogging) {
+      console.log('Sending message to ' + (wss.clients.size) + ' connection(s): ' + message)
+    }
+
+    wss.clients.forEach(function each (client) {
+      if (client.readyState === ws.OPEN) {
+        client.send(message)
+      }
+    })
+  }
+
+  reloadReturn = {
+    'reload': function () {
+      sendMessage('reload')
+    },
+    'startWebSocketServer': function () {
+      if (webSocketServerWaitStart) {
+        startWebSocketServer()
+      }
+    }
+  }
+
+  if (server) { // Private return API only used in command line version of reload
+    reloadReturn.reloadClientCode = function () {
+      if (server) {
+        return reloadCode
+      }
+    }
+  }
+
+  return reloadReturn
+}

-- 
To stop receiving notification emails like this one, please contact
bigosmallm@apache.org.

Mime
View raw message