From 63902907b54233ad537c750ea9319963df3cc60e Mon Sep 17 00:00:00 2001 From: NGPixel Date: Sat, 27 Jan 2018 21:40:51 -0500 Subject: [PATCH] refactor: dev optimizations --- client/js/app.js | 3 +- dev/webpack/webpack.common.js | 13 +++++- dev/webpack/webpack.dev.js | 1 - dev/webpack/webpack.prod.js | 4 +- package.json | 72 +++++++++++++++++----------------- server/setup.js | 14 +++++++ server/views/master.pug | 2 +- server/views/setup.pug | 2 +- yarn.lock | Bin 396289 -> 401114 bytes 9 files changed, 68 insertions(+), 43 deletions(-) diff --git a/client/js/app.js b/client/js/app.js index 213397e2..283c7f67 100644 --- a/client/js/app.js +++ b/client/js/app.js @@ -56,7 +56,6 @@ import adminEditUserComponent from './pages/admin-edit-user.component.js' import adminProfileComponent from './pages/admin-profile.component.js' import adminSettingsComponent from './pages/admin-settings.component.js' import adminThemeComponent from './pages/admin-theme.component.js' -import setupComponent from './components/setup.component.js' import contentViewComponent from './pages/content-view.component.js' import editorComponent from './components/editor.component.js' import sourceViewComponent from './pages/source-view.component.js' @@ -130,7 +129,7 @@ Vue.component('modalUpgradeSystem', modalUpgradeSystemComponent) Vue.component('navigator', navigatorComponent) Vue.component('pageLoader', pageLoaderComponent) Vue.component('search', searchComponent) -Vue.component('setup', setupComponent) +Vue.component('setup', () => import(/* webpackChunkName: "setup" */ './components/setup.component.js')) Vue.component('sourceView', sourceViewComponent) Vue.component('toggle', toggleComponent) Vue.component('tree', treeComponent) diff --git a/dev/webpack/webpack.common.js b/dev/webpack/webpack.common.js index d032c376..3ed861f5 100644 --- a/dev/webpack/webpack.common.js +++ b/dev/webpack/webpack.common.js @@ -5,6 +5,7 @@ const webpack = require('webpack') const CopyWebpackPlugin = require('copy-webpack-plugin') const ProgressBarPlugin = require('progress-bar-webpack-plugin') const ExtractTextPlugin = require('extract-text-webpack-plugin') +const NameAllModulesPlugin = require('name-all-modules-plugin') const babelConfig = fs.readJsonSync(path.join(process.cwd(), '.babelrc')) const postCSSConfig = { @@ -182,6 +183,13 @@ module.exports = { { from: 'client/static' } ], { + }), + new webpack.NamedModulesPlugin(), + new webpack.NamedChunksPlugin((chunk) => { + if (chunk.name) { + return chunk.name + } + return chunk.modules.map(m => path.relative(m.context, m.request)).join('_') }), new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', @@ -190,9 +198,10 @@ module.exports = { } }), new webpack.optimize.CommonsChunkPlugin({ - name: 'manifest', + name: 'runtime', minChunks: Infinity - }) + }), + new NameAllModulesPlugin() ], resolve: { symlinks: true, diff --git a/dev/webpack/webpack.dev.js b/dev/webpack/webpack.dev.js index 0300a57f..dfef1a18 100644 --- a/dev/webpack/webpack.dev.js +++ b/dev/webpack/webpack.dev.js @@ -1,6 +1,5 @@ const webpack = require('webpack') const merge = require('webpack-merge') -const path = require('path') const ExtractTextPlugin = require('extract-text-webpack-plugin') diff --git a/dev/webpack/webpack.prod.js b/dev/webpack/webpack.prod.js index 6d7ad0a1..e02738d5 100644 --- a/dev/webpack/webpack.prod.js +++ b/dev/webpack/webpack.prod.js @@ -4,6 +4,7 @@ const merge = require('webpack-merge') const CleanWebpackPlugin = require('clean-webpack-plugin') const UglifyJSPlugin = require('uglifyjs-webpack-plugin') const ExtractTextPlugin = require('extract-text-webpack-plugin') +const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin') const common = require('./webpack.common.js') @@ -19,6 +20,7 @@ module.exports = merge(common, { new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }), - new ExtractTextPlugin('css/bundle.css') + new ExtractTextPlugin('css/bundle.css'), + new DuplicatePackageCheckerPlugin() ] }) diff --git a/package.json b/package.json index 353a9302..ff9300cd 100644 --- a/package.json +++ b/package.json @@ -43,32 +43,32 @@ "bcryptjs-then": "1.0.1", "bluebird": "3.5.1", "body-parser": "1.18.2", - "bugsnag": "2.0.1", - "bull": "3.3.7", + "bugsnag": "2.1.3", + "bull": "3.3.8", "bunyan": "1.8.12", "cheerio": "1.0.0-rc.2", "child-process-promise": "2.2.1", - "chokidar": "1.7.0", + "chokidar": "2.0.0", "compression": "1.7.1", "connect-flash": "0.1.1", - "connect-redis": "3.3.2", + "connect-redis": "3.3.3", "cookie-parser": "1.4.3", - "diff2html": "2.3.2", + "diff2html": "2.3.3", "dotize": "^0.2.0", - "execa": "0.8.0", + "execa": "0.9.0", "express": "4.16.2", "express-brute": "1.0.1", "express-brute-redis": "0.0.1", "express-session": "1.15.6", - "file-type": "7.4.0", + "file-type": "7.5.0", "filesize.js": "1.0.2", - "follow-redirects": "1.2.6", + "follow-redirects": "1.4.1", "fs-extra": "5.0.0", "git-wrapper2-promise": "0.2.9", "graphql": "0.12.3", - "graphql-tools": "2.14.1", + "graphql-tools": "2.19.0", "highlight.js": "9.12.0", - "i18next": "10.2.1", + "i18next": "10.3.0", "i18next-express-middleware": "1.0.9", "i18next-localstorage-cache": "1.1.1", "i18next-node-fs-backend": "1.0.0", @@ -76,24 +76,24 @@ "ioredis": "3.2.2", "jimp": "0.2.28", "js-yaml": "3.10.0", - "jsonwebtoken": "8.1.0", + "jsonwebtoken": "8.1.1", "klaw": "2.1.1", "lodash": "4.17.4", "markdown-it": "8.4.0", "markdown-it-abbr": "1.0.4", "markdown-it-anchor": "4.0.0", - "markdown-it-attrs": "1.2.0", + "markdown-it-attrs": "1.2.1", "markdown-it-emoji": "1.4.0", "markdown-it-expand-tabs": "1.0.12", "markdown-it-external-links": "0.0.6", "markdown-it-footnote": "3.0.1", "markdown-it-mathjax": "2.0.0", "markdown-it-task-lists": "2.1.0", - "mathjax-node": "1.2.1", + "mathjax-node": "1.3.0", "mime-types": "2.1.17", "moment": "2.20.1", "moment-timezone": "0.5.14", - "mongodb": "3.0.0-rc0", + "mongodb": "3.0.1", "multer": "1.3.0", "node-2fa": "1.1.2", "node-graceful": "0.2.3", @@ -114,67 +114,69 @@ "passport-windowslive": "1.0.2", "pg": "6.4.2", "pg-hstore": "2.3.2", - "pg-promise": "7.3.2", - "pm2": "2.9.1", + "pg-promise": "7.4.1", + "pm2": "2.9.3", "pug": "2.0.0-rc.4", "qr-image": "3.2.0", "read-chunk": "2.1.0", "remove-markdown": "0.2.2", "request": "2.83.0", "request-promise": "4.2.2", - "semver": "5.4.1", - "sequelize": "4.28.6", + "semver": "5.5.0", + "sequelize": "4.32.2", "serve-favicon": "2.4.5", "simplemde": "1.11.2", "stream-to-promise": "2.2.0", - "tar": "4.2.0", + "tar": "4.3.0", "through2": "2.0.3", - "uuid": "3.1.0", - "validator": "9.2.0", + "uuid": "3.2.1", + "validator": "9.3.0", "validator-as-promised": "1.0.2", "winston": "2.4.0", - "yargs": "10.0.3" + "yargs": "11.0.0" }, "devDependencies": { "@glimpse/glimpse": "0.22.15", "@panter/vue-i18next": "0.9.1", - "apollo-client-preset": "1.0.5", - "autoprefixer": "7.2.3", + "apollo-client-preset": "1.0.6", + "autoprefixer": "7.2.5", "babel-cli": "6.26.0", "babel-core": "6.26.0", "babel-eslint": "8.2.1", - "babel-jest": "22.0.4", + "babel-jest": "22.1.0", "babel-loader": "7.1.2", "babel-preset-env": "1.6.1", "babel-preset-es2015": "6.24.1", "babel-preset-stage-2": "6.24.1", "brace": "0.11.0", "cache-loader": "1.2.0", - "clean-webpack-plugin": "0.1.17", + "clean-webpack-plugin": "0.1.18", "colors": "1.1.2", "consolidate": "0.15.0", "copy-webpack-plugin": "4.3.1", "css-loader": "0.28.9", "cssnano": "4.0.0-rc.2", - "eslint": "4.13.1", + "duplicate-package-checker-webpack-plugin": "2.1.0", + "eslint": "4.16.0", "eslint-config-requarks": "1.0.7", "eslint-config-standard": "11.0.0-beta.0", "eslint-plugin-import": "2.8.0", "eslint-plugin-node": "5.2.1", "eslint-plugin-promise": "3.6.0", "eslint-plugin-standard": "3.0.1", - "eslint-plugin-vue": "3.13.1", + "eslint-plugin-vue": "4.2.0", "extract-text-webpack-plugin": "3.0.2", "file-loader": "1.1.6", "graphql-tag": "^2.6.1", - "i18next-xhr-backend": "1.5.0", + "i18next-xhr-backend": "1.5.1", "intl": "1.2.5", - "jest": "22.0.4", + "jest": "22.1.4", "jest-junit": "3.4.1", "js-cookie": "2.2.0", + "name-all-modules-plugin": "1.0.1", "node-dev": "3.1.3", "node-sass": "4.7.2", - "nodemon": "1.14.3", + "nodemon": "1.14.11", "postcss-loader": "2.0.10", "postcss-selector-parser": "3.1.1", "progress-bar-webpack-plugin": "1.10.0", @@ -182,15 +184,15 @@ "raw-loader": "0.5.1", "sass-loader": "6.0.6", "sass-resources-loader": "1.3.1", - "style-loader": "0.19.1", + "style-loader": "0.20.1", "svg-sprite-loader": "3.6.2", "twemoji-awesome": "1.0.6", "typescript": "2.6.2", - "uglify-es": "3.2.2", + "uglify-es": "3.3.9", "uglifyjs-webpack-plugin": "1.1.6", - "vee-validate": "2.0.0-rc.27", + "vee-validate": "2.0.3", "vue": "2.5.13", - "vue-clipboards": "1.2.0", + "vue-clipboards": "1.2.1", "vue-hot-reload-api": "2.2.4", "vue-loader": "13.7.0", "vue-lodash": "1.0.4", diff --git a/server/setup.js b/server/setup.js index 5f270fcf..520dbb55 100644 --- a/server/setup.js +++ b/server/setup.js @@ -57,6 +57,20 @@ module.exports = () => { app.locals.data = wiki.data app.locals._ = require('lodash') + // ---------------------------------------- + // HMR (Dev Mode Only) + // ---------------------------------------- + + if (global.DEV) { + const webpackDevMiddleware = require('webpack-dev-middleware') + const webpackHotMiddleware = require('webpack-hot-middleware') + app.use(webpackDevMiddleware(global.WP, { + publicPath: global.WPCONFIG.output.publicPath, + logger: wiki.logger + })) + app.use(webpackHotMiddleware(global.WP)) + } + // ---------------------------------------- // Controllers // ---------------------------------------- diff --git a/server/views/master.pug b/server/views/master.pug index 57c95d6d..d3a51274 100644 --- a/server/views/master.pug +++ b/server/views/master.pug @@ -25,7 +25,7 @@ html link(type='text/css', rel='stylesheet', href=config.site.path + 'css/bundle.css') //- JS - script(type='text/javascript', src=config.site.path + 'js/manifest.js') + script(type='text/javascript', src=config.site.path + 'js/runtime.js') script(type='text/javascript', src=config.site.path + 'js/vendor.js') script(type='text/javascript', src=config.site.path + 'js/client.js') diff --git a/server/views/setup.pug b/server/views/setup.pug index be342a19..e05c2bcd 100644 --- a/server/views/setup.pug +++ b/server/views/setup.pug @@ -274,7 +274,7 @@ block body i(v-if='loading') .panel-content.is-text .is-logo - svg.icons.is-64: use(xlink:href='#nc-man') + svg.icons.is-64: use(xlink:href='#nc-man-black') h4 Administrator Account p A root administrator account will be created for local authentication. From this account, you can create or authorize more users. .panel-content.form-sections diff --git a/yarn.lock b/yarn.lock index 8efce0b273e8db059079dbc3def055cdff6e923d..25e6de33c5e516ffbd0a526fe80b0664ab725f68 100644 GIT binary patch delta 11290 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