Bläddra i källkod

refactor: client-side optimizations + lazy-loading

NGPixel 8 år sedan
förälder
incheckning
dc0e2fac41

+ 9 - 6
client/js/app.js

@@ -8,7 +8,7 @@ import Vue from 'vue'
 import VueResource from 'vue-resource'
 import VueClipboards from 'vue-clipboards'
 import store from './store'
-import io from 'socket.io-client'
+import io from 'socket-io-client'
 import i18next from 'i18next'
 import i18nextXHR from 'i18next-xhr-backend'
 import VueI18Next from '@panter/vue-i18next'
@@ -23,14 +23,15 @@ import alertComponent from './components/alert.vue'
 import anchorComponent from './components/anchor.vue'
 import colorPickerComponent from './components/color-picker.vue'
 import loadingSpinnerComponent from './components/loading-spinner.vue'
+import modalCreatePageComponent from './components/modal-create-page.vue'
+import modalCreateUserComponent from './components/modal-create-user.vue'
 import searchComponent from './components/search.vue'
 import treeComponent from './components/tree.vue'
 
-import adminUsersCreateComponent from './modals/admin-users-create.vue'
-
 import adminProfileComponent from './pages/admin-profile.component.js'
 import adminSettingsComponent from './pages/admin-settings.component.js'
-import sourceComponent from './pages/source.component.js'
+import contentViewComponent from './pages/content-view.component.js'
+import sourceViewComponent from './pages/source-view.component.js'
 
 // ====================================
 // Initialize Vue Modules
