UNPKG

@liascript/devserver

Version:
256 lines (255 loc) 10.6 kB
"use strict"; exports.__esModule = true; exports.gotoLine = exports.stop = exports.start = exports.init = void 0; require('dotenv').config(); var express = require("express"); var fs = require("fs"); var path = require("path"); var cors = require('cors'); var handlebars = require('express-handlebars'); var ip = require('ip'); var open = require('open'); var bodyParser = require('body-parser'); var app = express(); app.use(bodyParser.json()); var dirname = ''; var node_modules; var reloadPath = ''; var liascriptPath = ''; var clients = []; var gotoScript = "<script>\nif (!window.LIA) {\n window.LIA = {}\n}\n\nvar filename__ = document.location.search.replace(\"?\"+document.location.origin, \"\")\n\nwindow.LIA.lineGoto = function(linenumber) {\n fetch(\"/lineGoto\", {\n method: \"POST\",\n headers: {'Content-Type': 'application/json'}, \n body: JSON.stringify({\n \"linenumber\": linenumber,\n \"filename\": filename__\n })\n }).then(res => {\n console.log(\"Goto line\", linenumber);\n });\n}\n\nconst events = new EventSource('/gotoLine');\nevents.onmessage = (event) => {\n try {\n const data = JSON.parse(event.data);\n if (data.filename == filename__) {\n console.log(\"goto line:\", data.linenumber);\n window.LIA.gotoLine(data.linenumber)\n }\n } catch (e) {\n console.warn(\"gotoLine failed\")\n }\n};\n</script>"; var serverPointer; init(__dirname); function init(serverPath, nodeModulesPath) { dirname = serverPath || path.join(__dirname, '..'); node_modules = nodeModulesPath || path.join(dirname, 'node_modules'); reloadPath = path.resolve(path.join(node_modules, 'reloadsh.js/reloader.browser.js')); liascriptPath = path.resolve(path.join(node_modules, '@liascript/editor/dist')); } exports.init = init; function start(port, hostname, input, responsiveVoice, liveReload, openInBrowser, testOnline, gotoCallback) { port = port || 3000; hostname = hostname || 'localhost'; openInBrowser = openInBrowser || false; input = input || '.'; liveReload = liveReload || false; testOnline = testOnline || false; var project = { path: input, readme: undefined }; if (input) { var stats = fs.lstatSync(input); // Is it a directory? if (stats.isDirectory()) { project.path = input; } else if (stats.isFile()) { project.path = path.dirname(input); project.readme = path.basename(input); } } app.set('view engine', 'hbs'); app.engine('hbs', handlebars({ layoutsDir: path.resolve(path.join(dirname, 'views/layouts')), defaultLayout: 'main', extname: 'hbs' })); app.set('views', path.resolve(path.join(dirname, 'views'))); app.get('/', function (req, res) { res.redirect('/home'); }); app.get('/gotoLine', eventsHandler); app.get('/home*', function (req, res) { var currentPath = project.path + '/' + req.params[0]; var stats = fs.lstatSync(currentPath); // Is it a directory? if (stats.isDirectory()) { var files = fs.readdirSync(currentPath).filter(function (e) { return e[0] !== '.'; }); var basePath = '/home'; var pathNames = req.params[0].split('/').filter(function (e) { return e !== ''; }); var paths = []; for (var i = 0; i < pathNames.length; i++) { basePath += '/' + pathNames[i]; paths.push({ name: pathNames[i], href: basePath }); } res.render('main', { layout: 'index', path: paths, file: files .map(function (file) { return { name: file, href: "http://".concat(hostname, ":").concat(port, "/home").concat(req.params[0], "/").concat(file), isDirectory: fs.lstatSync(currentPath + '/' + file).isDirectory() }; }) .sort(function (a, b) { if (a.isDirectory && !b.isDirectory) { return -1; } else if (!a.isDirectory && b.isDirectory) { return 1; } else { if (a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) { return -1; } else { return 1; } } return 0; }) }); } else if (stats.isFile()) { if (req.params[0].toLocaleLowerCase().endsWith('.md')) { if (testOnline) { res.redirect("https://LiaScript.github.io/course/?http://".concat(hostname, ":").concat(port, "/").concat(req.params[0])); } else { res.redirect("/liascript/index.html?http://".concat(hostname, ":").concat(port, "/").concat(req.params[0])); } } else { res.sendFile(req.params[0], { root: project.path }); } } else { res.send('ups, something went wrong'); } }); app.get('/liascript/', function (req, res) { res.redirect('/liascript/index.html'); }); app.get('/liascript/index.html', function (req, res) { // ------------------------------------ if (liveReload && responsiveVoice) { fs.readFile(liascriptPath + '/index.html', 'utf8', function (err, data) { res.send(data.replace('</head>', "<script type='text/javascript' src='/reloader/reloader.js'></script>\n <script type='text/javascript' src='https://code.responsivevoice.org/responsivevoice.js?key=".concat(responsiveVoice, "'></script>\n ").concat(gotoScript, "\n </head>"))); }); } // ------------------------------------ else if (liveReload) { fs.readFile(liascriptPath + '/index.html', 'utf8', function (err, data) { res.send(data.replace('</head>', "<script type='text/javascript' src='/reloader/reloader.js'></script>\n ".concat(gotoScript, "\n </head>"))); }); } // ------------------------------------ else if (responsiveVoice) { fs.readFile(liascriptPath + '/index.html', 'utf8', function (err, data) { res.send(data.replace('</head>', "<script type='text/javascript' src='https://code.responsivevoice.org/responsivevoice.js?key=".concat(responsiveVoice, "'></script>\n ").concat(gotoScript, "\n </head>"))); }); } // ------------------------------------ else { fs.readFile(liascriptPath + '/index.html', 'utf8', function (err, data) { res.send(data.replace('</head>', "".concat(gotoScript, "</head>"))); }); } }); // load everything from the liascript folder app.get('/liascript/*', function (req, res) { res.sendFile(req.params[0], { root: liascriptPath }); }); // ignore this one app.get('/sw.js', function (req, res) { }); app.get('/favicon.ico', function (req, res) { }); // pass the reloader, to be used for live updates app.get('/reloader/reloader.js', function (req, res) { res.sendFile(reloadPath); }); // react to click-events app.post('/lineGoto', function (req, res) { if (gotoCallback) { try { var linenumber = req.body.linenumber; var filename = req.body.filename; gotoCallback(linenumber, filename); } catch (e) { console.warn("lineGoto event with wrong datatype, you have to provide {'linenumber': int, 'filename': string}"); } } return res.json({}); }); // everything else comes from the current project folder app.get('/*', cors(), function (req, res) { res.sendFile(req.originalUrl, { root: project.path }); }); var localURL = 'http://' + hostname + ':' + port; if (project.path && project.readme) { localURL += '/liascript/index.html?http://' + hostname + ':' + port + '/' + project.readme; } if (testOnline && project.readme) { localURL = 'https://LiaScript.github.io/course/?http://' + hostname + ':' + port + '/' + project.readme; } var server = require('reloadsh.js')(app, liveReload ? [path.join(project.path, project.readme || '')] : []); if (liveReload) { console.log("\u2728 watching for changes on: \"".concat(path.join(project.path || '', project.readme || ''), "\"")); } server.on('error', function (e) { throw e; }); server.listen(port); if (openInBrowser) { open(localURL); } console.log('📡 starting server'); console.log(" - local: ".concat(localURL)); console.log(" - on your network: ".concat(localURL.replace(hostname, ip.address()))); serverPointer = server; } exports.start = start; function stop() { if (serverPointer) { serverPointer.close(); } } exports.stop = stop; function gotoLine(linenumber, filename) { clients.forEach(function (client) { return client.response.write("data: ".concat(JSON.stringify({ linenumber: linenumber, filename: filename }), "\n\n")); }); } exports.gotoLine = gotoLine; function eventsHandler(request, response, next) { var headers = { 'Content-Type': 'text/event-stream', Connection: 'keep-alive', 'Cache-Control': 'no-cache' }; response.writeHead(200, headers); var data = "data: \n\n"; response.write(data); var clientId = Date.now(); var newClient = { id: clientId, response: response }; clients.push(newClient); request.on('close', function () { console.log("".concat(clientId, " Connection closed")); clients = clients.filter(function (client) { return client.id !== clientId; }); }); }