feat: perfect migrate to @vue/cli-service, upgrade vue babel version (#1267)
* feat: perfect migrate to @vue/cli-service, upgrade vue babel version 1. update to @vue/cli-service@3.0.5, @babel/core@7.0.0 2. use vue-cli service replace config file in build/ and config/ 3. upgrade vue and babel configuration 4. solve the svg-sprite config problem #980 refs: #932 #1087 #980 #1056 * fix: fix breadcrumb dependency * fix: fix index template and static assets load with vue-cli 3 * fix: fix import driver.js in guide page * refactor(mock): mak mock api compatible with both web-view and webpack server 1. 把 Mockjs 功能移到 server 端中间件,同时也兼容前端直接劫持 XHR 2. dev 环境下默认作为 express 中间件通过 webpack server 提供 mock api 3. prod 构建时,默认在前端用 Mockjs 劫持 XHR benefits: - dev 开发调试时能直接看到 XHR 请求,方便调试网络,能和后端对接联调 - 避开在开发时因为 Mockjs 引起的网络 bug - prod 构建时劫持 XHR,保证本项目的 Github Pages preview 能正常显示 (逻辑和 error-log 一样) - 前后台使用的 mock 是同一份代码,不会增加维护负担 ref: [#562](https://github.com/PanJiaChen/vue-element-admin/issues/562#issuecomment-378116233) * update requires the lowest version of node * add favicon * fix(TreeTable): fix `Array.prototype.concat` on custom-tree-table page
							
								
								
									
										17
									
								
								.babelrc
									
									
									
									
									
								
							
							
						
						| @@ -1,17 +0,0 @@ | |||||||
| { |  | ||||||
|   "presets": [ |  | ||||||
|     ["env", { |  | ||||||
|       "modules": false, |  | ||||||
|       "targets": { |  | ||||||
|         "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] |  | ||||||
|       } |  | ||||||
|     }], |  | ||||||
|     "stage-2" |  | ||||||
|   ], |  | ||||||
|   "plugins": ["transform-vue-jsx", "transform-runtime"], |  | ||||||
|   "env": { |  | ||||||
|     "development":{ |  | ||||||
|       "plugins": ["dynamic-import-node"] |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										1
									
								
								.env.development
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | VUE_APP_BASE_API = '/api' | ||||||
							
								
								
									
										1
									
								
								.env.production
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | VUE_APP_BASE_API = '/api' | ||||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -17,5 +17,7 @@ selenium-debug.log | |||||||
| *.ntvs* | *.ntvs* | ||||||
| *.njsproj | *.njsproj | ||||||
| *.sln | *.sln | ||||||
|  | *.local | ||||||
|  |  | ||||||
| package-lock.json | package-lock.json | ||||||
|  | yarn.lock | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								babel.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,14 @@ | |||||||
|  | module.exports = { | ||||||
|  |   presets: [ | ||||||
|  |     ['@vue/app', { modules: 'commonjs' }] | ||||||
|  |   ], | ||||||
|  |   plugins: [], | ||||||
|  |   env: { | ||||||
|  |     test: { | ||||||
|  |       presets: [ | ||||||
|  |         ['@vue/app', { modules: 'commonjs' }] | ||||||
|  |       ], | ||||||
|  |       plugins: ['istanbul'] | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -1,67 +0,0 @@ | |||||||
| 'use strict' |  | ||||||
| require('./check-versions')() |  | ||||||
|  |  | ||||||
| const ora = require('ora') |  | ||||||
| const rm = require('rimraf') |  | ||||||
| const path = require('path') |  | ||||||
| const chalk = require('chalk') |  | ||||||
| const webpack = require('webpack') |  | ||||||
| const config = require('../config') |  | ||||||
| const webpackConfig = require('./webpack.prod.conf') |  | ||||||
| var connect = require('connect') |  | ||||||
| var serveStatic = require('serve-static') |  | ||||||
|  |  | ||||||
| const spinner = ora( |  | ||||||
|   'building for ' + process.env.env_config + ' environment...' |  | ||||||
| ) |  | ||||||
| spinner.start() |  | ||||||
|  |  | ||||||
| rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { |  | ||||||
|   if (err) throw 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' |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     if (stats.hasErrors()) { |  | ||||||
|       console.log(chalk.red(' Build failed with errors.\n')) |  | ||||||
|       process.exit(1) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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" |  | ||||||
|       ) |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     if (process.env.npm_config_preview) { |  | ||||||
|       const port = 9526 |  | ||||||
|       const host = 'http://localhost:' + port |  | ||||||
|       const basePath = config.build.assetsPublicPath |  | ||||||
|       const app = connect() |  | ||||||
|  |  | ||||||
|       app.use( |  | ||||||
|         basePath, |  | ||||||
|         serveStatic('./dist', { |  | ||||||
|           index: ['index.html', '/'] |  | ||||||
|         }) |  | ||||||
|       ) |  | ||||||
|  |  | ||||||
|       app.listen(port, function() { |  | ||||||
|         console.log( |  | ||||||
|           chalk.green(`> Listening at  http://localhost:${port}${basePath}`) |  | ||||||
|         ) |  | ||||||
|       }) |  | ||||||
|     } |  | ||||||
|   }) |  | ||||||
| }) |  | ||||||
| @@ -1,64 +0,0 @@ | |||||||
| 'use strict' |  | ||||||
| const chalk = require('chalk') |  | ||||||
| const semver = require('semver') |  | ||||||
| const packageConfig = require('../package.json') |  | ||||||
| const shell = require('shelljs') |  | ||||||
|  |  | ||||||
| function exec(cmd) { |  | ||||||
|   return require('child_process') |  | ||||||
|     .execSync(cmd) |  | ||||||
|     .toString() |  | ||||||
|     .trim() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const versionRequirements = [ |  | ||||||
|   { |  | ||||||
|     name: 'node', |  | ||||||
|     currentVersion: semver.clean(process.version), |  | ||||||
|     versionRequirement: packageConfig.engines.node |  | ||||||
|   } |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| if (shell.which('npm')) { |  | ||||||
|   versionRequirements.push({ |  | ||||||
|     name: 'npm', |  | ||||||
|     currentVersion: exec('npm --version'), |  | ||||||
|     versionRequirement: packageConfig.engines.npm |  | ||||||
|   }) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| 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) |  | ||||||
|       ) |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (warnings.length) { |  | ||||||
|     console.log('') |  | ||||||
|     console.log( |  | ||||||
|       chalk.yellow( |  | ||||||
|         'To use this template, you must update following to modules:' |  | ||||||
|       ) |  | ||||||
|     ) |  | ||||||
|     console.log() |  | ||||||
|  |  | ||||||
|     for (let i = 0; i < warnings.length; i++) { |  | ||||||
|       const warning = warnings[i] |  | ||||||
|       console.log('  ' + warning) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     console.log() |  | ||||||
|     process.exit(1) |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								build/logo.png
									
									
									
									
									
								
							
							
						
						| Before Width: | Height: | Size: 6.7 KiB | 
							
								
								
									
										108
									
								
								build/utils.js
									
									
									
									
									
								
							
							
						
						| @@ -1,108 +0,0 @@ | |||||||
| 'use strict' |  | ||||||
| const path = require('path') |  | ||||||
| const config = require('../config') |  | ||||||
| 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 |  | ||||||
|  |  | ||||||
|   return path.posix.join(assetsSubDirectory, _path) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| exports.cssLoaders = function(options) { |  | ||||||
|   options = options || {} |  | ||||||
|  |  | ||||||
|   const cssLoader = { |  | ||||||
|     loader: 'css-loader', |  | ||||||
|     options: { |  | ||||||
|       sourceMap: options.sourceMap |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   const postcssLoader = { |  | ||||||
|     loader: 'postcss-loader', |  | ||||||
|     options: { |  | ||||||
|       sourceMap: options.sourceMap |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // generate loader string to be used with extract text plugin |  | ||||||
|   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({ |  | ||||||
|         loader: loader + '-loader', |  | ||||||
|         options: Object.assign({}, loaderOptions, { |  | ||||||
|           sourceMap: options.sourceMap |  | ||||||
|         }) |  | ||||||
|       }) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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 |  | ||||||
|     }), |  | ||||||
|     scss: generateLoaders('sass'), |  | ||||||
|     stylus: generateLoaders('stylus'), |  | ||||||
|     styl: generateLoaders('stylus') |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Generate loaders for standalone style files (outside of .vue) |  | ||||||
| exports.styleLoaders = function(options) { |  | ||||||
|   const output = [] |  | ||||||
|   const loaders = exports.cssLoaders(options) |  | ||||||
|  |  | ||||||
|   for (const extension in loaders) { |  | ||||||
|     const loader = loaders[extension] |  | ||||||
|     output.push({ |  | ||||||
|       test: new RegExp('\\.' + extension + '$'), |  | ||||||
|       use: loader |  | ||||||
|     }) |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return output |  | ||||||
| } |  | ||||||
|  |  | ||||||
| exports.createNotifierCallback = () => { |  | ||||||
|   const notifier = require('node-notifier') |  | ||||||
|  |  | ||||||
|   return (severity, errors) => { |  | ||||||
|     if (severity !== 'error') return |  | ||||||
|  |  | ||||||
|     const error = errors[0] |  | ||||||
|     const filename = error.file && error.file.split('!').pop() |  | ||||||
|  |  | ||||||
|     notifier.notify({ |  | ||||||
|       title: packageConfig.name, |  | ||||||
|       message: severity + ': ' + error.name, |  | ||||||
|       subtitle: filename || '', |  | ||||||
|       icon: path.join(__dirname, 'logo.png') |  | ||||||
|     }) |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| 'use strict' |  | ||||||
|  |  | ||||||
| module.exports = { |  | ||||||
|   //You can set the vue-loader configuration by yourself. |  | ||||||
| } |  | ||||||
| @@ -1,107 +0,0 @@ | |||||||
| 'use strict' |  | ||||||
| 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) { |  | ||||||
|   return path.join(__dirname, '..', dir) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const createLintingRule = () => ({ |  | ||||||
|   test: /\.(js|vue)$/, |  | ||||||
|   loader: 'eslint-loader', |  | ||||||
|   enforce: 'pre', |  | ||||||
|   include: [resolve('src'), resolve('test')], |  | ||||||
|   options: { |  | ||||||
|     formatter: require('eslint-friendly-formatter'), |  | ||||||
|     emitWarning: !config.dev.showEslintErrorsInOverlay |  | ||||||
|   } |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| module.exports = { |  | ||||||
|   context: path.resolve(__dirname, '../'), |  | ||||||
|   entry: { |  | ||||||
|     app: './src/main.js' |  | ||||||
|   }, |  | ||||||
|   output: { |  | ||||||
|     path: config.build.assetsRoot, |  | ||||||
|     filename: '[name].js', |  | ||||||
|     publicPath: |  | ||||||
|       process.env.NODE_ENV === 'production' |  | ||||||
|         ? config.build.assetsPublicPath |  | ||||||
|         : config.dev.assetsPublicPath |  | ||||||
|   }, |  | ||||||
|   resolve: { |  | ||||||
|     extensions: ['.js', '.vue', '.json'], |  | ||||||
|     alias: { |  | ||||||
|       '@': resolve('src') |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   module: { |  | ||||||
|     rules: [ |  | ||||||
|       ...(config.dev.useEslint ? [createLintingRule()] : []), |  | ||||||
|       { |  | ||||||
|         test: /\.vue$/, |  | ||||||
|         loader: 'vue-loader', |  | ||||||
|         options: vueLoaderConfig |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         test: /\.js$/, |  | ||||||
|         loader: 'babel-loader?cacheDirectory', |  | ||||||
|         include: [ |  | ||||||
|           resolve('src'), |  | ||||||
|           resolve('test'), |  | ||||||
|           resolve('node_modules/webpack-dev-server/client') |  | ||||||
|         ] |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         test: /\.svg$/, |  | ||||||
|         loader: 'svg-sprite-loader', |  | ||||||
|         include: [resolve('src/icons')], |  | ||||||
|         options: { |  | ||||||
|           symbolId: 'icon-[name]' |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, |  | ||||||
|         loader: 'url-loader', |  | ||||||
|         exclude: [resolve('src/icons')], |  | ||||||
|         options: { |  | ||||||
|           limit: 10000, |  | ||||||
|           name: utils.assetsPath('img/[name].[hash:7].[ext]') |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, |  | ||||||
|         loader: 'url-loader', |  | ||||||
|         options: { |  | ||||||
|           limit: 10000, |  | ||||||
|           name: utils.assetsPath('media/[name].[hash:7].[ext]') |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, |  | ||||||
|         loader: 'url-loader', |  | ||||||
|         options: { |  | ||||||
|           limit: 10000, |  | ||||||
|           name: utils.assetsPath('fonts/[name].[hash:7].[ext]') |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     ] |  | ||||||
|   }, |  | ||||||
|   plugins: [new VueLoaderPlugin()], |  | ||||||
|   node: { |  | ||||||
|     // prevent webpack from injecting useless setImmediate polyfill because Vue |  | ||||||
|     // source contains it (although only uses it if it's native). |  | ||||||
|     setImmediate: false, |  | ||||||
|     // prevent webpack from injecting mocks to Node native modules |  | ||||||
|     // that does not make sense for the client |  | ||||||
|     dgram: 'empty', |  | ||||||
|     fs: 'empty', |  | ||||||
|     net: 'empty', |  | ||||||
|     tls: 'empty', |  | ||||||
|     child_process: 'empty' |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,98 +0,0 @@ | |||||||
| 'use strict' |  | ||||||
| const path = require('path') |  | ||||||
| const utils = require('./utils') |  | ||||||
| const webpack = require('webpack') |  | ||||||
| const config = require('../config') |  | ||||||
| const merge = require('webpack-merge') |  | ||||||
| const baseWebpackConfig = require('./webpack.base.conf') |  | ||||||
| const HtmlWebpackPlugin = require('html-webpack-plugin') |  | ||||||
| const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') |  | ||||||
| const portfinder = require('portfinder') |  | ||||||
|  |  | ||||||
| function resolve(dir) { |  | ||||||
|   return path.join(__dirname, '..', dir) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| 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 |  | ||||||
|     }) |  | ||||||
|   }, |  | ||||||
|   // cheap-module-eval-source-map is faster for development |  | ||||||
|   devtool: config.dev.devtool, |  | ||||||
|  |  | ||||||
|   // these devServer options should be customized in /config/index.js |  | ||||||
|   devServer: { |  | ||||||
|     clientLogLevel: 'warning', |  | ||||||
|     historyApiFallback: true, |  | ||||||
|     hot: true, |  | ||||||
|     compress: true, |  | ||||||
|     host: HOST || config.dev.host, |  | ||||||
|     port: PORT || config.dev.port, |  | ||||||
|     open: config.dev.autoOpenBrowser, |  | ||||||
|     overlay: config.dev.errorOverlay |  | ||||||
|       ? { warnings: false, errors: true } |  | ||||||
|       : false, |  | ||||||
|     publicPath: config.dev.assetsPublicPath, |  | ||||||
|     proxy: config.dev.proxyTable, |  | ||||||
|     quiet: true, // necessary for FriendlyErrorsPlugin |  | ||||||
|     watchOptions: { |  | ||||||
|       poll: config.dev.poll |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   plugins: [ |  | ||||||
|     new webpack.DefinePlugin({ |  | ||||||
|       'process.env': require('../config/dev.env') |  | ||||||
|     }), |  | ||||||
|     new webpack.HotModuleReplacementPlugin(), |  | ||||||
|     // https://github.com/ampedandwired/html-webpack-plugin |  | ||||||
|     new HtmlWebpackPlugin({ |  | ||||||
|       filename: 'index.html', |  | ||||||
|       template: 'index.html', |  | ||||||
|       inject: true, |  | ||||||
|       favicon: resolve('favicon.ico'), |  | ||||||
|       title: 'vue-element-admin', |  | ||||||
|       templateParameters: { |  | ||||||
|         BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory, |  | ||||||
|       }, |  | ||||||
|     }), |  | ||||||
|   ] |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| module.exports = new Promise((resolve, reject) => { |  | ||||||
|   portfinder.basePort = process.env.PORT || config.dev.port |  | ||||||
|   portfinder.getPort((err, port) => { |  | ||||||
|     if (err) { |  | ||||||
|       reject(err) |  | ||||||
|     } else { |  | ||||||
|       // publish the new Port, necessary for e2e tests |  | ||||||
|       process.env.PORT = port |  | ||||||
|       // add port to devServer config |  | ||||||
|       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 |  | ||||||
|         }) |  | ||||||
|       ) |  | ||||||
|  |  | ||||||
|       resolve(devWebpackConfig) |  | ||||||
|     } |  | ||||||
|   }) |  | ||||||
| }) |  | ||||||
| @@ -1,188 +0,0 @@ | |||||||
| 'use strict' |  | ||||||
| const path = require('path') |  | ||||||
| const utils = require('./utils') |  | ||||||
| const webpack = require('webpack') |  | ||||||
| const config = require('../config') |  | ||||||
| const merge = require('webpack-merge') |  | ||||||
| const baseWebpackConfig = require('./webpack.base.conf') |  | ||||||
| const CopyWebpackPlugin = require('copy-webpack-plugin') |  | ||||||
| const HtmlWebpackPlugin = require('html-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) { |  | ||||||
|   return path.join(__dirname, '..', dir) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| 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, |  | ||||||
|       extract: true, |  | ||||||
|       usePostCSS: true |  | ||||||
|     }) |  | ||||||
|   }, |  | ||||||
|   devtool: config.build.productionSourceMap ? config.build.devtool : false, |  | ||||||
|   output: { |  | ||||||
|     path: config.build.assetsRoot, |  | ||||||
|     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 |  | ||||||
|     }), |  | ||||||
|     // extract css into its own file |  | ||||||
|     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 |  | ||||||
|     // see https://github.com/ampedandwired/html-webpack-plugin |  | ||||||
|     new HtmlWebpackPlugin({ |  | ||||||
|       filename: config.build.index, |  | ||||||
|       template: 'index.html', |  | ||||||
|       inject: true, |  | ||||||
|       favicon: resolve('favicon.ico'), |  | ||||||
|       title: 'vue-element-admin', |  | ||||||
|       templateParameters: { |  | ||||||
|         BASE_URL: config.build.assetsPublicPath + config.build.assetsSubDirectory, |  | ||||||
|       }, |  | ||||||
|       minify: { |  | ||||||
|         removeComments: true, |  | ||||||
|         collapseWhitespace: true, |  | ||||||
|         removeAttributeQuotes: true |  | ||||||
|         // more options: |  | ||||||
|         // https://github.com/kangax/html-minifier#options-quick-reference |  | ||||||
|       } |  | ||||||
|       // 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 |  | ||||||
|     }), |  | ||||||
|     new ScriptExtHtmlWebpackPlugin({ |  | ||||||
|       //`runtime` must same as runtimeChunk name. default is `runtime` |  | ||||||
|       inline: /runtime\..*\.js$/ |  | ||||||
|     }), |  | ||||||
|     // keep chunk.id stable when chunk has no name |  | ||||||
|     new webpack.NamedChunksPlugin(chunk => { |  | ||||||
|       if (chunk.name) { |  | ||||||
|         return chunk.name |  | ||||||
|       } |  | ||||||
|       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 |  | ||||||
|       } |  | ||||||
|     }), |  | ||||||
|     // keep module.id stable when vender modules does not change |  | ||||||
|     new webpack.HashedModuleIdsPlugin(), |  | ||||||
|     // copy custom static assets |  | ||||||
|     new CopyWebpackPlugin([ |  | ||||||
|       { |  | ||||||
|         from: path.resolve(__dirname, '../static'), |  | ||||||
|         to: config.build.assetsSubDirectory, |  | ||||||
|         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-commons', |  | ||||||
|           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) { |  | ||||||
|   const CompressionWebpackPlugin = require('compression-webpack-plugin') |  | ||||||
|  |  | ||||||
|   webpackConfig.plugins.push( |  | ||||||
|     new CompressionWebpackPlugin({ |  | ||||||
|       asset: '[path].gz[query]', |  | ||||||
|       algorithm: 'gzip', |  | ||||||
|       test: new RegExp( |  | ||||||
|         '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' |  | ||||||
|       ), |  | ||||||
|       threshold: 10240, |  | ||||||
|       minRatio: 0.8 |  | ||||||
|     }) |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| 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 |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| module.exports = { |  | ||||||
|   NODE_ENV: '"development"', |  | ||||||
|   ENV_CONFIG: '"dev"', |  | ||||||
|   BASE_API: '"https://api-dev"' |  | ||||||
| } |  | ||||||
| @@ -1,88 +0,0 @@ | |||||||
| 'use strict' |  | ||||||
| // Template version: 1.2.6 |  | ||||||
| // see http://vuejs-templates.github.io/webpack for documentation. |  | ||||||
|  |  | ||||||
| const path = require('path') |  | ||||||
|  |  | ||||||
| module.exports = { |  | ||||||
|   dev: { |  | ||||||
|     // Paths |  | ||||||
|     assetsSubDirectory: 'static', |  | ||||||
|     assetsPublicPath: '/', |  | ||||||
|     proxyTable: {}, |  | ||||||
|  |  | ||||||
|     // Various Dev Server settings |  | ||||||
|  |  | ||||||
|     // can be overwritten by process.env.HOST |  | ||||||
|     // if you want dev by ip, please set host: '0.0.0.0' |  | ||||||
|     host: 'localhost', |  | ||||||
|     port: 9527, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined |  | ||||||
|     autoOpenBrowser: true, |  | ||||||
|     errorOverlay: true, |  | ||||||
|     notifyOnErrors: false, |  | ||||||
|     poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- |  | ||||||
|  |  | ||||||
|     // Use Eslint Loader? |  | ||||||
|     // If true, your code will be linted during bundling and |  | ||||||
|     // linting errors and warnings will be shown in the console. |  | ||||||
|     useEslint: true, |  | ||||||
|     // If true, eslint errors and warnings will also be shown in the error overlay |  | ||||||
|     // in the browser. |  | ||||||
|     showEslintErrorsInOverlay: false, |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Source Maps |  | ||||||
|      */ |  | ||||||
|  |  | ||||||
|     // https://webpack.js.org/configuration/devtool/#development |  | ||||||
|     devtool: 'cheap-source-map', |  | ||||||
|  |  | ||||||
|     // CSS Sourcemaps off by default because relative paths are "buggy" |  | ||||||
|     // with this option, according to the CSS-Loader README |  | ||||||
|     // (https://github.com/webpack/css-loader#sourcemaps) |  | ||||||
|     // In our experience, they generally work as expected, |  | ||||||
|     // just be aware of this issue when enabling this option. |  | ||||||
|     cssSourceMap: false |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   build: { |  | ||||||
|     // Template for index.html |  | ||||||
|     index: path.resolve(__dirname, '../dist/index.html'), |  | ||||||
|  |  | ||||||
|     // Paths |  | ||||||
|     assetsRoot: path.resolve(__dirname, '../dist'), |  | ||||||
|     assetsSubDirectory: 'static', |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * You can set by youself according to actual condition |  | ||||||
|      * You will need to set this if you plan to deploy your site under a sub path, |  | ||||||
|      * for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/, |  | ||||||
|      * then assetsPublicPath should be set to "/bar/". |  | ||||||
|      * In most cases please use '/' !!! |  | ||||||
|      */ |  | ||||||
|     assetsPublicPath: '/', |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Source Maps |  | ||||||
|      */ |  | ||||||
|     productionSourceMap: false, |  | ||||||
|     // https://webpack.js.org/configuration/devtool/#production |  | ||||||
|     devtool: 'source-map', |  | ||||||
|  |  | ||||||
|     // Gzip off by default as many popular static hosts such as |  | ||||||
|     // Surge or Netlify already gzip all static assets for you. |  | ||||||
|     // Before setting to `true`, make sure to: |  | ||||||
|     // npm install --save-dev compression-webpack-plugin |  | ||||||
|     productionGzip: false, |  | ||||||
|     productionGzipExtensions: ['js', 'css'], |  | ||||||
|  |  | ||||||
|     // Run the build command with an extra argument to |  | ||||||
|     // View the bundle analyzer report after build finishes: |  | ||||||
|     // `npm run build:prod --report` |  | ||||||
|     // Set to `true` or `false` to always turn it on or off |  | ||||||
|     bundleAnalyzerReport: process.env.npm_config_report || false, |  | ||||||
|  |  | ||||||
|     // `npm run build:prod --generate_report` |  | ||||||
|     generateAnalyzerReport: process.env.npm_config_generate_report || false |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| module.exports = { |  | ||||||
|   NODE_ENV: '"production"', |  | ||||||
|   ENV_CONFIG: '"prod"', |  | ||||||
|   BASE_API: '"https://api-prod"' |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| module.exports = { |  | ||||||
|   NODE_ENV: '"production"', |  | ||||||
|   ENV_CONFIG: '"sit"', |  | ||||||
|   BASE_API: '"https://api-sit"' |  | ||||||
| } |  | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| import Mock from 'mockjs' | import Mock from 'mockjs' | ||||||
| import { param2Obj } from '@/utils' |  | ||||||
| 
 | 
 | ||||||
| const List = [] | const List = [] | ||||||
| const count = 100 | const count = 100 | ||||||
| @@ -29,8 +28,8 @@ for (let i = 0; i < count; i++) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   getList: config => { |   '/article/list': config => { | ||||||
|     const { importance, type, title, page = 1, limit = 20, sort } = param2Obj(config.url) |     const { importance, type, title, page = 1, limit = 20, sort } = config.query | ||||||
| 
 | 
 | ||||||
|     let mockList = List.filter(item => { |     let mockList = List.filter(item => { | ||||||
|       if (importance && item.importance !== +importance) return false |       if (importance && item.importance !== +importance) return false | ||||||
| @@ -50,21 +49,26 @@ export default { | |||||||
|       items: pageList |       items: pageList | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   getPv: () => ({ |   '/article/detail': config => { | ||||||
|     pvData: [{ key: 'PC', pv: 1024 }, { key: 'mobile', pv: 1024 }, { key: 'ios', pv: 1024 }, { key: 'android', pv: 1024 }] |     const { id } = config.query | ||||||
|   }), |  | ||||||
|   getArticle: (config) => { |  | ||||||
|     const { id } = param2Obj(config.url) |  | ||||||
|     for (const article of List) { |     for (const article of List) { | ||||||
|       if (article.id === +id) { |       if (article.id === +id) { | ||||||
|         return article |         return article | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   createArticle: () => ({ |   '/article/pv': { | ||||||
|  |     pvData: [ | ||||||
|  |       { key: 'PC', pv: 1024 }, | ||||||
|  |       { key: 'mobile', pv: 1024 }, | ||||||
|  |       { key: 'ios', pv: 1024 }, | ||||||
|  |       { key: 'android', pv: 1024 } | ||||||
|  |     ] | ||||||
|  |   }, | ||||||
|  |   '/article/create': { | ||||||
|     data: 'success' |     data: 'success' | ||||||
|   }), |   }, | ||||||
|   updateArticle: () => ({ |   '/article/update': { | ||||||
|     data: 'success' |     data: 'success' | ||||||
|   }) |   } | ||||||
| } | } | ||||||
							
								
								
									
										50
									
								
								mock/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,50 @@ | |||||||
|  | import Mock from 'mockjs' | ||||||
|  | import mocks from './mocks' | ||||||
|  | import { param2Obj } from '../src/utils' | ||||||
|  |  | ||||||
|  | const MOCK_API_BASE = '/mock' | ||||||
|  |  | ||||||
|  | export function mockXHR() { | ||||||
|  |   // 修复在使用 MockJS 情况下,设置 withCredentials = true,且未被拦截的跨域请求丢失 Cookies 的问题 | ||||||
|  |   // https://github.com/nuysoft/Mock/issues/300 | ||||||
|  |   Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send | ||||||
|  |   Mock.XHR.prototype.send = function() { | ||||||
|  |     if (this.custom.xhr) { | ||||||
|  |       this.custom.xhr.withCredentials = this.withCredentials || false | ||||||
|  |     } | ||||||
|  |     this.proxy_send(...arguments) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   function XHR2ExpressReqWrap(respond) { | ||||||
|  |     return function(options) { | ||||||
|  |       let result = null | ||||||
|  |       if (respond instanceof Function) { | ||||||
|  |         const { body, type, url } = options | ||||||
|  |         // https://expressjs.com/en/4x/api.html#req | ||||||
|  |         result = respond({ | ||||||
|  |           method: type, | ||||||
|  |           body: JSON.parse(body), | ||||||
|  |           query: param2Obj(url) | ||||||
|  |         }) | ||||||
|  |       } else { | ||||||
|  |         result = respond | ||||||
|  |       } | ||||||
|  |       return Mock.mock(result) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (const [route, respond] of Object.entries(mocks)) { | ||||||
|  |     Mock.mock(new RegExp(`${route}`), XHR2ExpressReqWrap(respond)) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const responseFake = (route, respond) => ( | ||||||
|  |   { | ||||||
|  |     route: new RegExp(`${MOCK_API_BASE}${route}`), | ||||||
|  |     response(req, res) { | ||||||
|  |       res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | export default Object.keys(mocks).map(route => responseFake(route, mocks[route])) | ||||||
| @@ -1,5 +1,3 @@ | |||||||
| import { param2Obj } from '@/utils' |  | ||||||
| 
 |  | ||||||
| const userMap = { | const userMap = { | ||||||
|   admin: { |   admin: { | ||||||
|     roles: ['admin'], |     roles: ['admin'], | ||||||
| @@ -18,17 +16,18 @@ const userMap = { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   loginByUsername: config => { |   '/login/login': config => { | ||||||
|     const { username } = JSON.parse(config.body) |     const { username } = config.body | ||||||
|     return userMap[username] |     return userMap[username] | ||||||
|   }, |   }, | ||||||
|   getUserInfo: config => { |   '/login/logout': 'success', | ||||||
|     const { token } = param2Obj(config.url) |   '/user/info': config => { | ||||||
|  |     const { token } = config.query | ||||||
|     if (userMap[token]) { |     if (userMap[token]) { | ||||||
|       return userMap[token] |       return userMap[token] | ||||||
|     } else { |     } else { | ||||||
|       return false |       return false | ||||||
|     } |     } | ||||||
|   }, |   } | ||||||
|   logout: () => 'success' |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
							
								
								
									
										12
									
								
								mock/mocks.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | |||||||
|  | import login from './login' | ||||||
|  | import article from './article' | ||||||
|  | import search from './remoteSearch' | ||||||
|  | import transaction from './transaction' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   ...login, | ||||||
|  |   ...article, | ||||||
|  |   ...search, | ||||||
|  |   ...transaction | ||||||
|  | } | ||||||
|  |  | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| import Mock from 'mockjs' | import Mock from 'mockjs' | ||||||
| import { param2Obj } from '@/utils' |  | ||||||
| 
 | 
 | ||||||
| const NameList = [] | const NameList = [] | ||||||
| const count = 100 | const count = 100 | ||||||
| @@ -12,12 +11,11 @@ for (let i = 0; i < count; i++) { | |||||||
| NameList.push({ name: 'mockPan' }) | NameList.push({ name: 'mockPan' }) | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   searchUser: config => { |   '/search/user': config => { | ||||||
|     const { name } = param2Obj(config.url) |     const { name } = config.query | ||||||
|     const mockNameList = NameList.filter(item => { |     const mockNameList = NameList.filter(item => { | ||||||
|       const lowerCaseName = item.name.toLowerCase() |       const lowerCaseName = item.name.toLowerCase() | ||||||
|       if (name && lowerCaseName.indexOf(name.toLowerCase()) < 0) return false |       return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0) | ||||||
|       return true |  | ||||||
|     }) |     }) | ||||||
|     return { items: mockNameList } |     return { items: mockNameList } | ||||||
|   } |   } | ||||||
							
								
								
									
										16
									
								
								mock/transaction.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | |||||||
|  | import Mock from 'mockjs' | ||||||
|  |  | ||||||
|  | const count = 20 | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   '/transaction/list': { | ||||||
|  |     total: count, | ||||||
|  |     [`items|${count}`]: [{ | ||||||
|  |       order_no: '@guid()', | ||||||
|  |       timestamp: +Mock.Random.date('T'), | ||||||
|  |       username: '@name()', | ||||||
|  |       price: '@float(1000, 15000, 0, 2)', | ||||||
|  |       'status|1': ['success', 'pending'] | ||||||
|  |     }] | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										61
									
								
								package.json
									
									
									
									
									
								
							
							
						
						| @@ -5,9 +5,9 @@ | |||||||
|   "author": "Pan <panfree23@gmail.com>", |   "author": "Pan <panfree23@gmail.com>", | ||||||
|   "license": "MIT", |   "license": "MIT", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "dev": "cross-env BABEL_ENV=development webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", |     "dev": "vue-cli-service serve", | ||||||
|     "build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js", |     "build:prod": "vue-cli-service build", | ||||||
|     "build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js", |     "build:sit": "vue-cli-service build --mode text", | ||||||
|     "lint": "eslint --ext .js,.vue src", |     "lint": "eslint --ext .js,.vue src", | ||||||
|     "test": "npm run lint", |     "test": "npm run lint", | ||||||
|     "precommit": "lint-staged", |     "precommit": "lint-staged", | ||||||
| @@ -47,9 +47,9 @@ | |||||||
|     "js-cookie": "2.2.0", |     "js-cookie": "2.2.0", | ||||||
|     "jsonlint": "1.6.3", |     "jsonlint": "1.6.3", | ||||||
|     "jszip": "3.1.5", |     "jszip": "3.1.5", | ||||||
|     "mockjs": "1.0.1-beta3", |  | ||||||
|     "normalize.css": "7.0.0", |     "normalize.css": "7.0.0", | ||||||
|     "nprogress": "0.2.0", |     "nprogress": "0.2.0", | ||||||
|  |     "path-to-regexp": "^2.4.0", | ||||||
|     "screenfull": "3.3.3", |     "screenfull": "3.3.3", | ||||||
|     "showdown": "1.8.6", |     "showdown": "1.8.6", | ||||||
|     "simplemde": "1.11.2", |     "simplemde": "1.11.2", | ||||||
| @@ -64,63 +64,36 @@ | |||||||
|     "xlsx": "^0.11.16" |     "xlsx": "^0.11.16" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|  |     "@babel/core": "7.0.0", | ||||||
|  |     "@babel/register": "7.0.0", | ||||||
|  |     "@vue/babel-helper-vue-jsx-merge-props": "0.1.0", | ||||||
|  |     "@vue/cli-plugin-babel": "^3.0.5", | ||||||
|  |     "@vue/cli-plugin-eslint": "^3.0.5", | ||||||
|  |     "@vue/cli-plugin-unit-mocha": "^3.0.5", | ||||||
|  |     "@vue/cli-service": "^3.0.5", | ||||||
|  |     "@vue/eslint-config-standard": "^3.0.5", | ||||||
|  |     "@vue/test-utils": "^1.0.0-beta.25", | ||||||
|     "autoprefixer": "8.5.0", |     "autoprefixer": "8.5.0", | ||||||
|     "babel-core": "6.26.3", |     "babel-plugin-istanbul": "^4.1.6", | ||||||
|     "babel-eslint": "8.2.6", |  | ||||||
|     "babel-helper-vue-jsx-merge-props": "2.0.3", |  | ||||||
|     "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.7.0", |  | ||||||
|     "babel-preset-env": "1.7.0", |  | ||||||
|     "babel-preset-stage-2": "6.24.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-vue": "4.7.1", |  | ||||||
|     "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", |     "husky": "0.14.3", | ||||||
|     "lint-staged": "7.2.2", |     "lint-staged": "7.2.2", | ||||||
|     "mini-css-extract-plugin": "0.4.1", |     "mockjs": "1.0.1-beta3", | ||||||
|     "node-notifier": "5.2.1", |     "node-notifier": "5.2.1", | ||||||
|     "node-sass": "^4.7.2", |     "node-sass": "^4.7.2", | ||||||
|     "optimize-css-assets-webpack-plugin": "5.0.0", |     "optimize-css-assets-webpack-plugin": "5.0.0", | ||||||
|     "ora": "3.0.0", |  | ||||||
|     "path-to-regexp": "2.4.0", |  | ||||||
|     "portfinder": "1.0.13", |  | ||||||
|     "postcss-import": "11.1.0", |     "postcss-import": "11.1.0", | ||||||
|     "postcss-loader": "2.1.6", |     "postcss-loader": "2.1.6", | ||||||
|     "postcss-url": "7.3.2", |     "postcss-url": "7.3.2", | ||||||
|     "rimraf": "2.6.2", |  | ||||||
|     "sass-loader": "7.0.3", |     "sass-loader": "7.0.3", | ||||||
|     "script-ext-html-webpack-plugin": "2.0.1", |     "script-ext-html-webpack-plugin": "2.0.1", | ||||||
|     "script-loader": "0.7.2", |     "script-loader": "0.7.2", | ||||||
|     "semver": "5.5.0", |  | ||||||
|     "serve-static": "1.13.2", |  | ||||||
|     "shelljs": "0.8.2", |     "shelljs": "0.8.2", | ||||||
|     "svg-sprite-loader": "3.8.0", |     "svg-sprite-loader": "3.8.0", | ||||||
|     "svgo": "1.0.5", |     "svgo": "1.0.5", | ||||||
|     "uglifyjs-webpack-plugin": "1.2.7", |     "vue-template-compiler": "2.5.17" | ||||||
|     "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": { |   "engines": { | ||||||
|     "node": ">= 6.0.0", |     "node": ">=8.9", | ||||||
|     "npm": ">= 3.0.0" |     "npm": ">= 3.0.0" | ||||||
|   }, |   }, | ||||||
|   "browserslist": [ |   "browserslist": [ | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								public/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 66 KiB | 
| @@ -5,10 +5,11 @@ | |||||||
|     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | ||||||
|     <meta name="renderer" content="webkit"> |     <meta name="renderer" content="webkit"> | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> |     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> | ||||||
|  |     <link rel="icon" href="<%= BASE_URL %>favicon.ico"> | ||||||
|     <title>vue-element-admin</title> |     <title>vue-element-admin</title> | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
|     <script src=<%= BASE_URL %>/tinymce4.7.5/tinymce.min.js></script> |     <script src="<%= BASE_URL %>static/tinymce4.7.5/tinymce.min.js"></script> | ||||||
|     <div id="app"></div> |     <div id="app"></div> | ||||||
|     <!-- built files will be auto injected --> |     <!-- built files will be auto injected --> | ||||||
|   </body> |   </body> | ||||||
| Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 354 B | 
| Before Width: | Height: | Size: 329 B After Width: | Height: | Size: 329 B | 
| Before Width: | Height: | Size: 331 B After Width: | Height: | Size: 331 B | 
| Before Width: | Height: | Size: 342 B After Width: | Height: | Size: 342 B | 
| Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 340 B | 
| Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 336 B | 
| Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 338 B | 
| Before Width: | Height: | Size: 343 B After Width: | Height: | Size: 343 B | 
| Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 321 B | 
| Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 323 B | 
| Before Width: | Height: | Size: 344 B After Width: | Height: | Size: 344 B | 
| Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 338 B | 
| Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 328 B | 
| Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 337 B | 
| Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B | 
| Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 336 B | 
| Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB | 
| Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB | 
| Before Width: | Height: | Size: 53 B After Width: | Height: | Size: 53 B | 
| Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB | 
| Before Width: | Height: | Size: 152 B After Width: | Height: | Size: 152 B | 
| Before Width: | Height: | Size: 43 B After Width: | Height: | Size: 43 B | 
| @@ -61,7 +61,7 @@ export default { | |||||||
|         tmp = this.data |         tmp = this.data | ||||||
|       } |       } | ||||||
|       const func = this.evalFunc || treeToArray |       const func = this.evalFunc || treeToArray | ||||||
|       const args = this.evalArgs ? Array.concat([tmp, this.expandAll], this.evalArgs) : [tmp, this.expandAll] |       const args = this.evalArgs ? [].concat([tmp, this.expandAll], this.evalArgs) : [tmp, this.expandAll] | ||||||
|       return func.apply(null, args) |       return func.apply(null, args) | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   | |||||||
| @@ -17,10 +17,14 @@ import i18n from './lang' // Internationalization | |||||||
| import './icons' // icon | import './icons' // icon | ||||||
| import './errorLog' // error log | import './errorLog' // error log | ||||||
| import './permission' // permission control | import './permission' // permission control | ||||||
| import './mock' // simulation data |  | ||||||
|  |  | ||||||
| import * as filters from './filters' // global filters | import * as filters from './filters' // global filters | ||||||
|  |  | ||||||
|  | import { mockXHR } from '../mock' // simulation data | ||||||
|  |  | ||||||
|  | // mock api in github pages site build | ||||||
|  | if (process.env.NODE_ENV === 'production') { mockXHR() } | ||||||
|  |  | ||||||
| Vue.use(Element, { | Vue.use(Element, { | ||||||
|   size: Cookies.get('size') || 'medium', // set element-ui default size |   size: Cookies.get('size') || 'medium', // set element-ui default size | ||||||
|   i18n: (key, value) => i18n.t(key, value) |   i18n: (key, value) => i18n.t(key, value) | ||||||
|   | |||||||
| @@ -1,39 +0,0 @@ | |||||||
| import Mock from 'mockjs' |  | ||||||
| import loginAPI from './login' |  | ||||||
| import articleAPI from './article' |  | ||||||
| import remoteSearchAPI from './remoteSearch' |  | ||||||
| import transactionAPI from './transaction' |  | ||||||
|  |  | ||||||
| // 修复在使用 MockJS 情况下,设置 withCredentials = true,且未被拦截的跨域请求丢失 Cookies 的问题 |  | ||||||
| // https://github.com/nuysoft/Mock/issues/300 |  | ||||||
| Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send |  | ||||||
| Mock.XHR.prototype.send = function() { |  | ||||||
|   if (this.custom.xhr) { |  | ||||||
|     this.custom.xhr.withCredentials = this.withCredentials || false |  | ||||||
|   } |  | ||||||
|   this.proxy_send(...arguments) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Mock.setup({ |  | ||||||
| //   timeout: '350-600' |  | ||||||
| // }) |  | ||||||
|  |  | ||||||
| // 登录相关 |  | ||||||
| Mock.mock(/\/login\/login/, 'post', loginAPI.loginByUsername) |  | ||||||
| Mock.mock(/\/login\/logout/, 'post', loginAPI.logout) |  | ||||||
| Mock.mock(/\/user\/info\.*/, 'get', loginAPI.getUserInfo) |  | ||||||
|  |  | ||||||
| // 文章相关 |  | ||||||
| Mock.mock(/\/article\/list/, 'get', articleAPI.getList) |  | ||||||
| Mock.mock(/\/article\/detail/, 'get', articleAPI.getArticle) |  | ||||||
| Mock.mock(/\/article\/pv/, 'get', articleAPI.getPv) |  | ||||||
| Mock.mock(/\/article\/create/, 'post', articleAPI.createArticle) |  | ||||||
| Mock.mock(/\/article\/update/, 'post', articleAPI.updateArticle) |  | ||||||
|  |  | ||||||
| // 搜索相关 |  | ||||||
| Mock.mock(/\/search\/user/, 'get', remoteSearchAPI.searchUser) |  | ||||||
|  |  | ||||||
| // 账单相关 |  | ||||||
| Mock.mock(/\/transaction\/list/, 'get', transactionAPI.getList) |  | ||||||
|  |  | ||||||
| export default Mock |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| import Mock from 'mockjs' |  | ||||||
|  |  | ||||||
| const List = [] |  | ||||||
| const count = 20 |  | ||||||
|  |  | ||||||
| for (let i = 0; i < count; i++) { |  | ||||||
|   List.push(Mock.mock({ |  | ||||||
|     order_no: '@guid()', |  | ||||||
|     timestamp: +Mock.Random.date('T'), |  | ||||||
|     username: '@name()', |  | ||||||
|     price: '@float(1000, 15000, 0, 2)', |  | ||||||
|     'status|1': ['success', 'pending'] |  | ||||||
|   })) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   getList: () => { |  | ||||||
|     return { |  | ||||||
|       total: List.length, |  | ||||||
|       items: List |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -5,7 +5,8 @@ import { getToken } from '@/utils/auth' | |||||||
|  |  | ||||||
| // create an axios instance | // create an axios instance | ||||||
| const service = axios.create({ | const service = axios.create({ | ||||||
|   baseURL: process.env.BASE_API, // api 的 base_url |   baseURL: process.env.VUE_APP_BASE_API, // api 的 base_url | ||||||
|  |   withCredentials: true, // 跨域请求时发送 cookies | ||||||
|   timeout: 5000 // request timeout |   timeout: 5000 // request timeout | ||||||
| }) | }) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import * as Driver from 'driver.js' // import driver.js | import Driver from 'driver.js' // import driver.js | ||||||
| import 'driver.js/dist/driver.min.css' // import driver.js css | import 'driver.js/dist/driver.min.css' // import driver.js css | ||||||
| import steps from './defineSteps' | import steps from './defineSteps' | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								vue.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,60 @@ | |||||||
|  | 'use strict' | ||||||
|  | require('@babel/register') | ||||||
|  | const path = require('path') | ||||||
|  | const bodyParser = require('body-parser') | ||||||
|  |  | ||||||
|  | function resolve(dir) { | ||||||
|  |   return path.join(__dirname, dir) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |   devServer: { | ||||||
|  |     open: true, | ||||||
|  |     proxy: { | ||||||
|  |       '/api': { | ||||||
|  |         target: 'http://localhost:8080/mock', | ||||||
|  |         changeOrigin: true, | ||||||
|  |         pathRewrite: { | ||||||
|  |           '^/api': '' | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     after(app) { | ||||||
|  |       // parse app.body | ||||||
|  |       // http://expressjs.com/en/4x/api.html#req.body | ||||||
|  |       app.use(bodyParser.json()) | ||||||
|  |       app.use(bodyParser.urlencoded({ extended: true })) | ||||||
|  |  | ||||||
|  |       // import ES2015 module from common.js module | ||||||
|  |       const { default: mocks } = require('./mock') | ||||||
|  |       for (const mock of mocks) { | ||||||
|  |         app.all(mock.route, mock.response) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   configureWebpack: { | ||||||
|  |     resolve: { | ||||||
|  |       alias: { | ||||||
|  |         '$@': resolve('src/components') | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     module: { | ||||||
|  |       rules: [ | ||||||
|  |         { | ||||||
|  |           test: /\.svg$/, | ||||||
|  |           loader: 'svg-sprite-loader', | ||||||
|  |           include: [resolve('src/icons')], | ||||||
|  |           options: { | ||||||
|  |             symbolId: 'icon-[name]' | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       ] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   chainWebpack(config) { | ||||||
|  |     config.module | ||||||
|  |       .rule('svg') | ||||||
|  |       .exclude.add(resolve('src/icons')) | ||||||
|  |       .end() | ||||||
|  |   } | ||||||
|  | } | ||||||