@@ -81,12 +82,14 @@ $(() => {
       alert: alertComponent,
       adminProfile: adminProfileComponent,
       adminSettings: adminSettingsComponent,
-      adminUsersCreate: adminUsersCreateComponent,
       anchor: anchorComponent,
       colorPicker: colorPickerComponent,
+      contentView: contentViewComponent,
       loadingSpinner: loadingSpinnerComponent,
+      modalCreatePage: modalCreatePageComponent,
+      modalCreateUser: modalCreateUserComponent,
       search: searchComponent,
-      sourceView: sourceComponent,
+      sourceView: sourceViewComponent,
       tree: treeComponent
     },
     store,

+ 0 - 2
client/js/components/anchor.vue

@@ -14,8 +14,6 @@
 </template>
 
 <script>
-  import * as _ from 'lodash'
-
   export default {
     name: 'anchor',
     data () {

+ 16 - 17
client/js/modals/create.vue → client/js/components/modal-create-page.vue

@@ -10,45 +10,44 @@
             input.input(type='text', placeholder='page-name', v-model='entrypath', autofocus)
             span.help.is-danger(v-show='isInvalid') This document path is invalid!
         footer
-          a.button.is-grey.is-outlined(v-on:click='hide') Discard
+          a.button.is-grey.is-outlined(v-on:click='cancel') Discard
           a.button.is-light-blue(v-on:click='create') Create
 </template>
 
 <script>
-  import * as _ from 'lodash'
-  import { makeSafePath } from '../helpers/pages'
+  import { isEmpty } from 'lodash'
+  // import { makeSafePath } from '../helpers/pages'
+  import { mapState } from 'vuex'
 
   export default {
     name: 'modal-create',
     data () {
       return {
-        entrypath: ''
-        isInvalid: false,
-        isLoading: false,
-        isShown: false
+        isLoading: false
       }
     },
+    computed: mapState('createPage', {
+      entrypath: '',
+      isShown: 'shown',
+      isInvalid: 'invalid'
+    }),
     methods: {
-      show: function () {
-        this.isInvalid = false
-        this.shown = true
-      },
-      hide: function () {
-        this.shown = false
+      cancel: function () {
+        this.$store.dispatch('createPageClose')
       },
       create: function () {
         this.isInvalid = false
         let newDocPath = makeSafePath(this.entrypath)
-        if (_.isEmpty(newDocPath)) {
-          this.isInvalid = true
+        if (isEmpty(newDocPath)) {
+          this.$store.createPage.commit('')
         } else {
-          $('#txt-create-prompt').parent().addClass('is-loading')
+          this.isLoading = true
           window.location.assign('/create/' + newDocPath)
         }
       }
     },
     mounted () {
-      this.entrypath = currentBasePath + '/new-page'
+      // this.entrypath = currentBasePath + '/new-page'
     }
   }
 </script>

+ 0 - 0
client/js/modals/admin-users-create.vue → client/js/components/modal-create-user.vue


+ 2 - 2
client/js/components/page-loader.js

@@ -1,13 +1,13 @@
 'use strict'
 
 import $ from 'jquery'
-import _ from 'lodash'
+import delay from 'lodash/delay'
 
 module.exports = {
 
   complete () {
     $('#page-loader').addClass('is-loaded')
-    _.delay(() => {
+    delay(() => {
       $('#page-loader').addClass('is-hidden')
     }, 1100)
   }

+ 14 - 19
client/js/pages/view.js → client/js/pages/content-view.component.js

@@ -1,23 +1,13 @@
 'use strict'
 
-/* eslint-disable no-new */
-
-import $ from 'jquery'
 import MathJax from 'mathjax'
 
-module.exports = (alerts) => {
-  if ($('#page-type-view').length) {
-    let currentBasePath = ($('#page-type-view').data('entrypath') !== 'home') ? $('#page-type-view').data('entrypath') : ''
-
-    // Copy Path
-
-    // new Vue({
-    //   el: '.modal-copypath',
-    //   render: h => h(CopyPath)
-    // })
-
-    // MathJax Render
-
+export default {
+  name: 'content-view',
+  data() {
+    return {}
+  },
+  mounted() {
     MathJax.Hub.Config({
       jax: ['input/TeX', 'input/MathML', 'output/SVG'],
       extensions: ['tex2jax.js', 'mml2jax.js'],
@@ -36,8 +26,13 @@ module.exports = (alerts) => {
       messageStyle: 'none'
     })
     MathJax.Hub.Configured()
-
-    require('../modals/create.js')(currentBasePath)
-    require('../modals/move.js')(currentBasePath, alerts)
   }
 }
+
+// module.exports = (alerts) => {
+//   if ($('#page-type-view').length) {
+//     let currentBasePath = ($('#page-type-view').data('entrypath') !== 'home') ? $('#page-type-view').data('entrypath') : ''
+//     require('../modals/create.js')(currentBasePath)
+//     require('../modals/move.js')(currentBasePath, alerts)
+//   }
+// }

+ 27 - 0
client/js/pages/source-view.component.js

@@ -0,0 +1,27 @@
+'use strict'
+
+/* global FuseBox */
+
+import pageLoader from '../components/page-loader'
+
+export default {
+  name: 'source-view',
+  data() {
+    return {}
+  },
+  mounted() {
+    FuseBox.import('/js/ace/source-view.js', (ace) => {
+      let scEditor = ace.edit('source-display')
+      scEditor.setTheme('ace/theme/dawn')
+      scEditor.getSession().setMode('ace/mode/markdown')
+      scEditor.setOption('fontSize', '14px')
+      scEditor.setOption('hScrollBarAlwaysVisible', false)
+      scEditor.setOption('wrap', true)
+      scEditor.setReadOnly(true)
+      scEditor.renderer.updateFull()
+      scEditor.renderer.on('afterRender', () => {
+        pageLoader.complete()
+      })
+    })
+  }
+}

+ 0 - 26
client/js/pages/source.component.js

@@ -1,26 +0,0 @@
-'use strict'
-
-import * as ace from 'brace'
-import 'brace/theme/tomorrow_night'
-import 'brace/mode/markdown'
-import pageLoader from '../components/page-loader'
-
-export default {
-  name: 'source-view',
-  data() {
-    return {}
-  },
-  mounted() {
-    let scEditor = ace.edit('source-display')
-    scEditor.setTheme('ace/theme/tomorrow_night')
-    scEditor.getSession().setMode('ace/mode/markdown')
-    scEditor.setOption('fontSize', '14px')
-    scEditor.setOption('hScrollBarAlwaysVisible', false)
-    scEditor.setOption('wrap', true)
-    scEditor.setReadOnly(true)
-    scEditor.renderer.updateFull()
-    scEditor.renderer.on('afterRender', () => {
-      pageLoader.complete()
-    })
-  }
-}

+ 4 - 2
client/js/store/index.js

@@ -3,7 +3,8 @@ import Vuex from 'vuex'
 
 import alert from './modules/alert'
 import anchor from './modules/anchor'
-import adminUsersCreate from './modules/admin-users-create'
+import modalCreatePage from './modules/modal-create-page'
+import modalCreateUser from './modules/modal-create-user'
 
 Vue.use(Vuex)
 
@@ -22,6 +23,7 @@ export default new Vuex.Store({
   modules: {
     alert,
     anchor,
-    adminUsersCreate
+    modalCreatePage,
+    modalCreateUser
   }
 })

+ 0 - 0
client/js/store/modules/admin-users-create.js → client/js/store/modules/modal-create-page.js


+ 15 - 0
client/js/store/modules/modal-create-user.js

@@ -0,0 +1,15 @@
+'use strict'
+
+export default {
+  state: {
+    shown: false
+  },
+  getters: {},
+  mutations: {
+    shownChange: (state, shownState) => { state.shown = shownState }
+  },
+  actions: {
+    adminUsersCreateOpen({ commit }) { commit('shownChange', true) },
+    adminUsersCreateClose({ commit }) { commit('shownChange', false) }
+  }
+}

+ 26 - 11
fuse.js

@@ -13,7 +13,7 @@ const fs = Promise.promisifyAll(require('fs-extra'))
 const fsbx = require('fuse-box')
 const nodemon = require('nodemon')
 const path = require('path')
-const uglify = require('uglify-js')
+const uglify = require('uglify-es')
 
 // ======================================================
 // Parse cmd arguments
@@ -64,13 +64,28 @@ let globalTasks = Promise.mapSeries([
       if (err.code === 'ENOENT') {
         console.info(colors.white('  └── ') + colors.green('Copy + Minify ACE modes to assets...'))
         return fs.ensureDirAsync('./assets/js/ace').then(() => {
-          return fs.readdirAsync('./node_modules/brace/mode').then(modeList => {
-            return Promise.map(modeList, mdFile => {
-              console.info(colors.white('      mode-' + mdFile))
-              let result = uglify.minify(path.join('./node_modules/brace/mode', mdFile), { output: { 'max_line_len': 1000000 } })
-              return fs.writeFileAsync(path.join('./assets/js/ace', 'mode-' + mdFile), result.code)
+          return Promise.join(
+            // Core
+            Promise.all([
+              fs.readFileAsync('./node_modules/brace/index.js', 'utf8'),
+              fs.readFileAsync('./node_modules/brace/theme/dawn.js', 'utf8'),
+              fs.readFileAsync('./node_modules/brace/mode/markdown.js', 'utf8')
+            ]).then(items => {
+              console.info(colors.white('      source-view.js'))
+              let result = uglify.minify(items.join(';\n'), { output: { 'max_line_len': 1000000 } })
+              return fs.writeFileAsync('./assets/js/ace/source-view.js', result.code)
+            }),
+            // Modes
+            fs.readdirAsync('./node_modules/brace/mode').then(modeList => {
+              return Promise.map(modeList, mdFile => {
+                return fs.readFileAsync(path.join('./node_modules/brace/mode', mdFile), 'utf8').then(modeCode => {
+                  console.info(colors.white('      mode-' + mdFile))
+                  let result = uglify.minify(modeCode, { output: { 'max_line_len': 1000000 } })
+                  return fs.writeFileAsync(path.join('./assets/js/ace', 'mode-' + mdFile), result.code)
+                })
+              }, { concurrency: 3 })
             })
-          })
+          )
         })
       } else {
         throw err
@@ -179,7 +194,7 @@ let globalTasks = Promise.mapSeries([
 const ALIASES = {
   'brace-ext-modelist': 'brace/ext/modelist.js',
   'simplemde': 'simplemde/dist/simplemde.min.js',
-  'socket.io-client': 'socket.io-client/dist/socket.io.js',
+  'socket-io-client': 'socket.io-client/dist/socket.io.js',
   'vue': (dev) ? 'vue/dist/vue.js' : 'vue/dist/vue.min.js'
 }
 const SHIMS = {
@@ -209,7 +224,7 @@ globalTasks.then(() => {
       ['.scss', fsbx.SassPlugin({ outputStyle: (dev) ? 'nested' : 'compressed' }), fsbx.CSSPlugin()],
       fsbx.BabelPlugin({ comments: false, presets: ['es2015'] }),
       fsbx.JSONPlugin(),
-      !dev && fsbx.UglifyJSPlugin({
+      !dev && fsbx.UglifyESPlugin({
         compress: { unused: false },
         output: { 'max_line_len': 1000000 }
       })
@@ -225,8 +240,8 @@ globalTasks.then(() => {
     })
   }
 
-  const bundleLibs = fuse.bundle('libs').instructions('~ index.js')
-  const bundleApp = fuse.bundle('app').instructions('!> index.js')
+  const bundleLibs = fuse.bundle('libs').instructions('~ index.js - brace')
+  const bundleApp = fuse.bundle('app').instructions('!> [index.js]')
   const bundleSetup = fuse.bundle('configure').instructions('> configure.js')
 
   switch (mode) {

+ 6 - 5
package.json

@@ -89,8 +89,8 @@
     "mime-types": "^2.1.15",
     "moment": "^2.18.1",
     "moment-timezone": "^0.5.13",
-    "mongodb": "^2.2.26",
-    "mongoose": "^4.10.0",
+    "mongodb": "^2.2.27",
+    "mongoose": "^4.10.1",
     "multer": "^1.3.0",
     "node-graceful": "^0.2.3",
     "ora": "^1.2.0",
@@ -126,7 +126,7 @@
   },
   "devDependencies": {
     "@glimpse/glimpse": "^0.20.9",
-    "@panter/vue-i18next": "^0.4.1",
+    "@panter/vue-i18next": "^0.5.0",
     "babel-cli": "latest",
     "babel-jest": "latest",
     "babel-preset-es2015": "latest",
@@ -147,6 +147,7 @@
     "jquery-simple-upload": "^1.0.0",
     "jquery-smooth-scroll": "^2.2.0",
     "jquery-sticky": "^1.0.4",
+    "lodash-es": "^4.17.4",
     "mathjax": "^2.7.1",
     "node-sass": "latest",
     "nodemon": "latest",
@@ -154,11 +155,11 @@
     "snyk": "latest",
     "twemoji-awesome": "^1.0.6",
     "typescript": "^2.3.2",
-    "uglify-js": "latest",
+    "uglify-es": "^3.0.10",
     "vee-validate": "^2.0.0-rc.3",
     "vue": "^2.3.3",
     "vue-clipboards": "^1.0.0",
-    "vue-resource": "^1.3.1",
+    "vue-resource": "^1.3.3",
     "vue-template-compiler": "^2.3.3",
     "vue-template-es2015-compiler": "^1.5.2",
     "vuex": "^2.3.1"

+ 2 - 1
server/views/pages/view.pug

@@ -31,7 +31,8 @@ block rootNavRight
 
 block content
 
-  #page-type-view.page-type-container(data-entrypath=pageData.meta.path)
+  //- #page-type-view.page-type-container(data-entrypath=pageData.meta.path)
+  content-view(inline-template)
     .container.is-fluid.has-mkcontent
       .columns.is-gapless
 

+ 6 - 9
server/views/pages/welcome.pug

@@ -2,13 +2,10 @@ extends ../layout.pug
 
 block rootNavCenter
 
-
 block content
-
-  #page-type-welcome
-    .container
-      .welcome
-        img(src='/images/logo.png', alt='Wiki.js')
-        h1= t('welcome.title')
-        h2= t('welcome.subtitle')
-        a.button.is-indigo(href='/create/home')= t('welcome.createhome')
+  .container
+    .welcome
+      img(src='/images/logo.png', alt='Wiki.js')
+      h1= t('welcome.title')
+      h2= t('welcome.subtitle')
+      a.button.is-indigo(href='/create/home')= t('welcome.createhome')

+ 36 - 17
yarn.lock

@@ -53,9 +53,9 @@
     "@glimpse/glimpse-server" "0.20.9"
     lodash "^4.15.0"
 
-"@panter/vue-i18next@^0.4.1":
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/@panter/vue-i18next/-/vue-i18next-0.4.1.tgz#6b06b783cd4d8f2c80255457d3fa0db6aff1091c"
+"@panter/vue-i18next@^0.5.0":
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/@panter/vue-i18next/-/vue-i18next-0.5.0.tgz#3a7928d8113b680ca81a1a899eb5aad34ba9c17a"
 
 abab@^1.0.3:
   version "1.0.3"
@@ -4005,6 +4005,10 @@ locate-path@^2.0.0:
     p-locate "^2.0.0"
     path-exists "^3.0.0"
 
+lodash-es@^4.17.4:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
+
 lodash._baseassign@^3.0.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e"
@@ -4457,7 +4461,14 @@ mongodb-core@2.1.10:
     bson "~1.0.4"
     require_optional "~1.0.0"
 
-mongodb@2.2.26, "mongodb@>= 1.2.0 <3.0.0", mongodb@^2.2.26:
+mongodb-core@2.1.11:
+  version "2.1.11"
+  resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.1.11.tgz#1c38776ceb174997a99c28860eed9028da9b3e1a"
+  dependencies:
+    bson "~1.0.4"
+    require_optional "~1.0.0"
+
+mongodb@2.2.26:
   version "2.2.26"
   resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.26.tgz#1bd50c557c277c98e1a05da38c9839c4922b034a"
   dependencies:
@@ -4465,9 +4476,17 @@ mongodb@2.2.26, "mongodb@>= 1.2.0 <3.0.0", mongodb@^2.2.26:
     mongodb-core "2.1.10"
     readable-stream "2.2.7"
 
-mongoose@*, mongoose@^4.10.0:
-  version "4.10.0"
-  resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-4.10.0.tgz#f4ff031f8b9e7105ae62b7cb3d4fc4e00f320b87"
+"mongodb@>= 1.2.0 <3.0.0", mongodb@^2.2.27:
+  version "2.2.27"
+  resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.27.tgz#34122034db66d983bcf6ab5adb26a24a70fef6e6"
+  dependencies:
+    es6-promise "3.2.1"
+    mongodb-core "2.1.11"
+    readable-stream "2.2.7"
+
+mongoose@*, mongoose@^4.10.1:
+  version "4.10.1"
+  resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-4.10.1.tgz#5982948c51d2174d27b782a89ea502a2a53c9db0"
   dependencies:
     async "2.1.4"
     bson "~1.0.4"
@@ -6782,6 +6801,13 @@ uc.micro@^1.0.1, uc.micro@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192"
 
+uglify-es@^3.0.10:
+  version "3.0.10"
+  resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.0.10.tgz#8fc9b86f2b57b2805e8863a6fcde1a92210cb885"
+  dependencies:
+    commander "~2.9.0"
+    source-map "~0.5.1"
+
 uglify-js@^2.6, uglify-js@^2.6.1:
   version "2.8.24"
   resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.24.tgz#48eb5175cf32e22ec11a47e638d7c8b4e0faf2dd"
@@ -6791,13 +6817,6 @@ uglify-js@^2.6, uglify-js@^2.6.1:
   optionalDependencies:
     uglify-to-browserify "~1.0.0"
 
-uglify-js@latest:
-  version "3.0.9"
-  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.9.tgz#974c5e638f5e2348f8509f0233667caedd52d813"
-  dependencies:
-    commander "~2.9.0"
-    source-map "~0.5.1"
-
 uglify-to-browserify@~1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
@@ -7024,9 +7043,9 @@ vue-clipboards@^1.0.0:
   dependencies:
     clipboard "^1.5.15"
 
-vue-resource@^1.3.1:
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-1.3.1.tgz#bf2f7b70bfe21b397c9d7607878f776a3acea2cf"
+vue-resource@^1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-1.3.3.tgz#6f12cfc77cccd47fb7e07aff6c42d75e34005992"
   dependencies:
     got "^6.7.1"