浏览代码

Migrated to Fusebox

NGPixel 8 年之前
父节点
当前提交
5189ec3835
共有 21 个文件被更改,包括 426 次插入217 次删除
  1. 15 0
      .deployexclude
  2. 7 0
      .eslintignore
  3. 3 143
      .eslintrc.json
  4. 2 2
      .gitignore
  5. 6 6
      .travis.yml
  6. 69 0
      assets/js/bundle.min.js
  7. 20 0
      client/index.js
  8. 7 1
      client/js/app.js
  9. 5 2
      client/js/components/alerts.js
  10. 5 1
      client/js/configure.js
  11. 1 1
      client/js/login.js
  12. 1 1
      client/scss/app.scss
  13. 127 0
      fuse.js
  14. 3 3
      gulpfile.js
  15. 31 31
      package.json
  16. 0 3
      test/index.js
  17. 77 0
      test/lint.js
  18. 39 0
      test/security.js
  19. 3 8
      views/auth/login.pug
  20. 3 8
      views/configure/index.pug
  21. 2 7
      views/layout.pug

+ 15 - 0
.deployexclude

@@ -0,0 +1,15 @@
+client/js
+client/scss
+coverage
+data
+logs
+node_modules
+npm
+repo
+test
+.*
+*.log
+*.tar.gz
+*.zip
+config.yml
+fuse.js

+ 7 - 0
.eslintignore

