From 378ca2c217f94d3f31e2518116708092ee06f95c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=8A=B1=E8=A3=A4=E8=A1=A9?= <panfree23@gmail.com>
Date: Wed, 15 Aug 2018 15:33:34 +0800
Subject: [PATCH] update to webpack4 (#889)

---
 README.md                   |   3 +
 README.zh-CN.md             |   5 +-
 build/build.js              |  51 ++++++----
 build/check-versions.js     |  24 +++--
 build/utils.js              |  49 +++++----
 build/vue-loader.conf.js    |  19 +---
 build/webpack.base.conf.js  |  19 ++--
 build/webpack.dev.conf.js   |  36 ++++---
 build/webpack.prod.conf.js  | 193 +++++++++++++++++++-----------------
 config/index.js             |  16 ++-
 package.json                | 101 ++++++++++---------
 src/views/errorPage/404.vue |  16 +--
 12 files changed, 284 insertions(+), 248 deletions(-)

diff --git a/README.md b/README.md
index 7dfa567d..6c5048ba 100644
--- a/README.md
+++ b/README.md
@@ -151,6 +151,9 @@ npm run build:prod
 # --report to build with bundle size analytics
 npm run build:prod --report
 
+# --generate a bundle size analytics. default: bundle-report.html
+npm run build:prod --generate_report
+
 # --preview to start a server in local to preview
 npm run build:prod --preview
 
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 45f84e02..521cd21e 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -162,7 +162,10 @@ npm run build:prod
 ## 其它
 ```bash
 # --report to build with bundle size analytics
-npm run build:prod --report
+npm run build:prod
+
+# --generate a bundle size analytics. default: bundle-report.html
+npm run build:prod --generate_report
 
 # --preview to start a server in local to preview
 npm run build:prod --preview
diff --git a/build/build.js b/build/build.js
index fe24ac8f..34c71a55 100644
--- a/build/build.js
+++ b/build/build.js
@@ -8,10 +8,12 @@ const chalk = require('chalk')
 const webpack = require('webpack')
 const config = require('../config')
 const webpackConfig = require('./webpack.prod.conf')
-var connect = require('connect');
+var connect = require('connect')
 var serveStatic = require('serve-static')
 
-const spinner = ora('building for ' + process.env.env_config + ' environment...')
+const spinner = ora(
+  'building for ' + process.env.env_config + ' environment...'
+)
 spinner.start()
 
 rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
@@ -19,13 +21,15 @@ rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
   webpack(webpackConfig, (err, stats) => {
     spinner.stop()
     if (err) throw err
-    process.stdout.write(stats.toString({
-      colors: true,
-      modules: false,
-      children: false,
-      chunks: false,
-      chunkModules: false
-    }) + '\n\n')
+    process.stdout.write(
+      stats.toString({
+        colors: true,
+        modules: false,
+        children: false,
+        chunks: false,
+        chunkModules: false
+      }) + '\n\n'
+    )
 
     if (stats.hasErrors()) {
       console.log(chalk.red(' Build failed with errors.\n'))
@@ -33,24 +37,31 @@ rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
     }
 
     console.log(chalk.cyan(' Build complete.\n'))
-    console.log(chalk.yellow(
-      ' Tip: built files are meant to be served over an HTTP server.\n' +
-      ' Opening index.html over file:// won\'t work.\n'
-    ))
+    console.log(
+      chalk.yellow(
+        ' Tip: built files are meant to be served over an HTTP server.\n' +
+          " Opening index.html over file:// won't work.\n"
+      )
+    )
 
     if (process.env.npm_config_preview) {
       const port = 9526
-      const host = "http://localhost:" + port
+      const host = 'http://localhost:' + port
       const basePath = config.build.assetsPublicPath
       const app = connect()
 
-      app.use(basePath, serveStatic('./dist', {
-        'index': ['index.html', '/']
-      }))
+      app.use(
+        basePath,
+        serveStatic('./dist', {
+          index: ['index.html', '/']
+        })
+      )
 
-      app.listen(port, function () {
-        console.log(chalk.green(`> Listening at  http://localhost:${port}${basePath}`))
-      });
+      app.listen(port, function() {
+        console.log(
+          chalk.green(`> Listening at  http://localhost:${port}${basePath}`)
+        )
+      })
     }
   })
 })
