常用配置
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin') // 提供 html 模板
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') // 查看打包后模块依赖关系
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin') // 提高打包构建速度 第一次缓存 第二次速度提升
const OptimizeCssWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 压缩css
// 去掉多余 css
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const glob = require('glob')
// 查看打包
const speedMeasureWebpackPlugin = require('speed-measure-webpack-plugin') // 记录打包各个模块时间
const smw = new speedMeasureWebpackPlugin()
smp.wrap({/*包裹整个配置对象*/})
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 提取 css 为单独文件
const {CleanWebpackPlugin} = require('clean-webpack-plugin') // 每次打包 清理 dist 目录
const HappyPack = require('happypack')
const webpack = require('webpack')
module.exports = {
mode: 'development',// development
entry: './src/index.js', // 每个 entry 产出一个 chunk
// entry: { // 多页面打包
// index: './src/index.js',
// cart: './src/cart.js'
// },
},
output: {
// publicPath: 'https://www.baidu.com', // 也可以单独给某个资源添加前缀
filename: '[name].[hash:8].js',
path: path.resolve('./dist')
},
devServer: {
// 运行代码的目录
contentBase: path.resolve(__dirname, './dist'),
// 监视 contentBase 目录下的所有文件,一旦文件变化就会 reload
watchContentBase: true,
watchOptions: {
// 忽略文件
ignored: /node_modules/
},
// 启动 gzip 压缩
compress: true,
// 端口号
port: 5000,
// 域名
host: 'localhost',
// 自动打开浏览器
open: true,
// 开启 HMR 功能
hot: true,
// 不要显示启动服务器日志信息
clientLogLevel: 'none',
// 除了一些基本启动信息以外,其他内容都不要显示
quiet: true,
// 如果出错了,不要全屏提示~
overlay: false,
before(app) { // 可不用代理提供响应内容
app.get('/api/user', (req, res) => {
res.send({a: 1})
})
}
// 服务器代理 --> 解决开发环境跨域问题
proxy: {
// 一旦 devServer(5000)服务器接受到 /api/xxx 的请求,就会把请求转发到另外一个服务器 (3000)
'/api': {
target: 'http://localhost:3000',
// 发送请求时,请求路径重写:将 /api/xxx --> /xxx (去掉/api)
pathRewrite: { '^/api': '' }
}
}
},
// 解析模块的规则
resolve: {
// 配置解析模块路径别名: 优点简写路径 缺点路径没有提示
alias: { '@': path.resolve('src'), },
// 配置省略文件路径的后缀名
extensions: ['.js', '.json', '.jsx', '.css'],
// 告诉 webpack 解析模块是去找哪个目录
modules: ['./node_modules']
},
module: {
noParse: [/jquery/], // 不去解析 jquery 中的依赖库
rules: [
// {
// test: require.resolve('jquery'),
// loader: 'expose-loader', // 把 变量 暴露到全局
// options: {
// exposes: ['$', 'jQuery'],
// },
// },
{
test: /\.html$/, // 解析 html 中的图片
use: 'html-loader'
},
{
test: /\.(png|gif|jpg)$/,
use: {
loader: 'url-loader',
options: {
// 图片大小小于 8kb,就会被 base64 处理 // 优点: 减少请求数量(减轻服务器压力) // 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024,
esModule: false, // 问题:因为 url-loader 默认使用 es6 模块化解析,而 html-loader 引入图片是 commonjs // 解析时会出问题:[object Module] // 解决:关闭 url-loader 的 es6 模块化,使用 commonjs 解析
name: '[hash:10].[ext]', // 给图片进行重命名 [hash:10]取图片的 hash 的前 10 位 [ext]取文件原来扩展名
outputPath: '/image/',
publicPath: 'https://www.baidu.com' // 给图片加上公共路径
}
},
},
{
test: /\.css$/,
use: [{
loader: 'style-loader',
options: {
insert: 'top' // 插入到 html style 的下面
}
}, 'css-loader']
},
{
test: /\.less$/,
use: [{
loader: MiniCssExtractPlugin.loader, // 可抽离出来复用到 css 配置项
options: {
insert: 'top' // 插入到 html style 的下面
}
}, 'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => {
require('postcss-preset-env')()
}
}
},
'less-loader']
},
{
test: /\.js$/,
include: path.resolve(__dirname, './src'),
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: { // 用 babel-loader 需要把 es6 转换成 es5
// 插件集合 只会转换语法 箭头函数, const
// presets: ['@babel/preset-env', ],
presets: [['@babel/preset-env', {
// 按需加载
useBuiltIns: 'usage',
// 制定 core-js的版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本的浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}], ['@babel/react']], // react 预设
plugins: [
['@babel/plugin-proposal-decorators', { 'legacy': true }] // 配置装饰器
]
}
}
},
// {
// test: /\.js$/,
// exclude: /node_modules/,
// use: [
// {
// loader: 'eslint-loader',
// options: {
// enforce: 'pre', // previous 之前, post 之后, 默认 loader 从下到上从右到左执行
// fix: true // 自动修复
// }
// }
// ]
// }
]
},
opimization: {
usedExports: true, // tree shaking 生产模式 默认开启
splitChunks: {
chunks: 'all',// 支持同步引入模块也支持异步
minChunks: 1 // 最少1个 chunk引入了该模块
}
},
plugins: [
new HardSourceWebpackPlugin(),
new BundleAnalyzerPlugin(),
new PurgeCSSPlugin({ // 摇树 css
paths: glob.sync(`./src/**/*`, { nodir: true }),
}),
new webpack.hotModuleReplacementPlugin() // 开启热更新 需要 指定热更新位置
// if (module.hot) { // js 文件中 使用
// module.hot.accept('./main.js', () => {
// require('./main.js')
// // TODO
// })
// }
// if (module.hot) {
// module.hot.accept()
// }
new webpack.IgnorePlugin(/\.\/locale/, /moment/), // 忽略引入内容
new webpack.DefinePlugin({ // 定义全局变量
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.BannerPlugin('by Misdirection'), // 定义版权
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// chunk: ['index'] // 多页面打包 配置多个 HtmlWebpackPlugin 引入 entry 的 index 选项的 js 文件
template: './src/index.html',
filename: 'index.html',
minify: {
removeAttributeQuotes: true, // 删除双引号
collapseWhitespace: true // 删除空格
},
// chunksSortMode: 'manual' // 按照 chunks 的顺序 排序引入页面
hash: true
}),
new MiniCssExtractPlugin({
filename: 'css/build.[hash:8].css'
}),
new OptimizeCssWebpackPlugin(), // 生产环境下才会压缩
// new webpack.ProvidePlugin({ // 把 jquery 注入到每个模块
// $: 'jquery'
// })
],
// 构建单吗后监听文件是否变化重新打包
// watch: true,
// watchOptions: {
// pool: 1000, // 1s 询问一次
// aggregateTimeout: 1000 // 用来防抖
// },
externals: {
jquery: '$'
}
devtool: 'source-map'
}
source-map
通过 sourceMappingURL=bundle.js.map 映射源文件
source-map.png
项目依赖
{
"name": "new-webpack",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"dev": "webpack-dev-server --config ./webpack.config.js",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.10.4",
"@babel/plugin-proposal-decorators": "^7.10.4",
"@babel/polyfill": "^7.10.4",
"@babel/preset-env": "^7.10.4",
"@babel/preset-react": "^7.10.4",
"babel-loader": "^8.1.0",
"clean-webpack-plugin": "^3.0.0",
"core-js": "^3.6.5",
"css-loader": "^3.6.0",
"eslint": "^7.4.0",
"eslint-loader": "^4.0.2",
"expose-loader": "^1.0.0",
"file-loader": "^6.0.0",
"happypack": "^5.0.1",
"html-loader": "^1.1.0",
"html-webpack-plugin": "^4.3.0",
"less-loader": "^6.2.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^1.2.1",
"url-loader": "^4.1.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.0.9"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
"dependencies": {
"@babel/polyfill": "^7.10.4",
"core-js": "^3.6.5",
"jquery": "^3.5.1",
"react": "^16.13.1",
"react-dom": "^16.13.1"
}
}
环境分离
webpack.prod.js
const base = require('./webpack.base')
const { merge } = require('webpack-merge')
module.exports = merge(base, {
mode: 'production'
})
webpack.dev.js
const base = require('./webpack.base')
const { merge } = require('webpack-merge')
module.exports = merge(base, {
mode: 'development'
})
webpack.base.js
const {resolve} = require('path')
module.exports ={
entry: './src/index.js',
output: {
filename: 'index.js',
path: resolve(__dirname, './dist')
}
}
优化配置
module: {
noParse: [/jquery/], // 不去解析 jquery 中的依赖库
{
test: /\.js$/,
exclude: /node_modules/ // 不打包 node_modules 中的文件
}
},
externals: {
jquery: '$' // 不去打包 jquery, 需要自己 cdn 引入资源
},
plugins: [
new webpack.IgnorePlugin(/\.\/locale/, /moment/), // 忽略引入的 locale
]
动态连接库
webpack.config.react.js
加快打包速度,将不会变的第三方模块先进行打包,通过 webpackReferencePlugin 引用
const path = require('path')
const webpack = require('webpack')
module.exports = {
mode: 'development',
entry: {
// react 为生成的文件 name
react: ['react', 'react-dom']
},
output: {
filename: '_dll_[name].js',
path: path.resolve(__dirname, './dist'),
library: '_dll_[name]',
libraryTarget: 'var' // commonjs umd
},
plugins: [
new webpack.DllPlugin({ // name = libraryname
name: '_dll_[name]', // 和 library 名字一致
path: path.resolve(__dirname, './dist', 'manifest.json')
})
]
}
webpack.config.js
plugins: [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist', 'manifest.json')
}),
]
hanppypack
多线程打包
module: {
rules: [
{
test: /\.css$/,
use: 'HappyPack/loader?id=css'
},
]
}
plugins: [
new HappyPack({
id: 'css',
use: [{
loader: 'style-loader',
options: {
insert: 'top' // 插入到 html style 的下面
}
}, 'css-loader'
]
})
]
懒加载
import React from 'react'
import ReactDom from 'react-dom'
function App () {
function click() {
import('./other').then(res => {
console.log(res.default)
})
}
return (
<div>
<button onClick={click}>点击</button>
</div>
)
}
ReactDom.render(<App/>, document.querySelector('#root'))
环境配置
{
"build": "webpack --env=production --config ./webpack.config.js",
"test:dev" : "webpack --env.ss ./webpack.config.js",
"env" : "cross-env NODE_ENV=development webpack --config ./webpack.config.js"
}
// 1.
module.exports = (env) => {
console.log(env) // production
}
// 2.
module.exports = (env) => {
console.log(env) // {ss: true}
}
// 3.
console.log(process.env.NODE_ENV) // production