webpack 使用总结
12 Jun 2019webpack 使用总结
基础配置
const path = require('path');
module.exports = {
entry: './app/index.js',
context: path.resolve(__dirname),
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.[hash:8].js',
publicPath: 'https://www.example.com'
},
module: {
rules: []
},
resolve: {},
devtool: 'source-map',
plugins: [],
externals: {} //页面之间引入的库,不进行webpack打包
};
html-webpack-plugin
多入口
entry: {
home: './app/home.js',
other: './app/other.js'
}
...
new HtmlWebpackPlugin({
template: './index.html',
filename: 'home.html',
hash: true,
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true
}
chunks: ['home','other']
}),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'other.html',
chunks: ['other']
})
样式处理和css抽离
rules: [
{
test: /.css$/,
use: [
'style-loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')()]
}
}
'sass-loader',
]
}
]
抽离css(mini-css-extract-plugin)、js 及文件分类
const TerserJSPlugin = require('terser-webpack-plugin'); //压缩js
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 压缩css
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 抽离css
...
entry: './app/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.[hash:8].js'
},
...
optimization: {
minimizer: [
new TerserJSPlugin({}),
new OptimizeCSSAssetsPlugin({})
],
},
...
module: {
rules: [
{
test: /.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
]
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 1024*1,
outputPath: '/imgs'
}
}
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/index.css'
}),
]
postcss.config.js
module.exports = {
plugins: [require('autoprefixer')]
}
es6语法转换
module: {
rules: [
{
test: /.js$/,
use: [
'babel-loader'
],
exclude: /node_modules/,
include: path.resolve(__dirname,'src')
}
]
}
.babelrc
{
"presets": ["@babel/preset-env"],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }],
["@babel/plugin-transform-runtime"]
]
}
@babel/plugin-transform-runtime 开发依赖 转换 generator等 @babel/runtime 生产依赖 runtime可以将babel转换的公共helper方法抽离公用 但不能转换实例上的方法像 str.includes(), 需要 @bable/polyfill
js校验 eslint
rules: [
{
test: /.js$/,
use: [
'babel-loader'
],
exclude: /node_modules/,
include: path.resolve(__dirname,'src')
},
{
test: /.js$/,
use: {
loader: 'eslint-loader',
options:{
enforce: 'pre' // enforce 强制前/后 'pre/post'
}
},
exclude: /node_modules/,
include: path.resolve(__dirname,'src')
}
]
.eslintrc.json
{
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "double"]
}
...官网配置
}
全局暴露及全局变量、环境变量
webpack 内置插件 ProvidePlugin 在每个模块中注入模块 DefinePlugin定义变量
plugin: [
new webpack.ProvidePlugin({
$: 'jquery'
_: 'loash'
}),
new webpack.DefinePlugin({
DEV: JSON.stringify('development')
})
]
图片处理
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'html-withimg-loader',
}
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 1024*1,
outputPath: '/imgs',
publicPath: 'http://images.example.cn'
}
}
}
source-map 源码映射
{
module :{
rules: [...]
},
devtool: 'source-map'
}
- source-map: 会单独生成一个 sourcemap文件,出错会显示行和列
- eval-source-map: 不会单独产生一个文件,可以显示行和列
- cheap-module-source-map: 不会产生列 但会生成一个单独文件 产生后可以保留
- cheap-module-eval-source-map: 不会产生文件,集成在打包后的文件中,只点位行不定位列
常用插件
- cleanWebpackPlugin
- copyWebpackPlugin
- bannerPlugin(内置插件,添加文件前注释)
const cleanWebpackPlugin = require('clean-webpack-plugin');
const copyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack')
plugins: [
new cleanWebpackPlugin(['./dist']),
new copyWebpackPlugin([
{form: './document', to: './dist'}
]),
new webpack.BannerPlugin('author: blue')
]
devServer 及跨域代理
devServer: {
proxy: {
'/api': {
target: 'http://xxx.xxx',
pathRewrite: {
'/api': '/'
}
}
}
}
devServer 其他配置
devServer: {
before(app){ // app 即 express 的 app 此处可以代表mock数据
app.get('/user', (req,res) => {
res.json({status:true,data:[1,2,3]})
})
}
}
另外如果服务端为 node服务,可以 服务端启动webpack 避免跨域问题 使用 webpack-dev-middleware
const app = express();
const config = require('./webpack.config.js')
const middle = require('webpack-dev-middleware')
const compiler = webpack(config);
app.use(middle(compiler))
....
app.listen(3000)
resolve配置
resolve: {
extensions: ['.js','.json','.jsx','.css'], //省略扩展名
modules: [path.resolve('node_modules')], //只在被目录下的 node_modules中查找模块
alias: { // 别名
vue: 'vue/dist/vue.rutime.js',
bootstrap: 'bootstrap/dist/css/bootstrap.css'
},
mainFields: ['style','main'], //优先加载 package.json 中的key中的路径
mainFiles: [], //package.json中入口文件路径 默认 main: index.js
}
wepack优化 noParse
module: {
noParse: /jquery/, //不解析 jquery 模块中的依赖(减少解析时间)
rules: [
{test: /.js$/}
]
}
webpack优化 exclude include
module:{
rules: [
{
test: /.js$/,
exclude: /node_modules/,
include: path.reslove(__dirname,'src')
}
]
}
webpack优化 webpack.IngorePlugin
plugins: [
// 忽略掉在 node_modules/moment模块中 正则匹配./locale/ 引入的相关模块
new webpack.IgnorePlugin(/\.\/locale/,/moment/),
]
webpack优化 webpack.DllPlugin
内置模块 将一些库单独打包 如 vue,react,react-dom,jquery,loadsh等,单独打包到一个文件,只打包业务代码,减少打包时间
//webpack.libs.js 公共库单独抽离打包
const path = require('path')
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
common: ['moment','vue','loadsh','jquery','react','react-dom']
},
output: {
filename: '_dll_[name].js',
path: path.resolve(__dirname,'dist'),
library: '_dll_[name]',
libraryTarget: 'umd' //取值有 umd commonjs var 等
},
plugins: [
new webpack.IgnorePlugin(/\.\/locale/,/moment/),
new webpack.DllPlugin({
name: '_dll_[name]',
path: path.resolve(__dirname,'dist','manifest.json')
})
]
}
//webpack.config.js 项目打包配置
{
...
plugins: [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname,'dist','manifest.json')
}),
]
}
另外需要在 html模板文件中手动添加最后打包的公共库
<script src="_dll_common.js"></script>
webpack优化 happypack 多线程打包
const Happypack = require('happypack')
rules: [
{
test: /.js$/,
exclude: /node_modules/,
include: path.reslove(__dirname,'src'),
use: 'Happypack/loader?id=aaa'
},
{
test: /.css$/,
exclude: /node_modules/,
include: path.reslove(__dirname,'src'),
use: 'Happypack/loader?id=bbb'
}
],
plugins: [
new Happypack({
id: 'aaa',
use: [
loader: 'babel-loader',
options: {
...
}
]
}),
new Happypack({
id: 'bbb',
use: ['style-loader','css-loader']
})
]
webpack自带优化 tree-shaking, scope hosting
tree-shaking 只加载用的的代码 scope-hosting 作用域提升,会自动省略一些可以简化的代码
webpack 抽取公共代码(多入口文件代码公共部分抽离)
注意与 dllplugin的区别,针对多入口提取公共代码
{
...
optimization: {
splitChunks: { //代码分割
cacheGroups: { //抽离缓存组
common: { //业务中公共模块抽离 名字为common
chunks: 'initial', // 三个值 initial 打包开始时 async 异步引入 all 所有的
minSize: 0, //最小大小
minChunks: 2 //最小引入次数
},
vendor: { //第三方库抽离 名字为 vendor
priority: 1, //权重提升,避免与上面的 common 影响
test: /node_modules/, //通常第三方库位置
chunks: 'initial',
minSize: 0,
minChunks: 2
}
}
},
}
}
webpack 懒加载
依赖插件 @babel/plugin-syntax-dynamic-import
.babelrc
plugins: [
...
"@babel/plugin-syntax-dynamic-import"
]
实例代码
button.addEventListener('click',()=>{
import('./async-a').then(res => {
console.log(res);
})
});
webpack 热更新
devServer: {
...
hot: true
},
plugins: [
...
new webpack.HotModuleReplacementPlugin(),
]
入口文件添加下面代码
if (module.hot) {
module.hot.accept()
}