diff --git a/build/check-versions.js b/build/check-versions.js
index 3ef972a0..c5c29e90 100644
--- a/build/check-versions.js
+++ b/build/check-versions.js
@@ -4,8 +4,11 @@ const semver = require('semver')
 const packageConfig = require('../package.json')
 const shell = require('shelljs')
 
-function exec (cmd) {
-  return require('child_process').execSync(cmd).toString().trim()
+function exec(cmd) {
+  return require('child_process')
+    .execSync(cmd)
+    .toString()
+    .trim()
 }
 
 const versionRequirements = [
@@ -24,23 +27,30 @@ if (shell.which('npm')) {
   })
 }
 
-module.exports = function () {
+module.exports = function() {
   const warnings = []
 
   for (let i = 0; i < versionRequirements.length; i++) {
     const mod = versionRequirements[i]
 
     if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
-      warnings.push(mod.name + ': ' +
-        chalk.red(mod.currentVersion) + ' should be ' +
-        chalk.green(mod.versionRequirement)
+      warnings.push(
+        mod.name +
+          ': ' +
+          chalk.red(mod.currentVersion) +
+          ' should be ' +
+          chalk.green(mod.versionRequirement)
       )
     }
   }
 
   if (warnings.length) {
     console.log('')
-    console.log(chalk.yellow('To use this template, you must update following to modules:'))
+    console.log(
+      chalk.yellow(
+        'To use this template, you must update following to modules:'
+      )
+    )
     console.log()
 
     for (let i = 0; i < warnings.length; i++) {
diff --git a/build/utils.js b/build/utils.js
index e534fb0f..c96d0936 100644
--- a/build/utils.js
+++ b/build/utils.js
@@ -1,18 +1,19 @@
 'use strict'
 const path = require('path')
 const config = require('../config')
-const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const MiniCssExtractPlugin = require('mini-css-extract-plugin')
 const packageConfig = require('../package.json')
 
-exports.assetsPath = function (_path) {
-  const assetsSubDirectory = process.env.NODE_ENV === 'production'
-    ? config.build.assetsSubDirectory
-    : config.dev.assetsSubDirectory
+exports.assetsPath = function(_path) {
+  const assetsSubDirectory =
+    process.env.NODE_ENV === 'production'
+      ? config.build.assetsSubDirectory
+      : config.dev.assetsSubDirectory
 
   return path.posix.join(assetsSubDirectory, _path)
 }
 
-exports.cssLoaders = function (options) {
+exports.cssLoaders = function(options) {
   options = options || {}
 
   const cssLoader = {
@@ -30,8 +31,22 @@ exports.cssLoaders = function (options) {
   }
 
   // generate loader string to be used with extract text plugin
-  function generateLoaders (loader, loaderOptions) {
-    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
+  function generateLoaders(loader, loaderOptions) {
+    const loaders = []
+
+    // Extract CSS when that option is specified
+    // (which is the case during production build)
+    if (options.extract) {
+      loaders.push(MiniCssExtractPlugin.loader)
+    } else {
+      loaders.push('vue-style-loader')
+    }
+
+    loaders.push(cssLoader)
+
+    if (options.usePostCSS) {
+      loaders.push(postcssLoader)
+    }
 
     if (loader) {
       loaders.push({
@@ -42,24 +57,16 @@ exports.cssLoaders = function (options) {
       })
     }
 
-    // Extract CSS when that option is specified
-    // (which is the case during production build)
-    if (options.extract) {
-      return ExtractTextPlugin.extract({
-        use: loaders,
-        fallback: 'vue-style-loader'
-      })
-    } else {
-      return ['vue-style-loader'].concat(loaders)
-    }
+    return loaders
   }
-
   // https://vue-loader.vuejs.org/en/configurations/extract-css.html
   return {
     css: generateLoaders(),
     postcss: generateLoaders(),
     less: generateLoaders('less'),
-    sass: generateLoaders('sass', { indentedSyntax: true }),
+    sass: generateLoaders('sass', {
+      indentedSyntax: true
+    }),
     scss: generateLoaders('sass'),
     stylus: generateLoaders('stylus'),
     styl: generateLoaders('stylus')
@@ -67,7 +74,7 @@ exports.cssLoaders = function (options) {
 }
 
 // Generate loaders for standalone style files (outside of .vue)
-exports.styleLoaders = function (options) {
+exports.styleLoaders = function(options) {
   const output = []
   const loaders = exports.cssLoaders(options)
 
diff --git a/build/vue-loader.conf.js b/build/vue-loader.conf.js
index 33ed58bc..5496c931 100644
--- a/build/vue-loader.conf.js
+++ b/build/vue-loader.conf.js
@@ -1,22 +1,5 @@
 'use strict'
-const utils = require('./utils')
-const config = require('../config')
-const isProduction = process.env.NODE_ENV === 'production'
-const sourceMapEnabled = isProduction
-  ? config.build.productionSourceMap
-  : config.dev.cssSourceMap
 
 module.exports = {
-  loaders: utils.cssLoaders({
-    sourceMap: sourceMapEnabled,
-    extract: isProduction
-  }),
-  cssSourceMap: sourceMapEnabled,
-  cacheBusting: config.dev.cacheBusting,
-  transformToRequire: {
-    video: ['src', 'poster'],
-    source: 'src',
-    img: 'src',
-    image: 'xlink:href'
-  }
+  //You can set the vue-loader configuration by yourself.
 }
diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js
index 9936a877..3b946b4b 100644
--- a/build/webpack.base.conf.js
+++ b/build/webpack.base.conf.js
@@ -2,9 +2,10 @@
 const path = require('path')
 const utils = require('./utils')
 const config = require('../config')
+const { VueLoaderPlugin } = require('vue-loader')
 const vueLoaderConfig = require('./vue-loader.conf')
 
-function resolve (dir) {
+function resolve(dir) {
   return path.join(__dirname, '..', dir)
 }
 
@@ -27,14 +28,15 @@ module.exports = {
   output: {
     path: config.build.assetsRoot,
     filename: '[name].js',
-    publicPath: process.env.NODE_ENV === 'production'
-      ? config.build.assetsPublicPath
-      : config.dev.assetsPublicPath
+    publicPath:
+      process.env.NODE_ENV === 'production'
+        ? config.build.assetsPublicPath
+        : config.dev.assetsPublicPath
   },
   resolve: {
     extensions: ['.js', '.vue', '.json'],
     alias: {
-      '@': resolve('src'),
+      '@': resolve('src')
     }
   },
   module: {
@@ -48,7 +50,11 @@ module.exports = {
       {
         test: /\.js$/,
         loader: 'babel-loader?cacheDirectory',
-        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
+        include: [
+          resolve('src'),
+          resolve('test'),
+          resolve('node_modules/webpack-dev-server/client')
+        ]
       },
       {
         test: /\.svg$/,
@@ -85,6 +91,7 @@ module.exports = {
       }
     ]
   },
+  plugins: [new VueLoaderPlugin()],
   node: {
     // prevent webpack from injecting useless setImmediate polyfill because Vue
     // source contains it (although only uses it if it's native).
diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js
index 43901e5b..5eba7eb3 100644
--- a/build/webpack.dev.conf.js
+++ b/build/webpack.dev.conf.js
@@ -9,7 +9,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
 const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
 const portfinder = require('portfinder')
 
-function resolve (dir) {
+function resolve(dir) {
   return path.join(__dirname, '..', dir)
 }
 
@@ -17,8 +17,12 @@ const HOST = process.env.HOST
 const PORT = process.env.PORT && Number(process.env.PORT)
 
 const devWebpackConfig = merge(baseWebpackConfig, {
+  mode: 'development',
   module: {
-    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
+    rules: utils.styleLoaders({
+      sourceMap: config.dev.cssSourceMap,
+      usePostCSS: true
+    })
   },
   // cheap-module-eval-source-map is faster for development
   devtool: config.dev.devtool,
@@ -39,7 +43,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
     proxy: config.dev.proxyTable,
     quiet: true, // necessary for FriendlyErrorsPlugin
     watchOptions: {
-      poll: config.dev.poll,
+      poll: config.dev.poll
     }
   },
   plugins: [
@@ -47,8 +51,6 @@ const devWebpackConfig = merge(baseWebpackConfig, {
       'process.env': require('../config/dev.env')
     }),
     new webpack.HotModuleReplacementPlugin(),
-    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
-    new webpack.NoEmitOnErrorsPlugin(),
     // https://github.com/ampedandwired/html-webpack-plugin
     new HtmlWebpackPlugin({
       filename: 'index.html',
@@ -57,7 +59,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
       favicon: resolve('favicon.ico'),
       title: 'vue-element-admin',
       path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
-    }),
+    })
   ]
 })
 
@@ -73,14 +75,20 @@ module.exports = new Promise((resolve, reject) => {
       devWebpackConfig.devServer.port = port
 
       // Add FriendlyErrorsPlugin
-      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
-        compilationSuccessInfo: {
-          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
-        },
-        onErrors: config.dev.notifyOnErrors
-        ? utils.createNotifierCallback()
-        : undefined
-      }))
+      devWebpackConfig.plugins.push(
+        new FriendlyErrorsPlugin({
+          compilationSuccessInfo: {
+            messages: [
+              `Your application is running here: http://${
+                devWebpackConfig.devServer.host
+              }:${port}`
+            ]
+          },
+          onErrors: config.dev.notifyOnErrors
+            ? utils.createNotifierCallback()
+            : undefined
+        })
+      )
 
       resolve(devWebpackConfig)
     }
diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js
index 7f710543..6220cc6b 100644
--- a/build/webpack.prod.conf.js
+++ b/build/webpack.prod.conf.js
@@ -7,17 +7,23 @@ const merge = require('webpack-merge')
 const baseWebpackConfig = require('./webpack.base.conf')
 const CopyWebpackPlugin = require('copy-webpack-plugin')
 const HtmlWebpackPlugin = require('html-webpack-plugin')
-const ExtractTextPlugin = require('extract-text-webpack-plugin')
-const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
+const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
+const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
 const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
 
-function resolve (dir) {
+function resolve(dir) {
   return path.join(__dirname, '..', dir)
 }
 
-const env = require('../config/'+process.env.env_config+'.env')
+const env = require('../config/' + process.env.env_config + '.env')
+
+// For NamedChunksPlugin
+const seen = new Set()
+const nameLength = 4
 
 const webpackConfig = merge(baseWebpackConfig, {
+  mode: 'production',
   module: {
     rules: utils.styleLoaders({
       sourceMap: config.build.productionSourceMap,
@@ -28,37 +34,18 @@ const webpackConfig = merge(baseWebpackConfig, {
   devtool: config.build.productionSourceMap ? config.build.devtool : false,
   output: {
     path: config.build.assetsRoot,
-    filename: utils.assetsPath('js/[name].[chunkhash].js'),
-    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+    filename: utils.assetsPath('js/[name].[chunkhash:8].js'),
+    chunkFilename: utils.assetsPath('js/[name].[chunkhash:8].js')
   },
   plugins: [
     // http://vuejs.github.io/vue-loader/en/workflow/production.html
     new webpack.DefinePlugin({
       'process.env': env
     }),
-    new UglifyJsPlugin({
-      uglifyOptions: {
-        compress: {
-          warnings: false
-        }
-      },
-      sourceMap: config.build.productionSourceMap,
-      parallel: true
-    }),
     // extract css into its own file
-    new ExtractTextPlugin({
-      filename: utils.assetsPath('css/[name].[contenthash].css'),
-      // Setting the following option to `false` will not extract CSS from codesplit chunks.
-      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
-      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
-      allChunks: false,
-    }),
-    // Compress extracted CSS. We are using this plugin so that possible
-    // duplicated CSS from different components can be deduped.
-    new OptimizeCSSPlugin({
-      cssProcessorOptions: config.build.productionSourceMap
-        ? { safe: true, map: { inline: false } }
-        : { safe: true }
+    new MiniCssExtractPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash:8].css'),
+      chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
     }),
     // generate dist index.html with correct asset hash for caching.
     // you can customize output by editing /index.html
@@ -76,68 +63,34 @@ const webpackConfig = merge(baseWebpackConfig, {
         removeAttributeQuotes: true
         // more options:
         // https://github.com/kangax/html-minifier#options-quick-reference
-      },
-      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
-      chunksSortMode: 'dependency'
-    }),
-    // keep module.id stable when vender modules does not change
-    new webpack.HashedModuleIdsPlugin(),
-    // enable scope hoisting
-    new webpack.optimize.ModuleConcatenationPlugin(),
-    // split vendor js into its own file
-    new webpack.optimize.CommonsChunkPlugin({
-      name: 'vendor',
-      minChunks (module) {
-        // any required modules inside node_modules are extracted to vendor
-        return (
-          module.resource &&
-          /\.js$/.test(module.resource) &&
-          module.resource.indexOf(
-            path.join(__dirname, '../node_modules')
-          ) === 0
-        )
       }
+      // default sort mode uses toposort which cannot handle cyclic deps
+      // in certain cases, and in webpack 4, chunk order in HTML doesn't
+      // matter anyway
     }),
-    // extract webpack runtime and module manifest to its own file in order to
-    // prevent vendor hash from being updated whenever app bundle is updated
-    new webpack.optimize.CommonsChunkPlugin({
-      name: 'manifest',
-      minChunks: Infinity
+    new ScriptExtHtmlWebpackPlugin({
+      //`runtime` must same as runtimeChunk name. default is `runtime`
+      inline: /runtime\..*\.js$/
     }),
-    // This instance extracts shared chunks from code splitted chunks and bundles them
-    // in a separate chunk, similar to the vendor chunk
-    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
-    new webpack.optimize.CommonsChunkPlugin({
-      name: 'app',
-      async: 'vendor-async',
-      children: true,
-      minChunks: 3
-    }),
-    // split echarts into its own file
-    new webpack.optimize.CommonsChunkPlugin({
-      async: 'echarts',
-      minChunks(module) {
-        var context = module.context;
-        return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
+    // keep chunk.id stable when chunk has no name
+    new webpack.NamedChunksPlugin(chunk => {
+      if (chunk.name) {
+        return chunk.name
       }
-    }),
-    // split xlsx into its own file
-    new webpack.optimize.CommonsChunkPlugin({
-      async: 'xlsx',
-      minChunks(module) {
-        var context = module.context;
-        return context && (context.indexOf('xlsx') >= 0);
+      const modules = Array.from(chunk.modulesIterable)
+      if (modules.length > 1) {
+        const hash = require('hash-sum')
+        const joinedHash = hash(modules.map(m => m.id).join('_'))
+        let len = nameLength
+        while (seen.has(joinedHash.substr(0, len))) len++
+        seen.add(joinedHash.substr(0, len))
+        return `chunk-${joinedHash.substr(0, len)}`
+      } else {
+        return modules[0].id
       }
     }),
-     // split codemirror into its own file
-     new webpack.optimize.CommonsChunkPlugin({
-      async: 'codemirror',
-      minChunks(module) {
-        var context = module.context;
-        return context && (context.indexOf('codemirror') >= 0);
-      }
-    }),
-
+    // keep module.id stable when vender modules does not change
+    new webpack.HashedModuleIdsPlugin(),
     // copy custom static assets
     new CopyWebpackPlugin([
       {
@@ -146,7 +99,48 @@ const webpackConfig = merge(baseWebpackConfig, {
         ignore: ['.*']
       }
     ])
-  ]
+  ],
+  optimization: {
+    splitChunks: {
+      chunks: 'all',
+      cacheGroups: {
+        libs: {
+          name: 'chunk-libs',
+          test: /[\\/]node_modules[\\/]/,
+          priority: 10,
+          chunks: 'initial' // 只打包初始时依赖的第三方
+        },
+        elementUI: {
+          name: 'chunk-elementUI', // 单独将 elementUI 拆包
+          priority: 20, // 权重要大于 libs 和 app 不然会被打包进 libs 或者 app
+          test: /[\\/]node_modules[\\/]element-ui[\\/]/
+        },
+        commons: {
+          name: 'chunk-comomns',
+          test: resolve('src/components'), // 可自定义拓展你的规则
+          minChunks: 3, // 最小公用次数
+          priority: 5,
+          reuseExistingChunk: true
+        }
+      }
+    },
+    runtimeChunk: 'single',
+    minimizer: [
+      new UglifyJsPlugin({
+        uglifyOptions: {
+          mangle: {
+            safari10: true
+          }
+        },
+        sourceMap: config.build.productionSourceMap,
+        cache: true,
+        parallel: true
+      }),
+      // Compress extracted CSS. We are using this plugin so that possible
+      // duplicated CSS from different components can be deduped.
+      new OptimizeCSSAssetsPlugin()
+    ]
+  }
 })
 
 if (config.build.productionGzip) {
@@ -157,9 +151,7 @@ if (config.build.productionGzip) {
       asset: '[path].gz[query]',
       algorithm: 'gzip',
       test: new RegExp(
-        '\\.(' +
-        config.build.productionGzipExtensions.join('|') +
-        ')$'
+        '\\.(' + config.build.productionGzipExtensions.join('|') + ')$'
       ),
       threshold: 10240,
       minRatio: 0.8
@@ -167,9 +159,28 @@ if (config.build.productionGzip) {
   )
 }
 
-if (config.build.bundleAnalyzerReport) {
-  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
-  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+if (config.build.generateAnalyzerReport || config.build.bundleAnalyzerReport) {
+  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
+    .BundleAnalyzerPlugin
+
+  if (config.build.bundleAnalyzerReport) {
+    webpackConfig.plugins.push(
+      new BundleAnalyzerPlugin({
+        analyzerPort: 8080,
+        generateStatsFile: false
+      })
+    )
+  }
+
+  if (config.build.generateAnalyzerReport) {
+    webpackConfig.plugins.push(
+      new BundleAnalyzerPlugin({
+        analyzerMode: 'static',
+        reportFilename: 'bundle-report.html',
+        openAnalyzer: false
+      })
+    )
+  }
 }
 
 module.exports = webpackConfig
diff --git a/config/index.js b/config/index.js
index 92c4a172..d8b17921 100644
--- a/config/index.js
+++ b/config/index.js
@@ -36,12 +36,7 @@ module.exports = {
      */
 
     // https://webpack.js.org/configuration/devtool/#development
-    devtool: '#cheap-source-map',
-
-    // If you have problems debugging vue-files in devtools,
-    // set this to false - it *may* help
-    // https://vue-loader.vuejs.org/en/options.html#cachebusting
-    cacheBusting: true,
+    devtool: 'cheap-source-map',
 
     // CSS Sourcemaps off by default because relative paths are "buggy"
     // with this option, according to the CSS-Loader README
@@ -73,7 +68,7 @@ module.exports = {
      */
     productionSourceMap: false,
     // https://webpack.js.org/configuration/devtool/#production
-    devtool: '#source-map',
+    devtool: 'source-map',
 
     // Gzip off by default as many popular static hosts such as
     // Surge or Netlify already gzip all static assets for you.
@@ -84,8 +79,11 @@ module.exports = {
 
     // Run the build command with an extra argument to
     // View the bundle analyzer report after build finishes:
-    // `npm run build --report`
+    // `npm run build:prod --report`
     // Set to `true` or `false` to always turn it on or off
-    bundleAnalyzerReport: process.env.npm_config_report
+    bundleAnalyzerReport: process.env.npm_config_report || false,
+
+      // `npm run build:prod --generate_report`
+    generateAnalyzerReport: process.env.npm_config_generate_report || false
   }
 }
diff --git a/package.json b/package.json
index e8ee8955..fbb1a766 100644
--- a/package.json
+++ b/package.json
@@ -33,15 +33,15 @@
     "url": "https://github.com/PanJiaChen/vue-element-admin/issues"
   },
   "dependencies": {
-    "axios": "0.17.1",
+    "axios": "0.18.0",
     "clipboard": "1.7.1",
-    "codemirror": "5.32.0",
+    "codemirror": "5.39.2",
     "connect": "3.6.6",
     "driver.js": "0.5.2",
     "dropzone": "5.2.0",
-    "echarts": "3.8.5",
-    "element-ui": "2.3.2",
-    "file-saver": "1.3.3",
+    "echarts": "4.1.0",
+    "element-ui": "2.4.6",
+    "file-saver": "1.3.8",
     "font-awesome": "4.7.0",
     "js-cookie": "2.2.0",
     "jsonlint": "1.6.3",
@@ -50,14 +50,13 @@
     "normalize.css": "7.0.0",
     "nprogress": "0.2.0",
     "screenfull": "3.3.2",
-    "serve-static": "1.13.2",
-    "showdown": "1.8.5",
+    "showdown": "1.8.6",
     "simplemde": "1.11.2",
     "sortablejs": "1.7.0",
-    "vue": "2.5.10",
+    "vue": "2.5.17",
     "vue-count-to": "1.0.13",
     "vue-i18n": "7.3.2",
-    "vue-multiselect": "2.0.8",
+    "vue-multiselect": "2.1.0",
     "vue-router": "3.0.1",
     "vue-splitpane": "1.0.2",
     "vuedraggable": "^2.16.0",
@@ -65,57 +64,61 @@
     "xlsx": "^0.11.16"
   },
   "devDependencies": {
-    "autoprefixer": "7.2.3",
-    "babel-core": "6.26.0",
-    "babel-eslint": "8.0.3",
+    "autoprefixer": "8.5.0",
+    "babel-core": "6.26.3",
+    "babel-eslint": "8.2.6",
     "babel-helper-vue-jsx-merge-props": "2.0.3",
-    "babel-loader": "7.1.2",
-    "babel-plugin-dynamic-import-node": "^1.2.0",
+    "babel-loader": "7.1.5",
+    "babel-plugin-dynamic-import-node": "2.0.0",
     "babel-plugin-syntax-jsx": "6.18.0",
     "babel-plugin-transform-runtime": "6.23.0",
-    "babel-plugin-transform-vue-jsx": "3.5.0",
-    "babel-preset-env": "1.6.1",
+    "babel-plugin-transform-vue-jsx": "3.7.0",
+    "babel-preset-env": "1.7.0",
     "babel-preset-stage-2": "6.24.1",
-    "chalk": "2.3.0",
-    "copy-webpack-plugin": "4.3.0",
-    "cross-env": "5.1.1",
-    "css-loader": "0.28.7",
-    "eslint": "4.13.1",
-    "eslint-friendly-formatter": "3.0.0",
-    "eslint-loader": "1.9.0",
-    "eslint-plugin-html": "4.0.1",
-    "extract-text-webpack-plugin": "3.0.2",
-    "file-loader": "1.1.5",
-    "friendly-errors-webpack-plugin": "1.6.1",
-    "html-webpack-plugin": "2.30.1",
+    "chalk": "2.4.1",
+    "copy-webpack-plugin": "4.5.2",
+    "cross-env": "5.2.0",
+    "css-loader": "1.0.0",
+    "eslint": "4.19.1",
+    "eslint-friendly-formatter": "4.0.1",
+    "eslint-loader": "2.0.0",
+    "eslint-plugin-html": "4.0.5",
+    "file-loader": "1.1.11",
+    "friendly-errors-webpack-plugin": "1.7.0",
+    "hash-sum": "^1.0.2",
+    "html-webpack-plugin": "^4.0.0-alpha",
     "husky": "0.14.3",
-    "lint-staged": "7.2.0",
-    "node-notifier": "5.1.2",
+    "lint-staged": "7.2.2",
+    "mini-css-extract-plugin": "0.4.1",
+    "node-notifier": "5.2.1",
     "node-sass": "^4.7.2",
-    "optimize-css-assets-webpack-plugin": "3.2.0",
-    "ora": "1.3.0",
+    "optimize-css-assets-webpack-plugin": "5.0.0",
+    "ora": "3.0.0",
     "portfinder": "1.0.13",
-    "postcss-import": "11.0.0",
-    "postcss-loader": "2.0.9",
-    "postcss-url": "7.3.0",
+    "postcss-import": "11.1.0",
+    "postcss-loader": "2.1.6",
+    "postcss-url": "7.3.2",
     "rimraf": "2.6.2",
-    "sass-loader": "6.0.6",
+    "sass-loader": "7.0.3",
+    "script-ext-html-webpack-plugin": "2.0.1",
     "script-loader": "0.7.2",
-    "semver": "5.4.1",
-    "shelljs": "0.7.8",
-    "svg-sprite-loader": "3.5.2",
-    "uglifyjs-webpack-plugin": "1.1.3",
-    "url-loader": "0.6.2",
-    "vue-loader": "13.7.2",
-    "vue-style-loader": "3.0.3",
-    "vue-template-compiler": "2.5.10",
-    "webpack": "3.10.0",
-    "webpack-bundle-analyzer": "2.9.1",
-    "webpack-dev-server": "2.9.7",
-    "webpack-merge": "4.1.1"
+    "semver": "5.5.0",
+    "serve-static": "1.13.2",
+    "shelljs": "0.8.2",
+    "svg-sprite-loader": "3.8.0",
+    "uglifyjs-webpack-plugin": "1.2.7",
+    "url-loader": "1.0.1",
+    "vue-loader": "15.3.0",
+    "vue-style-loader": "4.1.2",
+    "vue-template-compiler": "2.5.17",
+    "webpack": "4.16.5",
+    "webpack-bundle-analyzer": "2.13.1",
+    "webpack-cli": "3.1.0",
+    "webpack-dev-server": "3.1.5",
+    "webpack-merge": "4.1.4"
   },
   "engines": {
-    "node": ">= 4.0.0",
+    "node": ">= 6.0.0",
     "npm": ">= 3.0.0"
   },
   "browserslist": [
diff --git a/src/views/errorPage/404.vue b/src/views/errorPage/404.vue
index dccf5736..97e57b2f 100644
--- a/src/views/errorPage/404.vue
+++ b/src/views/errorPage/404.vue
@@ -2,10 +2,10 @@
   <div class="wscn-http404-container">
     <div class="wscn-http404">
       <div class="pic-404">
-        <img class="pic-404__parent" :src="img_404" alt="404">
-        <img class="pic-404__child left" :src="img_404_cloud" alt="404">
-        <img class="pic-404__child mid" :src="img_404_cloud" alt="404">
-        <img class="pic-404__child right" :src="img_404_cloud" alt="404">
+        <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
+        <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
+        <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
+        <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
       </div>
       <div class="bullshit">
         <div class="bullshit__oops">OOPS!</div>
@@ -21,17 +21,9 @@
 </template>
 
 <script>
-import img_404 from '@/assets/404_images/404.png'
-import img_404_cloud from '@/assets/404_images/404_cloud.png'
 
 export default {
   name: 'page404',
-  data() {
-    return {
-      img_404,
-      img_404_cloud
-    }
-  },
   computed: {
     message() {
       return '网管说这个页面你不能进......'
-- 
GitLab