老司机直接×
都是经验之谈
一.安装
安装webpack工具
npm install webpack -D
npm install webpack-cli -D
-D/--save-dev 开发依赖
-S/--save 运行依赖
二.多入口
entry:{ // 对象方式--多入口
homepage:"./src/homepage.js",
list:"./src/list.js"
...
}
output:{ //使用占位符,path必须是绝对路径
filename:[name].js,
path:path.resolve(__dirname,"dist")
}
使用 npx webpack 命令进行测试
成功生成构建好的目录
然而每次构建 目录不会清除
因此引入 clean-webpack-plugin
npm install clean-webpack-plugin
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
plugins: [new CleanWebpackPlugin()]
}
使用插件生成html 模版 需考虑多页应用
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const pageConfig = {
homepage: "./src/js/homepage.js",
list: "./src/js/list.js",
};
module.exports = {
entry: pageConfig,
output: {
filename: "[name]_[contenthash:8].js",
path: path.resolve(__dirname, "dist"),
},
plugins: [
new HtmlWebpackPlugin({
filename: "homepage.html",
template: path.resolve(__dirname, "src/html/homepage.html"),
chunks: ["homepage"],
}),
new HtmlWebpackPlugin({
filename: "list.html",
template: path.resolve(__dirname, "src/html/list.html"),
chunks: ["list"],
}),
],
};
有几个入口就有几个出口,有几个出口就有几个HtmlWebpackPlugin
三.处理多种格式
1.css/scss
npm install style-loader --save-dev
npm install css-loader --save-dev
npm install sass-loader sass --save-dev
module.exports = {
...
module: {
rules: [
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
],
},
...
}
使用多个loader 从右到左,先使用sass-loader 在使用css-loader,最后使用style-loader
关于正则
"\": 转义字符
".": 特殊字符
"\.": 表示"."
"|" :表示或者
增加兼容前缀
npm install --save-dev postcss-loader postcss
npm install --save-dev postcss-preset-env
新建 postcss.config.js postcss-loader会自动寻找这个配置文件
postcss.config.js
module.exports = {
plugins: [
[
"postcss-preset-env",
{
// Options
},
],
],
};
postcss-preset-env使用browserslist来配置目标环境 postcss-preset-env集成了autoprefixer
mini-css-extract-plugin
提取css,创建单独的css文件 安装
npm i mini-css-extract-plugin -D
在webpack.config.js中
const MiniCssExtractPlugin=require("mini-css-extract-plugin")
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(css|scss)$/, // \:转移字符 .:特殊字符 \. 表示.
use: [
{
loader:MiniCssExtractPlugin.loader,
options:{
publicPath:'../' //因为生成的css文件在css目录中(下面filename中配置),css文件中的代码找到其他资源则需要向上跳出一个目录
}
}, "css-loader", "postcss-loader", "sass-loader"],
},
...
]
]
plugins: [
...
new MiniCssExtractPlugin({
filename: "css/[name][contenthash:8].css" //打包后css文件在css目录中
}),
...
]
...
}
mini-css-extract-plugin有自己的loader
2.js/es6
npm i babel-loader @babel/core @babel/preset-env -D
- babel-loader是webpack 与 babel的通信桥梁梁,
- @babel/preset-env 把es6转成es5
module: {
rules: [
{
test:/\.js$/,
use:{
loader:"babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
}
],
},
还需要使用 @babel/polyfill 处理es新特性特有的方法,相当于用老方式实现新特性并挂载到全局变量中(语法糖)
npm install --save @babel/polyfill
在需要使用的polyfill的文件上 使用import "@babel/polyfill" 引入polyfill 此时会把 polyfill库完全打包到出口js,生成的js会非常大,因此使用按需引入的方式,之后生成的js会减小很多
删除import “@babel/polyfill” 在配置中增加
{
test:/\.js$/,
exclude: /node_modules/,
use:{
loader:"babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
corejs: 2,
useBuiltIns: "usage"
}
]
]
}
}
}
注意presets:[[]] 在新的方案中已经废弃了polyfill 使用 import "core-js/stable"; import "regenerator-runtime/runtime"; 代替 同时配置应改为 corejs:3 注意 core-js 和 regenerator-runtime 需要安装
参考 babel7 全套 @ babel / polyfill
将babel-loader的配置放入单独的文件
.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"corejs": 3,
"useBuiltIns": "usage"
}
]
]
}
配置修改为
{
test:/\.js$/,
exclude: /node_modules/,
loader:"babel-loader"
}
3.图片资源(包括字体)
直接图片资源
使用url-loader 包括file-loader同时可以将图片转base64 安装:
npm install url-loader -D
在入口js中 import “../css/homepage.css" 在homepage.css 中 使用background引入png , npx webpack 后报错 找不到对应loader。
由此可知不管有没有使用样式,通过入口文件引入的module/文件 都需要有loader进行处理。webpack默认只能处理js
{
test:/\.(png|jpe?g|gif)$/,
use:[
{
loader:"url-loader",
options: {
name: "[name]_[contenthash:8].[ext]",
outputPath: "images/", //生成后存放的路径
limit: 10000 //1024为1kb 小于10000(8kb),才转换成base64
}
}
]
}
此时会报错 Error: Cannot find module 'file-loader' url-loader内部会使用file-loader 补充安装 npm i file-loader -D
iconfont图标
- Symbol
第一步:引入项目下面生成的 symbol 代码:
<script src="./iconfont.js"></script>
第二步:加入通用 CSS 代码(引入一次就行):
<style>
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
第三步:挑选相应图标并获取类名,应用于页面html:
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-xxx"></use></svg>
iconfont.js处理svg不需要使用loader进行处理 如果入口js中使用了 svg文件呢?(todo)
- Font class 、Unicode
在js中引入iconfont.css 同时增加rule
{
test: /\.(eot|ttf|woff|woff2|svg)$/,
use: {
loader:"file-loader",
options:{
name: "[name]_[contenthash:8].[ext]",
outputPath:"font/"
}
}
},
html页面中引入
<span class="iconfont icon-tupian"></span>
此时会将font文件打包到指定位置,同时css中的路径会自动更改
四.webpack-dev-server
webpack-dev-server文档 安装 npm install webpack-dev-server -D
此时调用webpack-dev-server时 报错 Error: Cannot find module 'webpack-cli/bin/config-yargs' 各项版本为 "webpack": "^5.0.0", "webpack-cli": "^4.0.0", "webpack-dev-server": "^3.11.0" 可能webpack-dev-server还没有与最新的webpack-cli兼容 修改版本降级为如下 "webpack": "4.44.2", "webpack-cli": "3.3.12", "webpack-dev-server": "^3.11.0" 成功执行 执行后是查看不了dist目录的,代码在内存中
Proxy 解决跨域使用本地mock
创建本地serve 端口3000 http://localhost:3000/api/homepage
本地项目端口8080 在项目中直接使用
axios.get('http://localhost:3000/api/homepage').then(res=>{
console.log(res)
})
会出现跨域报错 Access to XMLHttpRequest at 'xxx' from origin '###' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
在devServer中配置proxy
module.exports = {
...
devServer: {
contentBase: path.join(__dirname, "dist"),
openPage:"homepage.html",
open:true,
proxy: {
"/api": {
target: "http://localhost:3000"
}
}
},
...
}
再把代码中的 请求前缀去掉 如下
axios.get('/api/homepage').then(res=>{
console.log(res)
})
即可成功获取数据
模块热替换(HMR)
devServer字段 hot:true 开启 hotOnly:true 开启失败也不会刷新浏览器
css 热替换
- 不能使用contenthash和chunkhash会报错
- 使用mini-css-extract-plugin分离后的css不生效
js 热替换(todo)
五.sourceMap
dev模式默认打开 推荐配置 devtool:"cheap-module-eval-source-map",//开发环境配置 //线上不不推荐开启 devtool:"cheap-module-source-map", // 线上⽣生成配置
六.优化配置
在production环境下会自动开启 css/js/html压缩
loader配置
include: path.resolve(__dirname, "./src"),//只在此目录查找处理
resolve
module.exports = {
resolve:{
alias:{
'@':path.resolve(__dirname,"./src") //别名,在编码中 使用@代替快速定位src
},
extensions:['.js'], //扩展名省略的配置
modules: ["node_modules")], //指定第三方库查询路径 否则会向上查询
},
}
externals配置cdn
externals: {
//配置之后可以使用import的方式引入jQuery 同时 在打包时不会打包jquery的库进入项目
'jquery': 'jQuery'
}
七.区分环境配置
1.安装
npm install webpack-merge -D
用来合并配置
const { merge } = require("webpack-merge")
const baseConfig = require("./webpack.base.js") //新建的公共部分配置文件
module.exports = merge(baseConfig,{
})
2.安装
npm install cross-env -D
用来创建一个变量(NODE_ENV)可以使用process.env访问 即process.env.NODE_ENV
cross-env主要解决了追加环境变量不同系统配置时的兼容问题
"build": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.dev.js"
--config 指定webpack的配置文件,默认为webpack.config.js NODE_ENV=production :创建了NODE_ENV的环境变量,在node中可以通过process.env.NODE_ENV 取得其值,为production 因此在代码里面可以添加逻辑
cross-env 和 webpack-merge是无关连的。使用process.env.NODE_ENV也可以使用逻辑代码修改配置文件的导出
之前我进入误区 一直想,有了process.env.NODE_ENV为啥还需要--config 或者webpack-merge都可以省略了。 从实现的角度,的确可以。还是两者结合搭配写配置更容易维护
3.在改完配置后,构建时报了一堆目录错误。因为此时配置文件的位置改变了。
因此理解了path.resolve这个方法。
path.resolve(__dirname,'../src')
第二个参数的路径。相当于在当前位置(代码文件的位置)找到src在项目中的相对路径
此时代码位置 为config/webpack.base.js
找到src则需要 ../src