//安装eslint工具,规范项目中的代码
npm i eslint -D
npm i babel-eslint -D
npm i eslint-loader -D
//快速生成eslint配置
npx eslint --init
在 .eslintrc.js 中:
module.exports = {
"extends": "airbnb",
"parser": "babel-eslint",
"rules": {
"react/prefer-stateless-function": 0,
"react/jsx-filename-extension": 0
},
globals: {
document: false
}
};
详细请看官方文档:eslint
在 vscode 编辑器里安装 eslint 插件,自动检测语法错误。(推荐使用)
在 webpack.config.js 中:
devServer: {
+ overlay: true,//在浏览器弹出提示有错误
},
rules: [{
test: /\.js$/,
exclude: /node_modules/,
+ use: ['babel-loader', 'eslint-loader'] //先检查代码写的是否规范,在转换成es5
},
...],
在真实项目中,也可以不在webpack 中配置eslint,在提交git仓库时,git 钩子 eslint src 。但是没有图形交互式的错误提示。
详细请看官方文档:eslint-loader
Plugin 尽可能精简并确保可靠
resolve 参数合理配置, 引入资源文件写后缀,像 图片文件(.jpg, .png, .svg),逻辑代码配置在extensions中:extensions: ['.js', '.jsx']
使用 DLLPlugin 提高打包速度 详细请看官方文档:dll-plugin
实现第三方模块只打包一次
安装:
npm i add-asset-html-webpack-plugin --save
在 build 文件夹里创建 webpack.dll.js 文件:把第三方模块单独进行打包,生成一个vendors.dll.js 文件,所有的第三方模块都在这个文件里。
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendors: ['lodash'],
react: ['react', 'react-dom'],
jquery: ['jquery']
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, '../dll'),
library: '[name]'//打包生成的库名,通过全局变量的形式暴露到全局
},
plugins: [
new webpack.DllPlugin({//对暴露到全局的代码进行分析,生成vendors.manifest.json 的映射文件,
name: '[name]',
path: path.resolve(__dirname, '../dll/[name].manifest.json'),
})
]
}
在 webpack.common.js 中:
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
files.forEach(file => {
if(/.*\.dll.js/.test(file)) {
plugins.push(new AddAssetHtmlWebpackPlugin({//将打包好的dll文件挂载到html中
filepath: path.resolve(__dirname, '../dll', file)
}))
}
if(/.*\.manifest.json/.test(file)) {
plugins.push(new webpack.DllReferencePlugin({//分析第三方模块是否已经在dll文件里,如果里面有就不用再node_modules在分析打包了
manifest: path.resolve(__dirname, '../dll', file)
}))
}
})
总结:
如果不使用使用 DLLPlugin 插件,当引入第三方模块时,每一次打包都要进行分析,是消耗打包的性能的。使用 DLLPlugin 提高打包速度,在第一次打包时,把第三方模块单独打包生成一个文件 vendors.dll.js ,之后在打包时就可以直接从 vendors.dll.js 中引入之前打包好的第三方模块,速度就会变快。
要想实现,就得做一些配置:
先配置 webpack.dll.js 文件,在配置 webpack.common.js 文件
==============================================================
.dll 为后缀的文件称为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据
在 webpack.dll.js 中:
module.exports = {
entry: {
react: ['react'] //react模块打包到一个动态连接库
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].dll.js', //输出动态连接库的文件名称
library: '_dll_[name]' //全局变量名称
},
plugins: [
new webpack.DllPlugin({
name: '_dll_[name]', //和output.library中一致,值就是输出的manifest.json中的 name值
path: path.join(__dirname, 'dist', '[name].manifest.json')
})
]
}
webpack --config webpack.dll.config.js --mode production
在 webpack.common.js 中:
plugins: [
+ new webpack.DllReferencePlugin({
+ manifest: require(path.join(__dirname, 'dist', 'react.manifest.json')),
+ })
],
webpack --config webpack.config.js --mode development
==============================================================
配置 Tree shaking,把用不到的代码去除掉。配置 SplitChunksPlugin。
HappyPack就能让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。 happypack
安装:npm i happypack@next -D
配置:
module: {
rules: [{
test: /\.js$/,
//把对.js文件的处理转交给id为babel的HappyPack实例
+ use: 'happypack/loader?id=babel',
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}, {
//把对.css文件的处理转交给id为css的HappyPack实例
test: /\.css$/,
+ use: 'happypack/loader?id=css',
include: path.resolve(__dirname, 'src')
}],
noParse: [/react\.min\.js/]
},
plugins: [
//用唯一的标识符id来代表当前的HappyPack是用来处理一类特定文件
new HappyPack({
id: 'babel',
//如何处理.js文件,和rules里的配置相同
loaders: [{
loader: 'babel-loader',
query: {
presets: [
"env", "react"
]
}
}]
}),
new HappyPack({
id: 'css',
loaders: ['style-loader', 'css-loader'],
threads: 4, //代表开启几个子进程去处理这一类型的文件
verbose: true //是否允许输出日子
})
],
ParallelUglifyPlugin
可以把对JS文件的串行压缩变为开启多个子进程并行执行
安装:npm i -D webpack-parallel-uglify-plugin
配置:
new ParallelUglifyPlugin({
workerCount: 3, //开启几个子进程去并发的执行压缩。默认是当前运行电脑的 CPU 核数减去1
uglifyJS: {
output: {
beautify: false, //不需要格式化
comments: false, //不保留注释
},
compress: {
warnings: false, // 在UglifyJs删除没有用到的代码时不输出警告
drop_console: true, // 删除所有的 `console` 语句,可以兼容ie浏览器
collapse_vars: true, // 内嵌定义了但是只用到一次的变量
reduce_vars: true, // 提取出出现多次但是没有定义成变量去引用的静态值
}
},
})
配置多个 entry 里的 html 页面,用HtmlWebpackPlugin 插件,将打包好的j多个js分别插入到对应的html页面中。
在 webpack.common.js 中:
const path = require('path');
const fs = require('fs');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const webpack = require('webpack');
const makePlugins = (configs) => {
const plugins = [
new CleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../')
})
];
Object.keys(configs.entry).forEach(item => {
plugins.push(
+ new HtmlWebpackPlugin({
template: 'src/index.html',
filename: `${item}.html`,
chunks: ['runtime', 'vendors', item]
})
)
});
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
files.forEach(file => {
if(/.*\.dll.js/.test(file)) {
plugins.push(new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll', file)
}))
}
if(/.*\.manifest.json/.test(file)) {
plugins.push(new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll', file)
}))
}
});
return plugins;
}
const configs = {
+ entry: {
index: './src/index.js',
list: './src/list.js',
detail: './src/detail.js',
},
resolve: {
extensions: ['.js', '.jsx'],
},
module: {
rules: [{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'),
use: [{
loader: 'babel-loader'
}]
}, {
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240
}
}
}, {
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'file-loader'
}
}]
},
optimization: {
runtimeChunk: {
name: 'runtime'
},
usedExports: true,
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
name: 'vendors',
}
}
}
},
performance: false,
output: {
path: path.resolve(__dirname, '../dist')
}
}
configs.plugins = makePlugins(configs);
module.exports = configs