From 3881ac309f3c8c8f6de158b775e21df06e82ddf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 14 Oct 2020 23:20:45 -0400 Subject: [PATCH] refactor: async/await install/web.js --- install/web.js | 256 +++++++++++++++++++++++-------------------------- 1 file changed, 119 insertions(+), 137 deletions(-) diff --git a/install/web.js b/install/web.js index f624acd573..0efe68e05d 100644 --- a/install/web.js +++ b/install/web.js @@ -1,21 +1,26 @@ 'use strict'; -var winston = require('winston'); -var express = require('express'); -var bodyParser = require('body-parser'); -var fs = require('fs'); -var path = require('path'); -var childProcess = require('child_process'); -var less = require('less'); -var async = require('async'); -var uglify = require('uglify-es'); -var nconf = require('nconf'); -var Benchpress = require('benchpressjs'); - -var app = express(); -var server; - -var formats = [ +const winston = require('winston'); +const express = require('express'); +const bodyParser = require('body-parser'); +const fs = require('fs'); +const path = require('path'); +const childProcess = require('child_process'); +const less = require('less'); +const util = require('util'); +const lessRenderAsync = util.promisify( + (style, opts, cb) => less.render(String(style), opts, cb) +); +const uglify = require('uglify-es'); +const nconf = require('nconf'); + +const Benchpress = require('benchpressjs'); +const { paths } = require('../src/constants'); + +const app = express(); +let server; + +const formats = [ winston.format.colorize(), ]; @@ -42,9 +47,9 @@ winston.configure({ ], }); -var web = module.exports; +const web = module.exports; -var scripts = [ +const scripts = [ 'node_modules/jquery/dist/jquery.js', 'node_modules/xregexp/xregexp-all.js', 'public/src/modules/slugify.js', @@ -53,39 +58,39 @@ var scripts = [ 'node_modules/zxcvbn/dist/zxcvbn.js', ]; -var installing = false; -var success = false; -var error = false; -var launchUrl; +let installing = false; +let success = false; +let error = false; +let launchUrl; -web.install = function (port) { +web.install = async function (port) { port = port || 4567; winston.info('Launching web installer on port ' + port); app.use(express.static('public', {})); app.engine('tpl', function (filepath, options, callback) { - async.waterfall([ - function (next) { - fs.readFile(filepath, 'utf-8', next); - }, - function (buffer, next) { - Benchpress.compileParse(buffer.toString(), options, next); - }, - ], callback); + filepath = filepath.replace(/\.tpl$/, '.js'); + + Benchpress.__express(filepath, options, callback); }); app.set('view engine', 'tpl'); - app.set('views', path.join(__dirname, '../src/views')); + const viewsDir = path.join(paths.baseDir, 'build/public/templates'); + app.set('views', viewsDir); app.use(bodyParser.urlencoded({ extended: true, })); - - async.parallel([compileLess, compileJS, copyCSS, loadDefaults], function (err) { - if (err) { - winston.error(err.stack); - } + try { + await Promise.all([ + compileLess(), + compileJS(), + copyCSS(), + loadDefaults(), + ]); setupRoutes(); launchExpress(port); - }); + } catch (err) { + winston.error(err.stack); + } }; @@ -180,120 +185,97 @@ function install(req, res) { }); } -function launch(req, res) { - res.json({}); - server.close(); - req.setTimeout(0); - var child; - - if (!nconf.get('launchCmd')) { - child = childProcess.spawn('node', ['loader.js'], { - detached: true, - stdio: ['ignore', 'ignore', 'ignore'], - }); - - console.log('\nStarting NodeBB'); - console.log(' "./nodebb stop" to stop the NodeBB server'); - console.log(' "./nodebb log" to view server output'); - console.log(' "./nodebb restart" to restart NodeBB'); - } else { - // Use launchCmd instead, if specified - child = childProcess.exec(nconf.get('launchCmd'), { - detached: true, - stdio: ['ignore', 'ignore', 'ignore'], - }); - } +async function launch(req, res) { + try { + res.json({}); + server.close(); + req.setTimeout(0); + var child; + + if (!nconf.get('launchCmd')) { + child = childProcess.spawn('node', ['loader.js'], { + detached: true, + stdio: ['ignore', 'ignore', 'ignore'], + }); - var filesToDelete = [ - 'installer.css', - 'installer.min.js', - 'bootstrap.min.css', - ]; - - async.each(filesToDelete, function (filename, next) { - fs.unlink(path.join(__dirname, '../public', filename), next); - }, function (err) { - if (err) { - winston.warn('Unable to remove installer files'); + console.log('\nStarting NodeBB'); + console.log(' "./nodebb stop" to stop the NodeBB server'); + console.log(' "./nodebb log" to view server output'); + console.log(' "./nodebb restart" to restart NodeBB'); + } else { + // Use launchCmd instead, if specified + child = childProcess.exec(nconf.get('launchCmd'), { + detached: true, + stdio: ['ignore', 'ignore', 'ignore'], + }); } + const filesToDelete = [ + 'installer.css', + 'installer.min.js', + 'bootstrap.min.css', + ]; + await Promise.all( + filesToDelete.map( + filename => fs.promises.unlink(path.join(__dirname, '../public', filename)) + ) + ); child.unref(); process.exit(0); - }); + } catch (err) { + winston.error(err.stack); + throw err; + } } -function compileLess(callback) { - var installSrc = path.join(__dirname, '../public/less/install.less'); - fs.readFile(installSrc, function (err, style) { - if (err) { - return winston.error('Unable to read LESS install file: ', err.stack); - } - - less.render(style.toString(), { - filename: path.resolve(installSrc), - }, function (err, css) { - if (err) { - return winston.error('Unable to compile LESS: ', err.stack); - } - - fs.writeFile(path.join(__dirname, '../public/installer.css'), css.css, callback); - }); - }); +async function compileLess() { + try { + const installSrc = path.join(__dirname, '../public/less/install.less'); + const style = await fs.promises.readFile(installSrc); + const css = await lessRenderAsync(style, { filename: path.resolve(installSrc) }); + await fs.promises.writeFile(path.join(__dirname, '../public/installer.css'), css.css); + } catch (err) { + winston.error('Unable to compile LESS: \n' + err.stack); + throw err; + } } -function compileJS(callback) { - var code = ''; - async.eachSeries(scripts, function (srcPath, next) { - fs.readFile(path.join(__dirname, '..', srcPath), function (err, buffer) { - if (err) { - return next(err); - } +async function compileJS() { + let code = ''; - code += buffer.toString(); - next(); - }); - }, function (err) { - if (err) { - return callback(err); - } - try { - var minified = uglify.minify(code, { - compress: false, - }); - if (!minified.code) { - return callback(new Error('[[error:failed-to-minify]]')); - } - fs.writeFile(path.join(__dirname, '../public/installer.min.js'), minified.code, callback); - } catch (e) { - callback(e); - } + for (const srcPath of scripts) { + // eslint-disable-next-line no-await-in-loop + const buffer = await fs.promises.readFile(path.join(__dirname, '..', srcPath)); + code += buffer.toString(); + } + const minified = uglify.minify(code, { + compress: false, }); + if (!minified.code) { + throw new Error('[[error:failed-to-minify]]'); + } + await fs.promises.writeFile(path.join(__dirname, '../public/installer.min.js'), minified.code); } -function copyCSS(next) { - async.waterfall([ - function (next) { - fs.readFile(path.join(__dirname, '../node_modules/bootstrap/dist/css/bootstrap.min.css'), 'utf8', next); - }, - function (src, next) { - fs.writeFile(path.join(__dirname, '../public/bootstrap.min.css'), src, next); - }, - ], next); +async function copyCSS() { + const src = await fs.promises.readFile( + path.join(__dirname, '../node_modules/bootstrap/dist/css/bootstrap.min.css'), 'utf8' + ); + await fs.promises.writeFile(path.join(__dirname, '../public/bootstrap.min.css'), src); } -function loadDefaults(next) { - var setupDefaultsPath = path.join(__dirname, '../setup.json'); - fs.access(setupDefaultsPath, fs.constants.F_OK | fs.constants.R_OK, function (err) { - if (err) { - // setup.json not found or inaccessible, proceed with no defaults - return setImmediate(next); +async function loadDefaults() { + const setupDefaultsPath = path.join(__dirname, '../setup.json'); + try { + await fs.promises.access(setupDefaultsPath, fs.constants.F_OK | fs.constants.R_OK); + } catch (err) { + // setup.json not found or inaccessible, proceed with no defaults + if (err.code !== 'ENOENT') { + throw err; } - - winston.info('[installer] Found setup.json, populating default values'); - nconf.file({ - file: setupDefaultsPath, - }); - - next(); + } + winston.info('[installer] Found setup.json, populating default values'); + nconf.file({ + file: setupDefaultsPath, }); }