浏览代码

async expressjs code; version 1.0.0

Andi Dittrich 7 年之前
父节点
当前提交
a4a02de68d
共有 15 个文件被更改,包括 232 次插入164 次删除
  1. 1 0
      CHANGES.md
  2. 55 22
      README.md
  3. 11 38
      bin/generator.js
  4. 0 0
      dist/HTTP500.html
  5. 0 0
      dist/HTTP502.html
  6. 0 0
      dist/HTTP503.html
  7. 0 0
      dist/HTTP521.html
  8. 0 0
      dist/HTTP533.html
  9. 二进制
      dist/pages.tar
  10. 39 18
      express-demo.js
  11. 68 43
      lib/dispatcher.js
  12. 18 21
      lib/error-handler.js
  13. 15 0
      lib/json-reader.js
  14. 20 19
      lib/page-renderer.js
  15. 5 3
      package.json

+ 1 - 0
CHANGES.md

@@ -3,6 +3,7 @@ Preliminary
 
 ### 0.6.0 ###
 * New Generator/Build System: [EJS](https://github.com/mde/ejs) (templates), [SCSS](http://sass-lang.com/) (styles) and [GULP](https://gulpjs.com/) (build) are used as a replacement of the historical php/bash/ant/less setup.
+* New express.js handler (full asynchronous operation)
 * JSON based page definitions including **i18n** support
 * Option to use custom styles
 * Option to use custom template

+ 55 - 22
README.md

@@ -76,36 +76,69 @@ server {
 
 HttpErrorPages are available as NPM-Package - just install `http-error-pages` via **npm/yarn**
 
+**Installation**
+
 ```terminal
 npm install http-error-pages --save
 ```
 
-Example
+**Example**
 
 ```js
-var _express = require('express');
-var _webapp = _express();
-var _httpErrorPages = require('http-error-pages');
-
-// demo handler
-_webapp.get('/', function(req, res){
-    res.type('.txt').send('HttpErrorPages Demo');
-});
-
-// throw an 403 error
-_webapp.get('/my403error', function(req, res, next){
-    var myError = new Error();
-    myError.status = 403;
-    next(myError);
-});
-
-// use http error pages handler (final statement!)
-_httpErrorPages(_webapp);
-
-// start service
-_webapp.listen(8888);
+const _express = require('express');
+const _webapp = _express();
+
+// use require('http-error-pages') for regular apps!
+const _httpErrorPages = require('./lib/error-handler');
+
+async function bootstrap(){
+    // demo handler
+    _webapp.get('/', function(req, res){
+        res.type('.txt').send('HttpErrorPages Demo');
+    });
+
+    // throw an 403 error
+    _webapp.get('/my403error', function(req, res, next){
+        const myError = new Error();
+        myError.status = 403;
+        next(myError);
+    });
+
+    // throw an internal error
+    _webapp.get('/500', function(req, res){
+        throw new Error('Server Error');
+    });
+
+    // use http error pages handler (final statement!)
+    // because of the asynchronous file-loaders, wait until it has been executed
+    await _httpErrorPages(_webapp, {
+        lang: 'en_US',
+        footer: 'Hello <strong>World</strong>'
+    });
+
+    // start service
+    _webapp.listen(8888);
+}
+
+// invoke bootstrap operation
+bootstrap()
+    .then(function(){
+        console.log('Running Demo on Port 8888');
+    })
+    .catch(function(e){
+        console.error(e);
+    });
 ```
 
+**Options**
+
+Syntax: `Promise _httpErrorPages(expressWebapp [, options:Object])`
+
+* `template` - the path to a custom **EJS** template used to generate the pages. default [assets/template.ejs](assets/template.ejs)
+* `css` - the path to a precompiled **CSS** file injected into the page. default [assets/layout.css](assets/layout.css)
+* `footer` - optional page footer content (html allowed). default **null**
+* `lang` - language definition which should be used (available in the `i18n/` directory). default **en_US**
+
 ## Apache Httpd Integration ##
 [Apache Httpd 2.x](http://httpd.apache.org/) supports custom error-pages using multiple [ErrorDocument](http://httpd.apache.org/docs/2.4/mod/core.html#errordocument) directives.
 

+ 11 - 38
bin/generator.js

@@ -1,57 +1,30 @@
 #!/usr/bin/env node
 
 const _fs = require('fs-magic');
-const _ejs = require('ejs');
 const _path = require('path');
 const _assetsPath = _path.join(__dirname, '../assets');
 const _langPath = _path.join(__dirname, '../i18n');
 const _cli = require('commander');
 const _pkg = require('../package.json');
+const _pageRenderer = require('../lib/page-renderer');
+const _jsonReader = require('../lib/json-reader');
 
 // global paths
 let templatePath = null;
 let cssPath = null;
 
-// render template using given data
-async function renderTemplate(data={}){
-    // fetch css
-    data.inlinecss = await _fs.readFile(cssPath, 'utf8');
-
-    // fetch template
-    const tpl = await _fs.readFile(templatePath, 'utf8');
-   
-    // render template - use custom escape function to handle linebreaks!
-    return _ejs.render(tpl, data, {
-        escape: function(text){
-            // apply generic escape function
-            text = _ejs.escapeXML(text);
-
-            // linebreaks
-            text = text.replace(/\n/g, '<br />');
-
-            return text;
-        }
-    });
-}
-
-// parse json file and allow single line comments
-async function readJSONFile(filename){
-    // load file
-    let raw = await _fs.readFile(filename, 'utf8');
-
-    // strip single line js comments
-    raw = raw.replace(/^\s*\/\/.*$/gm, '');
-
-    // parse text
-    return JSON.parse(raw);
-}
-
 async function generator(configFilename, pageDefinitionFile, distPath){
     // load config
-    const config = await readJSONFile(configFilename);
+    const config = await _jsonReader(configFilename);
 
     // load page definitions
-    const pages = await readJSONFile(pageDefinitionFile);
+    const pages = await _jsonReader(pageDefinitionFile);
+
+    // load template
+    const tpl = await _fs.readFile(templatePath, 'utf8');
+   
+    // load css
+    const css = await _fs.readFile(cssPath, 'utf8');
 
     console.log('Generating static pages');
 
@@ -67,7 +40,7 @@ async function generator(configFilename, pageDefinitionFile, distPath){
         pconf.footer = pconf.footer || config.footer;
 
         // render page
-        const content = await renderTemplate(pconf);
+        const content = await _pageRenderer(tpl, css, pconf);
 
         // generate filename
         const filename = 'HTTP' + p + '.html';

文件差异内容过多而无法显示
+ 0 - 0
dist/HTTP500.html


文件差异内容过多而无法显示
+ 0 - 0
dist/HTTP502.html


文件差异内容过多而无法显示
+ 0 - 0
dist/HTTP503.html


文件差异内容过多而无法显示
+ 0 - 0
dist/HTTP521.html


文件差异内容过多而无法显示
+ 0 - 0
dist/HTTP533.html


二进制
dist/pages.tar


+ 39 - 18
express-demo.js

@@ -1,22 +1,43 @@
-var _express = require('express');
-var _webapp = _express();
-var _httpErrorPages = require('./lib/error-handler');
+const _express = require('express');
+const _webapp = _express();
 
-// demo handler
-_webapp.get('/', function(req, res){
-    res.type('.txt').send('HttpErrorPages Demo');
-});
+// use require('http-error-pages') for regular apps!
+const _httpErrorPages = require('./lib/error-handler');
 
-// throw an 403 error
-_webapp.get('/my403error', function(req, res, next){
-    var myError = new Error();
-    myError.status = 403;
-    next(myError);
-});
+async function bootstrap(){
+    // demo handler
+    _webapp.get('/', function(req, res){
+        res.type('.txt').send('HttpErrorPages Demo');
+    });
 
-// use http error pages handler (final statement!)
-_httpErrorPages(_webapp);
+    // throw an 403 error
+    _webapp.get('/my403error', function(req, res, next){
+        const myError = new Error();
+        myError.status = 403;
+        next(myError);
+    });
 
-// start service
-_webapp.listen(8888);
-console.log('Running Demo on Port 8888');
+    // throw an internal error
+    _webapp.get('/500', function(req, res){
+        throw new Error('Server Error');
+    });
+
+    // use http error pages handler (final statement!)
+    // because of the asynchronous file-loaders, wait until it has been executed
+    await _httpErrorPages(_webapp, {
+        lang: 'en_US',
+        footer: 'Hello <strong>World</strong>'
+    });
+
+    // start service
+    _webapp.listen(8888);
+}
+
+// invoke bootstrap operation
+bootstrap()
+    .then(function(){
+        console.log('Running Demo on Port 8888');
+    })
+    .catch(function(e){
+        console.error(e);
+    });

+ 68 - 43
lib/dispatcher.js

@@ -1,47 +1,72 @@
-const _pages = require('../dist/pages.json');
-const _renderer = require('./page-renderer');
-
-// multi-type support
-// @see https://github.com/expressjs/express/blob/master/examples/error-pages/index.js
-function dispatchRequest(page, httpStatusCode, req, res){
-    // page available ?
-    if (!_pages[page]){
-        // use "internal server error" as default
-        page = '500';
-        httpStatusCode = null;
-    }
+const _render = require('./page-renderer');
+const _path = require('path');
+const _fs = require('fs-magic');
+const _jsonReader = require('./json-reader');
+
+// wrapper to add custom options
+async function createDispatcher(options={}){
+
+    // merge options
+    const opt = {
+        template: options.template || _path.join(__dirname, '../assets/template.ejs'),
+        css: options.css || _path.join(__dirname, '../assets/layout.css'),
+        lang: options.lang || 'en_US',
+        footer: options.footer || null
+    };
 
-    // set http status code
-    res.status(httpStatusCode || 500);
-
-    // extract page date
-    const pageData = _pages[page];
-
-    // multiple response formats
-    res.format({
-        // standard http-error-pages
-        html: function(){
-            res.type('.html');
-            res.send(_renderer({
-                code: httpStatusCode,
-                title: pageData.title,
-                message: pageData.message
-            }))
-        },
-
-        // json
-        json: function(){
-            res.json({
-                error: pageData.title + ' - ' + pageData.message
-            })
-        },
-
-        // text response
-        default: function(){
-            // plain text
-            res.type('.txt').send(pageData.title + ' - ' + pageData.message);
+    // load page template
+    const tpl = await _fs.readFile(opt.template, 'utf8');
+
+    // load styles
+    const css = await _fs.readFile(opt.css, 'utf8');
+    
+    // load page definitions
+    const pages = await _jsonReader(_path.join(__dirname, '../i18n/pages-' + opt.lang + '.json'));
+
+    // multi-type support
+    // @see https://github.com/expressjs/express/blob/master/examples/error-pages/index.js
+    return function dispatchRequest(page, httpStatusCode, req, res){
+        // page available ?
+        if (!pages[page]){
+            // use "internal server error" as default
+            page = '500';
+            httpStatusCode = null;
         }
-    })
+
+        // set http status code
+        res.status(httpStatusCode || 500);
+
+        // extract page date
+        const pageData = pages[page];
+
+        // multiple response formats
+        res.format({
+            // standard http-error-pages
+            html: function(){
+                res.type('.html');
+                res.send(_render(tpl, css, {
+                    code: httpStatusCode,
+                    title: pageData.title,
+                    message: pageData.message,
+                    footer: opt.footer
+                }))
+            },
+
+            // json
+            json: function(){
+                res.json({
+                    error: pageData.title + ' - ' + pageData.message
+                })
+            },
+
+            // text response
+            default: function(){
+                // plain text
+                res.type('.txt').send(pageData.title + ' - ' + pageData.message);
+            }
+        })
+    }
 }
 
-module.exports = dispatchRequest;
+
+module.exports = createDispatcher;

+ 18 - 21
lib/error-handler.js

@@ -1,27 +1,24 @@
 const _dispatcher = require('./dispatcher');
 
-// http404 handler
-function notfoundHandler(req, res){
-    _dispatcher('404', 404, req, res);
-}
+module.exports = async function(router, options={}){
+    // create new disptacher with given options
+    const dispatch = await _dispatcher(options);
 
-// default error handler
-function errorHandler(err, req, res, next){
-    // status code given ?
-    if (err.status){
-        // custom errorpage set ?
-        _dispatcher(err.errorpage || err.status, err.status, req, res);
-
-    // use default http500 page
-    }else{
-        _dispatcher('500', 500, req, res);
-    }
-}
-
-module.exports = function(router){
-    // 404
-    router.use(notfoundHandler);
+    // default 404 error - no route matches
+    router.all('*', function(req, res){
+        dispatch('404', 404, req, res);
+    });
 
     // internal errors (all)
-    router.use(errorHandler);
+    router.use(function(err, req, res, next){
+        // status code given ?
+        if (err.status){
+            // custom errorpage set ?
+            dispatch(err.errorpage || err.status, err.status, req, res);
+    
+        // use default http500 page
+        }else{
+            dispatch('500', 500, req, res);
+        }
+    });
 };

+ 15 - 0
lib/json-reader.js

@@ -0,0 +1,15 @@
+const _fs = require('fs-magic');
+
+// parse json file and allow single line comments
+async function readJSONFile(filename){
+    // load file
+    let raw = await _fs.readFile(filename, 'utf8');
+
+    // strip single line js comments
+    raw = raw.replace(/^\s*\/\/.*$/gm, '');
+
+    // parse text
+    return JSON.parse(raw);
+}
+
+module.exports = readJSONFile;

+ 20 - 19
lib/page-renderer.js

@@ -1,26 +1,27 @@
-const _path = require('path');
-const _fs = require('fs');
-const _basedir = _path.dirname(__dirname);
+const _ejs = require('ejs');
 
-// load template file (1 time)
-const _template = _fs.readFileSync(_path.join(_basedir, 'dist/HTTP0.html'), 'utf8');
+// render template using given data
+function renderTemplate(template, css, data={}){
+  
+    // assign css
+    data.inlinecss = css;
 
-// simple template renderer
-function renderPage(vars){
-    
-    // add vars
-    const tpl = _template.replace(/{{([a-z]+)}}/gm, function(match, name){
+    // render template - use custom escape function to handle linebreaks!
+    return _ejs.render(template, data, {
+        escape: function(text){
+            if (!text){
+                return '';
+            }
 
-        // var available ?
-        if (vars[name]){
-            return vars[name];
-        // remove unused vars
-        }else{
-            return '';
+            // apply generic escape function
+            text = _ejs.escapeXML(text);
+
+            // linebreaks
+            text = text.replace(/\n/g, '<br />');
+
+            return text;
         }
     });
-
-    return tpl;
 }
 
-module.exports = renderPage;
+module.exports = renderTemplate;

+ 5 - 3
package.json

@@ -1,6 +1,6 @@
 {
     "name": "http-error-pages",
-    "version": "0.6.0",
+    "version": "1.0.0",
     "description": "Simple HTTP Error Pages for expressjs",
     "engines": {
         "node": ">=7.6"
@@ -25,6 +25,8 @@
         "lib",
         "dist",
         "i18n",
+        "assets",
+        "bin",
         "express-demo.js",
         "CHANGES.md",
         "LICENSE.md",
@@ -44,7 +46,6 @@
         "eslint": "^4.11.0",
         "eslint-config-aenondynamics": "^0.2.0",
         "express": "^4.15.2",
-        "fs-magic": "^2.1.1",
         "gulp": "^3.9.1",
         "gulp-clean-css": "^3.9.0",
         "gulp-concat-util": "^0.5.5",
@@ -53,6 +54,7 @@
         "less": "^2.7.3"
     },
     "dependencies": {
-        "ejs": "^2.5.7"
+        "ejs": "^2.5.7",
+        "fs-magic": "^2.1.1"
     }
 }

部分文件因为文件数量过多而无法显示