-
设置webpack模式的几种方法
- npx webpack --mode=development (mode的优先级高于env)
- npx webpack --env=development
// webpack.config.js
module.exports = (env) => {
return {
mode: env
//....
}
}
以上两种方式只会影响模块内的环境变量(也不会影响plugin、loader内的环境变量)
3. npx cross-env NODE_ENV=development webpack
cross-env用于设置环境变量(兼容windows和mac)
这种方式是设置当前node的环境变量
-
执行webpack打包
// 1. 使用默认配置
// npm install webpack webpack-cli -D
// npx webpack
// 2. 自定义配置(webpack.config.js)
const path = require('path')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build') // 必须是绝对路径
}
}
// npx webpack --config webpack.config.js
-
webpack创建静态服务 – webpack-dev-server
// npm install webpack-dev-server -D
// 在webpack.config.js中配置devServer
// 开发服务器的配置 -- 使用的是内存中打包后的文件
const devServer = {
port: 3000,
static: { // webpack5使用static,不再使用contentBase
directory: path.join(__dirname, 'build') // 静态文件目录(如果你还有一些没有参与打包的静态文件也需要作为开发服务器的资源被访问,那你就需要额外通过配置“告诉” webpack-dev-server)
},
open: true, // 自动打开页面
compress: true // 启用gzip压缩
}
-
将js文件引入模板html – html-webpack-plugin
plugins = [
// 把打包后的js文件引入模板html
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src/index.html'),
filename: 'index.html',
minify: {
collapseWhitespace: true, // 去掉换行
removeAttributeQuotes: true // 删除双引号
},
hash: true
})
]
-
解析less – less-loader
解析css – css-loader (解析@import语法)
生成style标签插入模板 – style-loader
module = {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
options: {
insertAt: 'top'
}
},
'css-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
}
]
}
-
提取css,用link标签引入 – mini-css-extract-plugin
module = {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 使用loader
'css-loader'
]
}
]
}
plugins = [
new MiniCssExtractPlugin({
filename: 'css/main.css' // 输出路径
})
]
-
postcss autoprefixer – 给css3样式添加前缀
module = {
rules: [
{
test: /\.less/,
use: [
'style-loader',
'css-loader',
'less-loader',
'postcss-loader'
]
}
]
}
// 添加postcss.config.js文件 postcss插件会读取这个文件
module.exports = {
plugins: [
require('autoprefixer')({
overrideBrowserslist: [
'last 10 Chrome versions',
'last 5 Firefox versions',
'Safari >= 6',
'ie> 8'
]
})
]
}
-
optimize-css-assets-webpack-plugin – 压缩css
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
optimization = {
minimizer: [
new UglifyjsWebpackPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCssAssetsWebpackPlugin() // 压缩css资源,会导致js资源没有压缩,需要使用uglifyjs压缩js
]
}
-
ES6转ES5 – babel-loader @babel/core @babel/preset-env
module = {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'babel-loader', // es6 -> es5
options: {
presets: ['@babel/preset-env']
}
}
]
}
]
}
-
支持更高级的语法 – npm i @babel/plugin-transform-runtime(支持generator等语法) @babel/runtime @babel/polyfill(支持es7及以上语法) @babel/plugin-proposal-decorators(支持类装饰器语法) -D
module = {
rules: [
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env"],
plugins: [
["@babel/plugin-proposal-decorators", {
legacy: true
}]
"@babel/plugin-transform-runtime"
]
}
}
]
]
}
-
配置代码校验 – eslint eslint-loader
module = {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'eslint-loader',
options: {
enforce: 'pre' // 优先执行 post 延后执行
}
}
]
}
]
}
-
webpack插件
- cleanWebpackPlugin --> 每次重新打包删除之前打包的内容
// npm i clean-webpack-plugin -D
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin('./build') // 打包后的目录
]
}
- copyWebpackPlugin --> 将静态资源拷贝打包到dist目录下
// npm i copy-webpack-plugin -D
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: './doc', // 静态资源目录
to: './' // 打包后的目录(dist)
}
]
})
]
}
- bannerPlugin (webpack内部插件)
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.BannerPlugin('bannerbanner') // 在打包生成的每个文件最前面添加版权标识(bannerbanner)
]
}
-
webpack解决跨域
正向代理: 正向代理代理的对象是客户端(翻墙)
反向代理: 反向代理代理的对象是服务端(nginx) 服反客正
module.exports = {
devServer: {
port: 3000,
static: path.join(__dirname, 'build'),
open: true,
compress: true,
// 1.
proxy: {
// 重写并转发给别的服务器
'/api': {
target: 'http://localhost:5000',
pathRewrite: {
'/api':''
}
}
},
// 2. 模拟数据(废弃,使用setupMiddlewares)
onBeforeSetupMiddleware(devServer){
devServer.app.get('/user', (req, res) => {
res.json({
name: 'before'
})
})
}
}
}
-
- 服务器和web共用一个端口 (在服务器中运行webpack)
const express = require('express');
const webpack = require('webpack');
let middle = require('webpack-dev-middleware'); // npm i webpack-dev-middleware 启动webpack的中间件
const config = require('./webpack.config.js') // 引入webpack配置文件
const compiler = webpack(config)
let app = express();
app.use(middle(compiler))
app.get('/user', (req, res) => {
res.json({
name: 'zwp'
})
})
app.listen(5000)
-
解析resolve
module.exports = {
resolve: {
extensions: ['.js', '.css', '.json'], // 自动匹配后缀名
alias: {
bootstrap: 'bootstrap/dist/css/bootstrap.css' // 路径别名
},
mainFields: [], // 当从npm包中导入模块时,此选项将决定在 package.json 中使用哪个字段导入模块
mainFiles: [], // 解析目录时要使用的文件名
modules: [path.resolve('node_modules')] // 告诉webpack模块解析时应该搜索的目录
}
}
-
环境变量
- 定义环境变量 - DefinePlugin
// 内置插件DefinePlugin
const webpack = require('webpack')
module.exports = {
plugins: [
new webpack.DefinePlugin({
DEV: JSON.stringify('development'),
FLAG: 'true',
EXPRESSION: '1+1' // 使用时会执行字符串
})
]
}
// key会作为全局变量属性
// index.js
console.log(DEV) // development
console.log(FLAG) // true
console.log(EXPRESSION) // 2
- 区分不同的环境
npm i webpack-merge
// webpack.config.base.js
module.exports = {
// 基础配置
}
// webpack.config.prod.js
const {merge} = require('webpack-merge')
const base = require('./webpack.config.js')
module.exports = merge(base, {
mode: 'production'
})
// webpack.config.dev.js
const {merge} = require('webpack-merge')
const base = require('./webpack.config.js')
module.exports = merge(base, {
mode: 'development'
})
-
webpack优化
- noParse --> 不去解析第三方库中的依赖项
module.exports = {
entry: './src/index',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
module: {
noParse: /jquery/, // 不解析项目中import的jquery中的依赖库
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-evn',
'@babel/preset-react'
]
}
}
}
]
}
}
- IgnorePlugin
module.exports = {
plugins: [
// 正则匹配要忽略的引入的文件路径
new webpack.IgnorePlugin({
resourceRegExp: /(\/locale)/
})
]
}
- DllPlugin 动态链接库
- tips: 先将第三方库打包好,生成manifest.json清单文件,在项目中通过DllReferencePlugin在manifest清单文件中动态查找,找不到再打包(ps: 需要手动在模板html文件中将打包好的文件引入)
// webpack.react.js -- 用于打包第三方库
const path = require('path')
const webpack = require('webpack')
module.exports = {
mode: 'production',
entry: {
react: ['react', 'react-dom']
},
output: {
filename: '_dll_[name].js',
path: path.resolve(__dirname,'dist'),
library: '_dll_[name]' // 定义变量名称,将导出的结果赋值给这个变量
// libraryTarget: 'umd' // 模式
},
plugins: [
// 生成清单,可以找到这个动态链接库
new webpack.DllPlugin({
name: '_dll_[name]', // 这里的name要和library保持一致!!
path: path.resolve(__dirname,'dist', 'manifest.json')
})
]
}
// 1. 通过 npx webpack --config webpack.react.js生成打包结果和manifest清单
// 2. 将打包后的js文件手动引入模板index.html文件 <script src="../dist/_dll_react.js"></script>
// 3. 在主项目中通过DllReferencePlugin查找清单
// webpack.config.js
plugins = [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist', 'manifest.json') // 去动态链接库里查找,找不到再进行打包
})
]
- 多线程打包 – happypack
// npm i happypack -D
const HappyPack = require('happypack')
module = {
rules: [
{
test: /\.js$/,
use: 'happypack/loader?id=js'
}
]
}
plugins = [
new HappyPack({
id: 'js',
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: [
// ["@babel/plugin-proposal-decorators", {
// "legacy": true
// }],
"@babel/plugin-transform-runtime"
]
}
}
]
})
]
- webpack自带优化
- 公共代码抽离(多入口多页面)
module.exports = {
optimization: {
// 分割代码块
splitChunks: {
// 缓存组
cacheGroups: {
common: {
chunks: 'initial',
minSize: 0,
minChunks: 2 // 有两个以上的引用就抽离出来
},
vendor: {
priority: 1, // 默认是从上到下执行(不设置优先级,会将第三方库和上面的公共代码打包到一起),这个选项设置为优先执行
test: /node_modules/,
minSize: 0,
minChunks: 2
}
}
}
}
}
- 懒加载 import()
const button = document.createElement('button')
button.innerHTML = '按钮'
document.body.appendChild(button)
button.addEventListener("click", function () {
import('./source').then(data => {
console.log(data)
})
})
- 热更新
devServer = {
hot: true // 默认开启
}