@@ -0,0 +1,7 @@
+**/node_modules/**
+**/*.min.js
+assets/**
+coverage/**
+repo/**
+data/**
+logs/**

+ 3 - 143
.eslintrc.json

@@ -1,23 +1,12 @@
 {
-  "parserOptions": {
-    "ecmaVersion": 8,
-    "ecmaFeatures": {
-      "experimentalObjectRestSpread": true,
-      "jsx": true
-    },
-    "sourceType": "module"
-  },
+  "extends": "standard",
 
   "env": {
+    "node": true,
     "es6": true,
-    "node": true
+    "jest": true
   },
 
-  "plugins": [
-    "standard",
-    "promise"
-  ],
-
   "globals": {
     "document": false,
     "navigator": false,
@@ -41,134 +30,5 @@
     "ROOTPATH": true,
     "IS_DEBUG": true,
     "PROCNAME": true
-  },
-
-  "rules": {
-    "accessor-pairs": 2,
-    "arrow-spacing": [2, { "before": true, "after": true }],
-    "block-spacing": [2, "always"],
-    "brace-style": [2, "1tbs", { "allowSingleLine": true }],
-    "camelcase": [2, { "properties": "never" }],
-    "comma-dangle": [2, "never"],
-    "comma-spacing": [2, { "before": false, "after": true }],
-    "comma-style": [2, "last"],
-    "constructor-super": 2,
-    "curly": [2, "multi-line"],
-    "dot-location": [2, "property"],
-    "eol-last": 2,
-    "eqeqeq": [2, "always", {"null": "ignore"}],
-    "func-call-spacing": [2, "never"],
-    "handle-callback-err": [2, "^(err|error)$" ],
-    "indent": [2, 2, { "SwitchCase": 1 }],
-    "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
-    "keyword-spacing": [2, { "before": true, "after": true }],
-    "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
-    "new-parens": 2,
-    "no-array-constructor": 2,
-    "no-caller": 2,
-    "no-class-assign": 2,
-    "no-cond-assign": 2,
-    "no-const-assign": 2,
-    "no-constant-condition": [2, { "checkLoops": false }],
-    "no-control-regex": 2,
-    "no-debugger": 2,
-    "no-delete-var": 2,
-    "no-dupe-args": 2,
-    "no-dupe-class-members": 2,
-    "no-dupe-keys": 2,
-    "no-duplicate-case": 2,
-    "no-duplicate-imports": 2,
-    "no-empty-character-class": 2,
-    "no-empty-pattern": 2,
-    "no-eval": 2,
-    "no-ex-assign": 2,
-    "no-extend-native": 2,
-    "no-extra-bind": 2,
-    "no-extra-boolean-cast": 2,
-    "no-extra-parens": [2, "functions"],
-    "no-fallthrough": 2,
-    "no-floating-decimal": 2,
-    "no-func-assign": 2,
-    "no-global-assign": 2,
-    "no-implied-eval": 2,
-    "no-inner-declarations": [2, "functions"],
-    "no-invalid-regexp": 2,
-    "no-irregular-whitespace": 2,
-    "no-iterator": 2,
-    "no-label-var": 2,
-    "no-labels": [2, { "allowLoop": false, "allowSwitch": false }],
-    "no-lone-blocks": 2,
-    "no-mixed-spaces-and-tabs": 2,
-    "no-multi-spaces": 2,
-    "no-multi-str": 2,
-    "no-multiple-empty-lines": [2, { "max": 1 }],
-    "no-negated-in-lhs": 2,
-    "no-new": 2,
-    "no-new-func": 2,
-    "no-new-object": 2,
-    "no-new-require": 2,
-    "no-new-symbol": 2,
-    "no-new-wrappers": 2,
-    "no-obj-calls": 2,
-    "no-octal": 2,
-    "no-octal-escape": 2,
-    "no-path-concat": 2,
-    "no-proto": 2,
-    "no-redeclare": 2,
-    "no-regex-spaces": 2,
-    "no-return-assign": [2, "except-parens"],
-    "no-self-assign": 2,
-    "no-self-compare": 2,
-    "no-sequences": 2,
-    "no-shadow-restricted-names": 2,
-    "no-sparse-arrays": 2,
-    "no-tabs": 2,
-    "no-template-curly-in-string": 2,
-    "no-this-before-super": 2,
-    "no-throw-literal": 2,
-    "no-trailing-spaces": 2,
-    "no-undef": 2,
-    "no-undef-init": 2,
-    "no-unexpected-multiline": 2,
-    "no-unmodified-loop-condition": 2,
-    "no-unneeded-ternary": [2, { "defaultAssignment": false }],
-    "no-unreachable": 2,
-    "no-unsafe-finally": 2,
-    "no-unsafe-negation": 2,
-    "no-unused-vars": [2, { "vars": "all", "args": "none" }],
-    "no-useless-call": 2,
-    "no-useless-computed-key": 2,
-    "no-useless-constructor": 2,
-    "no-useless-escape": 2,
-    "no-useless-rename": 2,
-    "no-whitespace-before-property": 2,
-    "no-with": 2,
-    "object-property-newline": [2, { "allowMultiplePropertiesPerLine": true }],
-    "one-var": [2, { "initialized": "never" }],
-    "operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }],
-    "padded-blocks": [2, "never"],
-    "quotes": [2, "single", { "avoidEscape": true, "allowTemplateLiterals": true }],
-    "rest-spread-spacing": [2, "never"],
-    "semi": [2, "never"],
-    "semi-spacing": [2, { "before": false, "after": true }],
-    "space-before-blocks": [2, "always"],
-    "space-before-function-paren": [2, "always"],
-    "space-in-parens": [2, "never"],
-    "space-infix-ops": 2,
-    "space-unary-ops": [2, { "words": true, "nonwords": false }],
-    "spaced-comment": [2, "always", { "line": { "markers": ["*package", "!", ","] }, "block": { "balanced": true, "markers": ["*package", "!", ","], "exceptions": ["*"] } }],
-    "template-curly-spacing": [2, "never"],
-    "unicode-bom": [2, "never"],
-    "use-isnan": 2,
-    "valid-typeof": 2,
-    "wrap-iife": [2, "any", { "functionPrototypeMethods": true }],
-    "yield-star-spacing": [2, "both"],
-    "yoda": [2, "never"],
-
-    "standard/object-curly-even-spacing": [2, "either"],
-    "standard/array-bracket-even-spacing": [2, "either"],
-    "standard/computed-property-even-spacing": [2, "even"],
-
-    "promise/param-names": 2
   }
 }

+ 2 - 2
.gitignore

@@ -41,8 +41,8 @@ jspm_packages
 # Optional REPL history
 .node_repl_history
 
-# SublimeText Files
-*.sublime-workspace
+# Fusebox
+.fusebox
 
 # Config Files
 config.yml

+ 6 - 6
.travis.yml

@@ -2,7 +2,7 @@ language: node_js
 node_js:
 - '7'
 - '6'
-#- '4'
+- '4'
 addons:
   apt:
     sources:
@@ -18,20 +18,20 @@ cache:
   directories:
   - node_modules
 before_script:
+- npm run build
 - npm install -g snyk
 - snyk auth $SNYK_TOKEN
 before_deploy:
-- npm install github:requarks/core -f
-- npm install -g gulp
-- gulp deploy
+- tar -czf wiki-js.tar.gz * -X='.deployexclude'
+- zip -R -q 'wiki-js' -x@.deployexclude
 - snyk monitor
 deploy:
   provider: releases
   api_key:
     secure: TyasQ2QnWQoBhsiwm88oHoeJ+PWBZnbWEJwu6JdN5HA9cXqIdHqd1msCh84gGtKRfL2EObw4AvDwLSEd5mIM0cmQfTiokYbmb7OSjOq880rbZwtXt9t9KkC5b+TIxkhJzkzi7vIpssTeNkVJBbo/R3m0suaCRqzypkW5mhVcsFhhZ8oVCZnI1uZAXCwFNMcFFUAHxWYE98tW5bfxknRU1NJFcXysN8VXskIZ82wQQBAzZ1aQgVyMl6Uw2hns399hxCx8gVKWOIdbpO1bliHBMdm5z+lR5i723IQnHpYJf4gWvPf3oHnSS1ocrJeWVoBqanC5Iu3QhwOvPLPw/AUcJOqhvS/QiGZ2AuA9GwtBpYNVYYGD9RqcODBKZy0fWluwCuVNNoQHmwMWVP7lRnwP+SNtLzzV5ZC8mrjb4B9KGoBUR8Q7lz8cMtLoPOixk1WdWOpIFzKcw/fy8Ze6cnnFKrzsPVUZy3E3SKit3GuP6Nd7ghO0Kxp4x0eAlqFDYRZ9nG55ctd0i2b5u1r+VArt21dk2aMFxL6i67funIraEndLQFHhRgPVmjemJBRXf8j8OYrGStTsm0S26IXo3iVh/NJakIg6mEFJ3j4BXPEjCUmIW0iD6sKGTeNH6jaON+DV4T+ErGnYzgwO5KIfo9cI00DqjG0tjBQ45lWaLGy6PEo=
   file:
-  - dist/wiki-js.zip
-  - dist/wiki-js.tar.gz
+  - wiki-js.zip
+  - wiki-js.tar.gz
   skip_cleanup: true
   overwrite: true
   on:

文件差异内容过多而无法显示
+ 69 - 0
assets/js/bundle.min.js


+ 20 - 0
client/index.js

@@ -0,0 +1,20 @@
+'use strict'
+
+let logic = document.documentElement.dataset.logic
+
+switch (logic) {
+  case 'login':
+    require('./scss/login.scss')
+    require('./js/login.js')
+    break
+  case 'configure':
+    require('./scss/configure.scss')
+    require('./js/configure.js')
+    break
+  default:
+    require('./node_modules/highlight.js/styles/tomorrow.css')
+    require('./node_modules/simplemde/dist/simplemde.min.css')
+    require('./scss/app.scss')
+    require('./js/app.js')
+    break
+}

+ 7 - 1
client/js/app.js

@@ -1,6 +1,12 @@
 'use strict'
 
-/* global jQuery, _, io, Sticky, alertsData, Alerts */
+/* global alertsData */
+
+import jQuery from 'jquery'
+import _ from 'lodash'
+import Sticky from 'sticky-js'
+import io from 'socket.io-client'
+import Alerts from './components/alerts.js'
 /* eslint-disable spaced-comment */
 
 jQuery(document).ready(function ($) {

+ 5 - 2
client/js/components/alerts.js

@@ -1,11 +1,12 @@
 'use strict'
 
-/* global Vue, _ */
+import Vue from 'vue'
+import _ from 'lodash'
 
 /**
  * Alerts
  */
-class Alerts { // eslint-disable-line no-unused-vars
+class Alerts {
   /**
    * Constructor
    *
@@ -107,3 +108,5 @@ class Alerts { // eslint-disable-line no-unused-vars
     }
   }
 }
+
+export default Alerts

+ 5 - 1
client/js/configure.js

@@ -1,6 +1,10 @@
 'use strict'
 
-/* global jQuery, _, Vue, VeeValidate, axios */
+import jQuery from 'jquery'
+import _ from 'lodash'
+import Vue from 'vue'
+import VeeValidate from 'vee-validate'
+import axios from 'axios'
 
 Vue.use(VeeValidate, {
   enableAutoClasses: true,

+ 1 - 1
client/js/login.js

@@ -1,6 +1,6 @@
 'use strict'
 
-/* global jQuery */
+import jQuery from 'jquery'
 
 jQuery(document).ready(function ($) {
   $('#login-user').focus()

+ 1 - 1
client/scss/app.scss

@@ -26,4 +26,4 @@ $primary: 'indigo';
 //@import './layout/_content';
 
 //@import './pages/_account';
-@import './pages/_welcome';
+@import './pages/_welcome';

+ 127 - 0
fuse.js

@@ -0,0 +1,127 @@
+'use strict'
+
+/**
+ * FUSEBOX
+ *
+ * Client & Server compiler / watcher
+ */
+
+const fsbx = require('fuse-box')
+const colors = require('colors/safe')
+const _ = require('lodash')
+
+// Parse cmd arguments
+
+const args = require('yargs')
+    .option('d', {
+      alias: 'dev',
+      describe: 'Start in Developer mode',
+      type: 'boolean'
+    })
+    .option('c', {
+      alias: 'configure',
+      describe: 'Use Configure mode',
+      type: 'boolean',
+      implies: 'd'
+    })
+    .help('h')
+    .alias('h', 'help')
+    .argv
+
+if (args.d) {
+  // =============================================
+  // DEVELOPER MODE
+  // =============================================
+
+  console.info(colors.bgWhite.black(' Starting Fuse in DEVELOPER mode... '))
+
+  const nodemon = require('nodemon')
+
+  // Client
+
+  const fuse = fsbx.FuseBox.init({
+    homeDir: './client',
+    outFile: './assets/js/bundle.min.js',
+    alias: {
+      vue: 'vue/dist/vue.js'
+    },
+    plugins: [
+      [ fsbx.SassPlugin({ includePaths: ['../core'] }), fsbx.CSSPlugin() ],
+      fsbx.BabelPlugin({ comments: false, presets: ['es2015'] }),
+      fsbx.JSONPlugin()
+    ],
+    debug: false,
+    log: true
+  })
+
+  fuse.devServer('>index.js', {
+    port: 4444,
+    httpServer: false
+  })
+
+  // Server
+
+  _.delay(() => {
+    if (args.c) {
+      nodemon({
+        exec: 'node wiki configure',
+        ignore: ['assets/', 'client/', 'data/', 'repo/', 'tests/'],
+        ext: 'js json',
+        watch: [
+          'configure.js'
+        ],
+        env: { 'NODE_ENV': 'development' }
+      })
+    } else {
+      nodemon({
+        script: './server.js',
+        args: [],
+        ignore: ['assets/', 'client/', 'data/', 'repo/', 'tests/'],
+        ext: 'js json',
+        watch: [
+          'controllers',
+          'libs',
+          'locales',
+          'middlewares',
+          'models',
+          'agent.js',
+          'server.js'
+        ],
+        env: { 'NODE_ENV': 'development' }
+      })
+    }
+  }, 1000)
+} else {
+  // =============================================
+  // BUILD MODE
+  // =============================================
+
+  console.info(colors.bgWhite.black(' Starting Fuse in BUILD mode... '))
+
+  const fuse = fsbx.FuseBox.init({
+    homeDir: './client',
+    outFile: './assets/js/bundle.min.js',
+    plugins: [
+      [ fsbx.SassPlugin({ outputStyle: 'compressed', includePaths: ['./node_modules/requarks-core'] }), fsbx.CSSPlugin() ],
+      fsbx.BabelPlugin({
+        config: {
+          comments: false,
+          presets: ['es2015']
+        }
+      }),
+      fsbx.JSONPlugin(),
+      fsbx.UglifyJSPlugin({
+        compress: { unused: false }
+      })
+    ],
+    debug: false,
+    log: true
+  })
+
+  fuse.bundle('>index.js').then(() => {
+    console.info(colors.green.bold('Assets compilation + bundling completed.'))
+  }).catch(err => {
+    console.error(colors.green.red(' X Bundle compilation failed! ' + err.message))
+    process.exit(1)
+  })
+}

+ 3 - 3
gulpfile.js

@@ -25,21 +25,21 @@ const paths = {
   scripts: {
     combine: [
       './node_modules/socket.io-client/dist/socket.io.min.js',
-      './node_modules/jquery/dist/jquery.min.js',
+      './node_modules/jquery/dist/jquery.min.js', // done
       './node_modules/vue/dist/vue.min.js',
       './node_modules/vee-validate/dist/vee-validate.min.js',
       './node_modules/axios/dist/axios.min.js',
       './node_modules/jquery-smooth-scroll/jquery.smooth-scroll.min.js',
       './node_modules/jquery-simple-upload/simpleUpload.min.js',
       './node_modules/jquery-contextmenu/dist/jquery.contextMenu.min.js',
-      './node_modules/sticky-js/dist/sticky.min.js',
+      './node_modules/sticky-js/dist/sticky.min.js', // done
       './node_modules/simplemde/dist/simplemde.min.js',
       './node_modules/ace-builds/src-min-noconflict/ace.js',
       './node_modules/ace-builds/src-min-noconflict/ext-modelist.js',
       './node_modules/ace-builds/src-min-noconflict/mode-markdown.js',
       './node_modules/ace-builds/src-min-noconflict/theme-tomorrow_night.js',
       './node_modules/filesize.js/dist/filesize.min.js',
-      './node_modules/lodash/lodash.min.js'
+      './node_modules/lodash/lodash.min.js' // done
     ],
     ace: [
       './node_modules/ace-builds/src-min-noconflict/mode-*.js',

+ 31 - 31
package.json

@@ -6,11 +6,17 @@
   "scripts": {
     "start": "node wiki start",
     "stop": "node wiki stop",
-    "dev": "gulp dev",
-    "test": "snyk test && standard && pug-lint ./views",
+    "build": "node fuse",
+    "dev": "node fuse -d",
+    "dev-configure": "node fuse -d -c",
+    "test": "jest",
     "snyk-protect": "snyk protect",
-    "__prepublish": "npm run snyk-protect"
+    "__prepublish": "npm run snyk-protect",
+    "pre-commit": "npm run test"
   },
+  "pre-commit": [
+    "pre-commit"
+  ],
   "bin": {
     "wiki": "wiki.js"
   },
@@ -114,37 +120,26 @@
   },
   "devDependencies": {
     "ace-builds": "^1.2.6",
+    "babel-cli": "^6.24.0",
+    "babel-jest": "^19.0.0",
     "babel-preset-es2015": "^6.24.0",
-    "chai": "^3.5.0",
-    "chai-as-promised": "^6.0.0",
-    "codacy-coverage": "^2.0.0",
+    "colors": "^1.1.2",
     "eslint": "^3.18.0",
+    "eslint-config-standard": "^7.1.0",
+    "eslint-plugin-import": "^2.2.0",
+    "eslint-plugin-node": "^4.2.1",
     "eslint-plugin-promise": "^3.5.0",
     "eslint-plugin-standard": "^2.1.1",
-    "gulp": "^3.9.1",
-    "gulp-babel": "^6.1.2",
-    "gulp-clean-css": "^3.0.4",
-    "gulp-concat": "^2.6.1",
-    "gulp-gzip": "^1.4.0",
-    "gulp-include": "^2.3.1",
-    "gulp-nodemon": "^2.2.1",
-    "gulp-plumber": "^1.1.0",
-    "gulp-sass": "^3.0.0",
-    "gulp-tar": "^1.9.0",
-    "gulp-uglify": "^2.1.2",
-    "gulp-watch": "^4.3.11",
-    "gulp-zip": "^4.0.0",
-    "istanbul": "^0.4.5",
+    "fuse-box": "^1.3.128",
+    "jest": "^19.0.2",
     "jquery": "^3.2.1",
     "jquery-contextmenu": "^2.4.4",
     "jquery-simple-upload": "^1.0.0",
     "jquery-smooth-scroll": "^2.0.0",
-    "merge-stream": "^1.0.1",
-    "mocha": "^3.2.0",
-    "mocha-lcov-reporter": "^1.3.0",
+    "node-sass": "^4.5.1",
     "nodemon": "^1.11.0",
+    "pre-commit": "^1.2.2",
     "pug-lint": "^2.4.0",
-    "run-sequence": "^1.2.2",
     "snyk": "^1.25.1",
     "standard": "^9.0.2",
     "sticky-js": "^1.1.9",
@@ -172,14 +167,19 @@
       "CORE_PATH",
       "ROOTPATH",
       "IS_DEBUG",
-      "PROCNAME"
-    ],
-    "ignore": [
-      "assets/**/*",
-      "data/**/*",
-      "node_modules/**/*",
-      "repo/**/*"
+      "PROCNAME",
+      "describe",
+      "it",
+      "expect"
     ]
   },
+  "jest": {
+    "collectCoverage": false,
+    "testMatch": [
+      "**/test/**/*.js?(x)",
+      "**/?(*.)(spec|test).js?(x)"
+    ],
+    "verbose": true
+  },
   "snyk": true
 }

+ 0 - 3
test/index.js

@@ -1,3 +0,0 @@
-'use strict'
-
-// TODO

+ 77 - 0
test/lint.js

@@ -0,0 +1,77 @@
+'use strict'
+
+const fs = require('fs-extra')
+const colors = require('colors')
+
+expect.extend({
+  /**
+   * Expect ESLint results to have no errors
+   * @param {*} received ESLint results
+   * @param {*} argument Arguments
+   * @returns {object} Matcher result
+   */
+  toESLint (received, argument) {
+    if (received && received.errorCount > 0) {
+      let errorMsgBuf = []
+      for (let i = 0; i < received.results.length; i++) {
+        const result = received.results[i]
+        if (result.errorCount <= 0) {
+          continue
+        }
+
+        for (let x = 0; x < result.messages.length; x++) {
+          const m = result.messages[x]
+          errorMsgBuf.push(colors.grey(`└── ${result.filePath}\t${m.line}:${m.column}\t${m.message}`))
+        }
+      }
+      if (errorMsgBuf.length > 0) {
+        return {
+          message: () => (errorMsgBuf.join(`\n`)),
+          pass: false
+        }
+      }
+    }
+    return {
+      pass: true
+    }
+  },
+  /**
+   * Expect PugLint results to have no errors
+   * @param {*} received PugLint results
+   * @param {*} argument Arguments
+   * @returns {object} Matcher result
+   */
+  toPugLint (received, argument) {
+    if (received && received.length > 0) {
+      let errorMsgBuf = []
+      for (let i = 0; i < received.length; i++) {
+        errorMsgBuf.push(colors.grey(`└── ${received[i].message}`))
+      }
+      return {
+        message: () => (errorMsgBuf.join(`\n`)),
+        pass: false
+      }
+    }
+    return {
+      pass: true
+    }
+  }
+})
+
+describe('Code Linting', () => {
+  it('should pass ESLint validation', () => {
+    const CLIEngine = require('eslint').CLIEngine
+    const cli = new CLIEngine()
+    let report = cli.executeOnFiles(['**/*.js'])
+    expect(report).toESLint()
+  })
+
+  it('should pass PugLint validation', () => {
+    const PugLint = require('pug-lint')
+    const lint = new PugLint()
+    const pugConfig = fs.readJsonSync('.pug-lintrc.json')
+    lint.configure(pugConfig)
+    let report = lint.checkPath('./views')
+    expect(report).toPugLint()
+  })
+})

+ 39 - 0
test/security.js

@@ -0,0 +1,39 @@
+'use strict'
+
+const colors = require('colors')
+
+expect.extend({
+  /**
+   * Expect Snyk results to have no errors
+   * @param {*} received Snyk results
+   * @param {*} argument Arguments
+   * @returns {object} Matcher result
+   */
+  toPassSnyk (received, argument) {
+    if (received && received.ok === false) {
+      let errorMsgBuf = []
+      for (let i = 0; i < received.vulnerabilities.length; i++) {
+        const result = received.vulnerabilities[i]
+        let vulnPath = result.from.slice(1).join(' > ')
+        errorMsgBuf.push(colors.red(`└──[${result.severity}] ${result.packageName}\t${result.title}`))
+        errorMsgBuf.push(colors.grey(`\t${vulnPath}`))
+      }
+      return {
+        message: () => (errorMsgBuf.join(`\n`)),
+        pass: false
+      }
+    }
+    return {
+      pass: true
+    }
+  }
+})
+
+describe('Security', () => {
+  it('should pass Snyk test', () => {
+    const snyk = require('snyk').test
+    return snyk('./').then(report => {
+      expect(report).toPassSnyk()
+    })
+  }, 20000)
+})

+ 3 - 8
views/auth/login.pug

@@ -1,5 +1,5 @@
 doctype html
-html
+html(data-logic='login')
   head
     meta(http-equiv='X-UA-Compatible', content='IE=edge')
     meta(charset='UTF-8')
@@ -17,13 +17,8 @@ html
       link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png')
     link(rel='manifest', href='/manifest.json')
 
-    // CSS
-    link(type='text/css', rel='stylesheet', href='/css/libs.css')
-    link(type='text/css', rel='stylesheet', href='/css/login.css')
-
-    // JS
-    script(type='text/javascript', src='/js/libs.js')
-    script(type='text/javascript', src='/js/login.js')
+    // JS / CSS
+    script(type='text/javascript', src='/js/bundle.min.js')
 
   body
     #bg

+ 3 - 8
views/configure/index.pug

@@ -1,5 +1,5 @@
 doctype html
-html
+html(data-logic='configure')
   head
     meta(http-equiv='X-UA-Compatible', content='IE=edge')
     meta(charset='UTF-8')
@@ -9,13 +9,8 @@ html
     each favsize in [32, 96, 16]
       link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png')
 
-    // CSS
-    link(type='text/css', rel='stylesheet', href='/css/libs.css')
-    link(type='text/css', rel='stylesheet', href='/css/configure.css')
-
-    // JS
-    script(type='text/javascript', src='/js/libs.js')
-    script(type='text/javascript', src='/js/configure.js')
+    // JS / CSS
+    script(type='text/javascript', src='/js/bundle.min.js')
 
     block head
 

+ 2 - 7
views/layout.pug

@@ -17,13 +17,8 @@ html
       link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png')
     link(rel='manifest', href='/manifest.json')
 
-    // CSS
-    link(type='text/css', rel='stylesheet', href='/css/libs.css')
-    link(type='text/css', rel='stylesheet', href='/css/app.css')
-
-    // JS
-    script(type='text/javascript', src='/js/libs.js')
-    script(type='text/javascript', src='/js/app.js')
+    // JS / CSS
+    script(type='text/javascript', src='/js/bundle.min.js')
 
     block head
 

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