之前1-3部分是webpack最基本的配置, 接下来会把项目结构和配置文件重新设计,可以扩充更多的功能模块。
一、重构webpack的配置项
1. 新建目录build,存放webpack不同的配置文件
(1) webpack.config.base.js 【保留公共的配置项,将生产环境和开发环境使用的配置项分离出去】
1 const path = require('path') 2 const webpack = require('webpack') 3 const VueLoaderPlugin = require('vue-loader/lib/plugin') 4 const HtmlWebpackPlugin = require('html-webpack-plugin') 5 const CleanWebpackPlugin = require('clean-webpack-plugin') 6 7 const isDev = process.env.NODE_ENV === 'development' 8 9 const config = {
mode: process.env.NODE_ENV || 'production' 10 target: 'web', 11 performance: { 12 hints: false, 13 maxAssetSize: 500000 14 }, 15 entry: path.join(__dirname, '../src/index.js'), 16 output: { 17 path: path.join(__dirname, '../dist'), 18 filename: 'scripts/bundle.[hash:8].js' 19 }, 20 module: { 21 rules: [ 22 { 23 test: /.vue$/, 24 use: [ 25 { 26 loader: "vue-loader" 27 } 28 ] 29 }, 30 { 31 test: /.jsx$/, 32 loader: "babel-loader" 33 }, 34 { 35 test: /.js$/, 36 loader: "babel-loader", 37 exclude: /node_modules/ 38 }, 39 { 40 test: /.(jpg|jpeg|gif|png|svg)$/, 41 use: [ 42 { 43 loader: "url-loader", 44 options: { 45 limit: 1024, 46 name: 'images/[name]-[hash:8].[ext]' 47 } 48 } 49 ] 50 } 51 ] 52 }, 53 plugins: [ 54 new VueLoaderPlugin() 55 ] 56 } 57 58 module.exports = config
注意: 入口文件和输出路径
注意: VueLoaderPlugin是使用vue-loader必须的,两种环境都需要加载。jsx和js的规则分开配置,因为js编译时需要除去node_modules目录下的文件。
(2) webpack.config.client.js 【配置开发和生产环境环境需要的选项】
安装 webpack-merge工具, 提供配置文件扩展方法。
1 $ npm i -D webpack-merge
(3) 在webpack.config.client.js中使用merge对基础的配置baseConfig进行扩展。
1 const path = require('path') 2 const webpack = require('webpack') 3 const merge = require('webpack-merge') 4 const VueLoaderPlugin = require('vue-loader/lib/plugin') 5 const HtmlWebpackPlugin = require('html-webpack-plugin') 6 const CleanWebpackPlugin = require('clean-webpack-plugin') 7 const ExtractTextPlugin = require('extract-text-webpack-plugin') 8 const baseConfig = require('./webpack.config.base') 9 10 const isDev = process.env.NODE_ENV === 'development' 11 const basePlugin = [ 12 new VueLoaderPlugin(), 13 new CleanWebpackPlugin(['../dist']), 14 // 根据不同环境区分打包 15 new webpack.DefinePlugin({ 16 'process.env': { 17 NODE_ENV: isDev ? '"development"' : '"production"', 18 } 19 }), 20 new HtmlWebpackPlugin({ 21 template: path.join(__dirname, '../index.html') 22 }) 23 ] 24 const devServer = { 25 port: 9000, 26 host: '0.0.0.0', 27 overlay: { 28 errors: true 29 }, 30 historyApiFallback: true, 31 hot: true, 32 } 33 34 let config 35 36 if (isDev) { 37 config = merge(baseConfig, { 38 // mode: 'development', 39 // devtool: '#cheap-module-eval-source-map', 40 module: { 41 rules: [ 42 { 43 test: /.css$/, 44 use: ['style-loader', 'css-loader'] 45 }, 46 { 47 test: /.styl(us)?$/, 48 use: [ 49 'style-loader', 50 'css-loader', 51 { 52 loader: "postcss-loader", 53 options: { 54 sourceMap: true 55 } 56 }, 57 'stylus-loader', 58 ] 59 }, 60 ] 61 }, 62 devServer, 63 plugins: basePlugin.concat([ 64 new webpack.HotModuleReplacementPlugin(), 65 new webpack.SourceMapDevToolPlugin() // devtool 66 ]) 67 }) 68 } else { 69 config = merge(baseConfig, { 70 // mode: 'production', 71 entry: { 72 app: path.join(__dirname, '../src/index.js'), 73 vendor: ['vue'] 74 }, 75 output: { 76 filename: 'scripts/[name].[chunkhash:8].js' 77 }, 78 module: { 79 rules: [ 80 { 81 test: /.css$/, 82 use: ExtractTextPlugin.extract({ 83 fallback: 'style-loader', 84 use: ['css-loader'] 85 }) 86 }, 87 { 88 test: /.styl(us)?$/, 89 use: ExtractTextPlugin.extract({ 90 fallback: 'style-loader', 91 use: [ 92 'css-loader', 93 { 94 loader: "postcss-loader", 95 options: { 96 sourceMap: true 97 } 98 }, 99 'stylus-loader', 100 ] 101 }) 102 }, 103 ] 104 }, 105 plugins: basePlugin.concat([ 106 new ExtractTextPlugin('style.[hash:8].css'), 107 ]), 108 optimization: { 109 splitChunks: { 110 chunks: 'all' // name: 'vendor' 111 }, 112 runtimeChunk: true 115 } 116 }) 117 } 118 119 module.exports = config
注意红色部分的修改:
1 .引入merge工具 和 webpack.config.base.js
2 .将公共plugin提取保存在变量 basePlugin, 不在base.js中使用的原因是后续的服务端渲染时无需使用, 故只在生产环境和开发环境引用。
3. 将devServer提取保存在变量中。
4. 声明变量config, 保存通过merge以baseConfig为基础扩展的配置项
5. basePlugin.concat()将公共的plugin添加到不同环境
修改package.json的运行脚本
1 "scripts": { 2 "test": "echo "Error: no test specified" && exit 1", 3 "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.client.js --colors --progress", 4 "dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.client.js --colors --progress", 5 "start": "npm run dev" 6 },
注意, 指向指定路劲时必须使用 --config否则报错无法编译。之前不用--config是因为默认指向了根目录的webpack.config.js
至此: 运行 $ npm run build $ npm run dev正常。
另注: 如果后续需要编写服务端的代码,可以将项目分为client/ 和 server/ 两个目录,分别存放服务端和客户端的业务代码, 如下
将原来的src/改成client/ 注意别忘了修改 webpack.config.base.js和 webpack.config.client.js内的相关路径。目录修改根据自己的习惯和环境而定。
二、使用rimraf工具 ,在打包前删除旧包
1. 之前使用的是clean-webpack-plugin,rimraf也有同样的功能,但rimraf可以直接写在scripts脚本内
2. 安装 $ npm i -D rimraf
3 . 添加到 scripts中
1 "scripts": { 2 "test": "echo "Error: no test specified" && exit 1", 3 "build": "npm run clean && cross-env NODE_ENV=production webpack --config build/webpack.config.client.js --colors --progress", 4 "dev": "npm run clean && cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.client.js --colors --progress", 5 "start": "npm run clean && npm run dev", 6 "clean": "rimraf dist" 7 },
三、添加eslint代码校验
(1)安装eslint及其依赖
npm i -D eslint npm i -D eslint-config-standard eslint-plugin-standard npm i -D eslint-plugin-promise eslint-plugin-import eslint-plugin-node
npm i -D eslint-plugin-html
特别要说明的是,在vue项目中,eslint默认是无法解析.vue的文件, 所以需要使用 eslint-plugin-html插件来解析 , 其他都是辅助eslint的插件和工具
(2)创建 .eslinrc配置文件
{ "extends": "standard", "plugins": [ "html" ] }
(3)package.json中添加命令
1 "scripts": { 2 "test": "echo "Error: no test specified" && exit 1", 3 "build": "npm run clean && cross-env NODE_ENV=production webpack --config build/webpack.config.client.js --colors --progress", 4 "dev": "npm run clean && cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.client.js --colors --progress", 5 "lint": "eslint --ext .js --ext .jsx --ext .vue client/", 6 "fix": "eslint --fix --ext .js --ext .jsx --ext .vue client/", 7 "start": "npm run clean && npm run dev", 8 "clean": "rimraf dist" 9 },
配置完成后运行脚本 : $ npm run lint会提示出一系列的警告。这是因为之前编写的代码中有些不符合eslint的默认规范。 可以使用 $ npm run fix命令批量修复。
(4)错误
在新版本的eslint中,如果设置extends为 'standard'则会报错:(不再支持"standard"的方式, 具体原因暂时未知),将eslinrc修改如下
1 module.exports = { 2 "env": { 3 "browser": true, 4 "commonjs": true, 5 "es6": true 6 }, 7 "extends": ["eslint:recommended"], 8 "plugins": [ 9 "html" 10 ] 11 }
运行 $ npm run lint 但又出现错误:都不能使用export和 import, 继续添加配置
1 "parserOptions": { 2 "ecmaFeatures": { 3 "jsx": true 4 }, 5 "ecmaVersion": 2015, 6 "sourceType": "module" 7 },
此时运行 $ npm run lint不再报错。
以上是使用 eslint-plugin-html 解析vue文件 , 也可以使用插件 eslint-plugin-vue来解析vue 文件,安装插件后修改eslintrc
1 "extends": ["eslint:recommended", "plugin:vue/essential"], 2 "plugins": [ 3 "vue" 4 ],
运行 $ npm run lint检查错误, 运行 $ npm run fix修正错误。
(5)在webpack项目中使用eslint-loader
安装
1 $ npm i -D eslint-loader 2 $ npm i -D babel-eslint
eslintrc的 parserOptions 中添加 babel-eslint
1 "parserOptions": { 2 "parser": "babel-eslint", // 解析检测babel的代码 3 "ecmaFeatures": { 4 "jsx": true // 检测jsx语法 5 }, 6 "ecmaVersion": 2015, 7 "sourceType": "module" 8 },
在 webpack.config.base.js中 rules 添加 eslint 规则
1 { 2 test: /.(vue|js|jsx)$/, 3 exclude: /node_modules/, 4 loader: "eslint-loader", 5 enforce: "pre" // 预处理,在匹配的文件编译前先检测语法 6 },
至此, 运行项目, 并在业务文件内改成有错误的格式, eslint将会自动检测到后提示错误, 只要再修改回来即可正常。
接下来在 eslintrc文件中配置 rules,设置指定的语法格式。这里只配置了一小部分,根据项目需求可自定义。
"rules": { "no-new": "off", "no-alert": "off", "no-console": [ "off" ], "eol-last": 0, "space-before-function-paren": 0, "indent": 0 }
0 或者 off一般表示关闭不做解析。如以上代码中"indent" :0表示不做缩进的检测, "indent": 2 表示缩进是两个空格否则会报错, 其他用法可参考官网。