Ⅰ. 开发环境配置
1. 安装依赖
// js的构建工具都是基于nodejs的 , 安装的依赖都是生产模式
npm i webpack webpack-cli --save-dev
2. module的use数组里面loader执行顺序
下 ==> 上 ( 右 ==> 左 )
3. 处理 css文件
css-loader : 将css文件变成commonjs模块加载到js中, 里面内容是样式字符串
style-loader : 创建style标签 , 将js中的样式资源插入进行, 添加到head标签中
4. 处理scss/less文件
// webpack里面用sass/less要安装相应依赖
npm install --save-dev node-sass sass-loader
npm install --save-dev less less-loader
{
test: /\.less$/,
use: [{ loader: "style-loader" },{ loader: "css-loader" }, { loader: "less-loader" }],
},
5. 处理html资源
html-webpack-plugin插件 (注意 : 不是html-loader)
作用 : 默认会创建一个空的html文件 , 自动引入打包输出的所有资源 (js/css文件等)
// 安装 npm i html-webpack-plugin -D
const HtmlWebpackPlugin = require("html-webpack-plugin")
plugins: [
// 创建一个实例
new HtmlWebpackPlugin({
// 模版 : 将路径中的html文件作为模版复制 , 并添加引入打包输出的所有资源 css/js
template: "./src/index.html",
minify: {
removeComments: true, //清理注释
collapseWhitespace: true, //清理空格
},
})
],
6. 打包图片资源
// 默认使用url-loader , 但仅仅能处理样式中引入的图片资源
url-loader , file-loader (url-loader依赖于file-loader)
// 处理html中的img引入图片 (负责img引入, 从而能被url-loader处理)
html-loader
注意 : url-loader默认使用es6模块化解析, 而html-loader引入图片是commonjs规范 , 解析时候会报错
解决 : 关闭url-loader的es6模块化 , 使用commonjs解析 esModule : false
// loader相关配置
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: "url-loader", //url-loader依赖于file-loader
options: {
limit: 8 * 1024,
/* 图片小于8kb就是用base64的方式
优点: 减少请求数量(减轻服务器压力) 缺点: 图片体积会更大(文件请求速度变慢)
所以一般不对大图片进行base64处理 , 对8-12kb以下的小图片进行base64处理
比如 : 有个9kb的图片 , 就可以设置 10*1024
*/
esModule: false,
name: "[hash:8].[ext]" // 重命名 取到hash值前8位 .[ext] 保留原来的后缀名
}
}
]
},
{
test: /\.html$/,
use: [
{
// 处理html中的img标签图片 (负责img引入, 从而能被url-loader处理)
loader: "html-loader"
}
]
}
// 如果打包后的的html出现 // module 开头的乱码 , 可能是配置了两次 html-loader
// plugin相关配置
const HtmlWebpackPlugin = require("html-webpack-plugin");
plugins: [
// 创建一个实例
new HtmlWebpackPlugin({
// 模版 : 将路径中的html文件作为模版复制 , 并添加引入打包输出的所有资源 css/js
template: "./src/index.html",
// minify: {
// removeComments: true, // 清理注释
// collapseWhitespace: true // 清理空格
// }
})
],
7. 打包其他资源
{
/* 打包其他资源(排除资源,原样输出) */
exclude: /\.(css|js|html)$/,
use:[
{
loader: "file-loader",
options: {
name: "[hash:8].[ext]"
}
}
]
}
8. 开发服务器devServer
webpack-cli4的启动命令 webpack serve
webpack-cli3的启动命令 npx webpack-dev-server
// 作用 : 自动编译 , 自动打开浏览器 , 自动刷新
// 特点 : 只会在内存中编译打包 , 不会有任何输出
// npm i webpack-dev-server -D , 卸载安装webpack-cli指定版本,避免兼容性踩坑
// npm uninstall webpack-cli -D
// npm install webpack-cli@3.3 -D
devServer: {
contentBase: path.resolve(__dirname, "build"), // 打包输出的文件夹
open: true, // 自动打开浏览器
port: 3003, // 端口
compress: true, // gzip压缩代码体积
inline:true // 实时刷新
}
天坑 : 默认启动指令: npx webpack-dev-server 可以在package.json中修改 , 默认指令可能在启动后不能自动刷新 , 还是修改比较好 ( 傻b配置坑过我一晚上)
// 在package.json中配置
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --mode development"
}
// 之后 用npm run dev就能启动devServer
8.1 报错: Cannot find module ‘webpack-cli/bin/config-yargs‘
// webpack最新版和webpack-cli4冲突
// 卸载全局和本地的最新webpack-cli , 安装指定版本
npm uninstall webpack-cli -g
npm uninstall webpack-cli -D
npm install webpack-cli@3.3 -D
npm install webpack-cl3.3 -g
8.2 devServer 不能自动刷新
// 绝壁是在output里配置了publicPath:'./'
// 要么不写 , 要么写成下面
publicPath:"/dist/" // 虚拟路径 , devServer运行时 webpack的虚拟路径
// 这里写的是什么 , 打包后的html文件引入的main.js路径前面就是什么
<script src="/dist/js/main.js"></script></body>
9. 各种打包报错
报错 1 : Cannot find module 'webpack-cli/bin/config-yargs'
webpack-cli版本冲突了
先把webpack-cli卸载,再安装执行npm install webpack-cli@3 -D
报错 2 : 打包后控制台报错Refused to apply style from 'http://localhost:7099/iconfont/iconfont.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
// 在devServer的配置中加入 publicPath:'./'
devServer: {
contentBase: path.join(__dirname, "build"), // 项目构建打包输出的路径
compress: true, // 启动gzip压缩 , 代码体积更小
open: true, // 自动打开浏览器
port: 7099,
publicPath:'./'
}
报错 3 : document is not defined
webpack://guigu_webpack/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?:93
var style = document.createElement('style');
解决方案: src中的index.html文件引入了css样式 , 或者main.js入口文件 , 删掉即可
报错 4. Automatic publicPath is not supported in this browser
// 输出配置output里面加上
publicPath:'./'
报错5. 打包后背景图片不显示
// 使用 mini-css-extract-plugin插件单独提取css后背景图不显示, 在options里加 publicPath: '../'
{
loader: MiniCssExtractPlugin.loader,
options:{
publicPath: '../'
}
}
// 加在处理css/scss/less的配置中 , 不是加在处理img的配置中 , 我是傻逼
报错6. export default webpack_public_path + "others/e86c5939.less";
打包其他文件时 , 没有把对应文件的格式排除
10. 配置文件打包输出的路径
// loader配置outputPath输出到文件夹
1. css/less/scss的输出路径不需要配置文件夹路径 , 因为能打包进 build.js文件 ,不然报错
2. html-loader处理html中img标签引入的图片资源时 , 不用写outputPath , 不然报错
10.1 傻逼报错 configuration.output has an unknown property 'outputPath'
Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.output has an unknown property 'outputPath'. These properties are valid:
要么是出口output中'path'写成了"outputPath
要么是打包css/scss/less的时候 options里写了outputPath
11. 每次打包前清理build文件夹的目录
// 注意: 尽量别用 ,devServer的时候 , 会把build里的文件都删了 , 但是又不打包输出
// 依赖 clean-webpack-plugin 插件
npm i --save-dev clean-webpack-plugin
// 解构 , 再plugins配置里调用
// 注意是解构 , 不是直接引用
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
// 每次打包前清除一遍build目录下的文件夹
// 在最新版的webpack中 ( )中不需要写里面的目标路径,会自动清除生成的文件夹,比如是build文件夹
new CleanWebpackPlugin()
Ⅱ. 处理兼容和压缩
1. css相关处理
1.1 提取css到单独文件
// mini-css-extract-plugin 插件
// 将CSS提取为独立的文件的插件,对每个包含css的js文件都会创建一个CSS文件,支持按需加载css和sourceMap
npm i mini-css-extract-plugin -D
MiniCssExtractPlugin.loader 取代 style-loader , 提取 js中打包的各个css文件整合成单独文件 , 就不需要插入style标签中了
// 如果less/scss/css 样式都有的话 , 就得每个loader配置里面都替换
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
use: [
// { loader: "style-loader" },
{ loader: MiniCssExtractPlugin.loader }, // 注意不要写成了字符串
{ loader: "css-loader" },
{ loader: "sass-loader" }
]
// 在plugins中
new MiniCssExtractPlugin({
filename: "css/build.css" // 配置单独提取出来的css文件的路径以及名字
})
1.2 css兼容处理及压缩
// 需要安装 postcss-loader postcss-preset-env
/*
css兼容性处理:postcss --> postcss-loader postcss-preset-env
帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
"browserslist": {
// 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
// 生产环境:默认是看生产环境
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
*/
- 新建postcss.config.js 配置文件
```js
module.exports = {
plugins: [
// 使用postcss插件
require("postcss-preset-env")
]
};
-
在package.json中写browserslist的配置
"browserslist": { "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ], "production": [ ">0.2%", "not dead", "not op_mini all" ] }
-
默认是看生产模式的browserslist配置 , 如果要改成开发模式 , 要设置nodejs环境变量
// 设置nodejs环境变量 process.env.NODE_ENV = 'development';
-
完整代码
{ test: /\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader' ] }
-
压缩css及其简单
// 安装 optimize-css-assets-webpack-plugin , 然后直接在plugins里配置调用即可 npm i optimize-css-assets-webpack-plugin -D const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); // plugins里配置调用即可 new OptimizeCssAssetsWebpackPlugin();
项目上线前记得要压缩css代码
1.3 less/sass的兼容处理
/*
postcss-loader 不能处理less/sass代码
和css处理相同 , 只是要把postcss-loader , 放在 less-loader 和 css-loader中间 , 执行顺序 less-loader先转换成css , 再处理兼容
*/
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader', 'postcss-loader','less-loader'
]
}
1.4 复用 loader 处理css/sass/less兼容
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader', 'postcss-loader'
]
// 代替前面重复代码
2. js语法检查 -- eslint
// 1. 注意 eslint只检查自己写的代码 ,第三方的库是不用检查的 , 所以要排除node_modules里的模块
// 2. 设置检查规则 , 在package.json中写eslintConfig 配置 , 继承airbnb-base的配置
/*
"eslintConfig": {
"root":true,
"extends": "airbnb-base"
}
*/
npm i eslint eslint-loader eslint-config-airbnb-base eslint-plugin-import -D
// eslint-config-airbnb-base 不包含react的插件
-
代码 :
// 开发调式时候忽略下一行的eslint检查 , 上线时候注意删掉 // eslint-disable-next-line // loader如下配置 { test: /\.js$/, exclude: /node_modules/, // 一定要排除, 不检查node_modules里的模块 loader: "eslint-loader", options: { // 自动修复eslint的错误 fix: true } } // package.json中如下配置 "eslintConfig": { "root":true, "extends": "airbnb-base" }
###### 2.1 报错 : Failed to load config "airbnb-base" to extend from.
![image-20201021202722429](C:\Users\Jiraiya\AppData\Roaming\Typora\typora-user-images\image-20201021202722429.png)
```js
// 解决方法
在上面eslintConfig的配置中忘加 "root":true
3. js兼容性处理 -- babel
推荐第三种方法 : 按需解决兼容
3.1 基础js兼容处理
// 使用 babel-loader @babel/preset-env @babel/core
npm i babel-loader @babel/preset-env @babel/core -D
// js兼容性处理
{
test: /\.js$/,
exclude: /node_modules/, // 一定要排除, 不检查node_modules里的模块
use: [
{
loader: "babel-loader",
options: {
// 预设: 指示babel做怎么样的兼容处理
presets: ["@babel/preset-env"]
}
}
]
}
```
3.2 全部 js兼容处理
// 极其简单 安装 @babel/polyfill 并引入即可
npm i @babel/polyfill -D
import '@babel/polyfill'
3.3 按需解决兼容
npm i core-js babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
// 使用此方案 , 就不能再用第二种方案的引入了
{
test: /\.js$/,
exclude: /node_modules/, // 一定要排除, 不检查node_modules里的模块
use: [
{
loader: "babel-loader",
options: {
// 预设: 指示babel做怎么样的兼容处理
presets: [
[
"@babel/preset-env",
{
// 按需加载
useBuiltIns: "entry",
// 指定corejs版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: "60",
firefox: "60",
ie: "9",
safari: "10",
edge: "17"
}
}
]
],
plugins: ["@babel/plugin-transform-runtime"]
}
}
]
}
4. eslint-loader和babel-loader执行顺序
/*
正常来讲, 一个文件只能被一个loader来处理.
当一个文件要被多个loader处理的话 , 那么一定要指定loader的执行顺序: 先执行eslint , 后babel
给eslint-loader加上 enforce: 'pre' 属性
*/
{
test: /\.js$/,
exclude: /node_modules/, // 一定要排除, 不检查node_modules里的模块
enforce: 'pre' , // 优先执行, 其他loader都往后稍稍
loader: "eslint-loader",
options: {
// 自动修复eslint的错误
fix: true
}
}
5. js和html的压缩
// js
改成production模式就能自动压缩js
// html
new HtmlWebpackPlugin({
// 模版 : 将路径中的html文件作为模版复制 , 并添加引入打包输出的所有资源 css/js
template: "./src/index.html",
minify: {
removeComments: true, // 清理注释
collapseWhitespace: true // 清理空格
}
})
Ⅲ. Webpack性能优化 (重点)
1. 开发环境性能优化
优化点 : 1.打包构建速度 2.代码调试
1.1 热模块替换 (HMR)
hot: true
-
样式文件 : 默认可以使用HMR功能 , 因为style-loader内部实现了 , 所以开发环境可以用style-loader方便调式 , 生产环境就得把css文件单独提取出来再上线 , 不能使用style-loader
-
js 文件 : 默认不能使用HMR功能 --> 需要添加支持HMR的代码
```js
// 首先要知道入口js文件是没办法做HMR优化的 , 入口文件js代码一旦改变,所有文件都会重新加载 // 添加代码如下 : if(module.hot){ // 一旦module.hot为true, 说明开启了HMR功能 ==> 让HMR功能代码生效 module.hot.accept("./print.js",function(){ // 方法会监听print.js文件的变化 , 一旦变化,其他模块不会重新打包构建 // 会执行callback print(); }) } ```
-
html 文件 : 默认不能使用HMR功能 , 同时会导致问题 , html文件不能热更新了~ (不用做HMR功能)
解决:修改entry入口, 将html文件引入
1.2. source-map
devtool:'source-map'
//
- source-map : 1.内部 2.提示错误代码准确信息 和 源代码的错误位置
- inline-source-map : 1.只生成一个内联的source-map 2.同上 hidden-source-map : 1.外部生成 2.不能追踪源代码错误 .只能提示到构建后代码的错误位置
- eval--source-map : 1.内部 每一个文件都生成对应的source-map 2.提示错误代码准确信息 和 源代码的错误位置
- nosource-source-map : 1.生成外部 2.错误代码准确信息,但是没有任何源代码信息
- cheap-source-map : 1.生成外部 2.提示错误代码准确信息 和 源代码的错误位置 ,但只能精确到行, 不能精确到列
- cheap-module--source-map : 1.生成外部 2. 同上 3. module会把loader的source map加进来
// 外部和内联的区别 : 1.外部生成了文件,内联没有 2.内联构建的速度更快
以上几种方案用法 :
-
开发环境要求 : 速度快 , 调试更友好
---> eva-source-map / eval-cheap-module-source-map
-
生产环境要求 : 源代码要不要隐藏 ? 调试要不要更友好 ?
内联会让代码体积变大 , 所以一般不用内联
---> source-map / cheap-module--source-map
如果需要隐藏源代码 , 就 nosource-source-map( 全部隐藏 ) / hidden-source-map( 只隐藏源代码, 会提示构建后代码错误信息 )
2. 生产环境性能优化
优化点 : 1.打包构建速度 2.代码运行性能
2.1 oneOf
oneOf数组里的loader规则: 只会匹配一个 , 比如css文件匹配到css-loader以后 , 就不会在去查询匹配其他loader了 , 性能就更好
注意 : 数组里不能有两个loader处理同一种类型文件 , 比如eslint-loader , babel-loader不能同时放在里面 , 把eslint-loader提取到外面
2.2 缓存
-
babel缓存
cacheDirectory: true
-
文件资源缓存
hash 值命名后缀
问题 : 因为 js和css构建时候生成唯一一个hash值 , 如果重新打包会使缓存失效
chunkhash: 根据chunk生成的hahs值 . 如果打包来源同一个chunk , 那么hash值就一样
contenthash:
Ⅳ. Webpack补充详解
1. entry 多入口
-
array : 只会形成一个chunk和一个bundle.js
- 作用 : 只有在HMR功能中html热更新生效
-
object : 有几个入口文件就形成几个chunk , 输出几个bundle文件 ,此时的chunk名称就是 key
entry: { a: "./src/test.js", // 生成a.js b: "./src/index.js" // 生成b.js },
- 特殊用法 : 对象的value可以是一个数组 , 包含多个文件路径 , 将多个文件打包输出一个bundle
2. output
filename: 'js/[name].js' // 指定名称 + 目录
publicPath:'/' // 所有资源引入的公共路径前缀
chunkFilename: '[name]_chunk.js' // 对非入口chunk进行重命名
library: '[name]' // 将打包后的js文件代码赋值给一个变量并抛出(变量名就是[]中的name)
libraryTarget: 'window' // 变量名添加到哪个上
3. loader
exclude: /node_modules/ // 排除
include: path.resolve(__dirname,'src') // 只检查src文件夹
enforce: 'pre' // 优先执行 , post -> 最后执行 , 其他就中间执行
4. resolve
resolve: {
// 配置路径别名 , 简写路径 比如 src --> @
alias: {
$css: path.resolve(__dirname,'src/css')
},
// 配置省略文件路径的后缀名
extensions: ['.js','.json'],
// 直接告诉 webpack去哪个目录找解析模块
modules: [path.resolve(__dirname,'../../node_modules'),"node_modules"]
}
5. devServer
watchContentBase: true, // 监视contentBase下的文件 , 一旦变动就reload
watchOptions:{
ignored: /node_modules/ // 忽略文件
},
clientLoginLevel: 'none', // 不显示启动服务器日志信息
quiet: true , // 除了一些基本启动信息以外 , 其他内容都不要显示
overlay: false, // 如果出错了不要全屏提示
proxy:{ // 反向代理
'/api':{
// 一旦devServer接收到'/api'开头的请求,就把请求转发到如下服务器
target: 'http://localhost:3000',
// 发送请求时 , 请求路径重写 : 将'/api/xxx' --> '/xxx'
pathRewrite: {
'^/api':''
}
}
}
6. opnimization
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!