Webpack和打包过程
学习webpack主要是为了了解目前前端开发的整体流程,实际开发中,我们并不需要去手动配置,因为框架的脚手架都已经帮助我们完成了配置
内置模块path
该模块在Webpack中会经常使用
从路径中获取信息
js
const path = require("path");
const pathStr = "D:/Mrzhang/Study/前端/node/code/zc_test/src/index.js";
//获取文件的父文件夹
console.log(path.dirname(pathStr)); //D:/Mrzhang/Study/前端/node/code/zc_test/src
//获取文件名
console.log(path.basename(pathStr)); //index.js
//获取扩展名
console.log(path.extname(pathStr));//.js
将多个路径拼接在一起(相对路径)
js
const path = require("path");
const pathStr1 = "./src/view";
const pathStr2 = "../index.js";
const pathStr3 = "./index.js";
console.log(path.join(pathStr1, pathStr2)); //src\index.js
console.log(path.join(pathStr1, pathStr3)); //src\view\index.js
将多个路径拼接在一起(返回绝对路径)
- 使用 **path.resolve()**方法,进行拼接
- 当遇到 /xxx即为终止的解析,生成绝对路径
- 在 **resolve()**方法中,里面的路径,会从右往左进行解析,直到生成一个绝对路径就会停止
- 在所有 路径都解析完成之后,还没有生成绝对路径,就会使用当前工作目录
- 路径中零长度的path会被忽略
js
const path = require("path");
console.log(path.resolve("/src", "/txt.js")); //在"txt.js"就会停止解析 D:\txt.js
console.log(path.resolve("/src", "./txt.js")); // 在"/src"停止解析,D:\src\txt.js
console.log(path.resolve("/src/view", "../txt.js")); //D:\src\txt.js
认识Webpack
- 官方的解释:Wevpack是一个静态的模块化打包工具,为现代的JS应用程序
- 实际上会将我们编写的代码,打包成静态的资源
- 打包:webpack可以帮助我们进行打包,它是一个打包工具
- 静态:webpack可以将我们的代码打包成静态资源
- **模块化:**webpack默认支持各种模块化开发,ESModule、CommonJS,AMD等
- **现代的:**因为前端的不断发展,面临着各种各样的问题,催生了webpack的出现
Webpack使用前提
webpack的中文官方文档 中文文档
- Webpack的运行是依赖Node环境的,所以电脑上需要右Node环境
Webpack的安装
- webpack的安装目前分为两个:webpack和webpack-cli
- webpack:主要用于代码中使用,通过代码对代码进行打包
- webpack-cli:主要用于命令行中使用,通过命令行对代码进行打包
npm install webpack webpack-cli
进行局部安装,若有需要可以进行全局安装
Webpack配置文件
- 当我们在命令行执行
webpack
命令,Webpack会默认去寻找目录中的 src/index.js文件 - 并将该文件以及该文件引用的其他依赖进行打包,生成 dist文件夹 ,里面包含 main.js
- 而默认的打包行为,不能满足我们的需求,因此,这时候可以在项目目录中创建webpack的配置文件 webpack.config.js
js
const path = require("path");
//导出配置信息
//因为webpack基于node,所以使用CommonJS
module.exports = {
//需要对哪个文件进行打包
entry: "./src/main.js",
//打包后的文件名,文件夹名称以及路径
output: {
filename: "bundle.js",
//这里的path需要使用绝对路径,因此需要使用node中的path模块
path: path.resolve(__dirname, "./dist"),
},
};
-
当我们在命令行输入 npx webpack后
- webpack就会寻找 webpack.config.js中的配置信息,完成代码的打包
-
而每次输入 npx webpack 会很麻烦,因此,我们可以在 package.json 文件中的 scripts属性进行配置
js
"scripts": {
"build":"webpack"
},
- 之后我们就可以通过输入
npm run build
进行文件的打包
css-loader的使用
Webpack默认是可以打包js文件的,但是对于其他文件在默认情况下不能进行打包
因此在打包其他文件的时候,需要用到对应文件的loader
css也不例外
- 首先应当先安装 css-loader
npm install css-loader
- 安装完成后,需要在 webpack.config.js 进行配置
- 目的是告诉webpack在遇到 css文件的时候,使用哪个loader
- 在 module.exports中创建module对象
- 在 module对象中,创建rules规则数组
- 在 rules数组中,创建一个又一个的对象,用于告诉webpack识别什么文件,使用什么loader
- 在 对象中,使用test设置识别的文件,use使用相关loader
- loader有多个内容的时候,是从后往前识别的,先识别后面,再识别前面
js
const path = require("path");
//导出配置信息
//因为webpack基于node,所以使用CommonJS
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
//这里的path需要使用绝对路径,因此需要使用node中的path模块
path: path.resolve(__dirname, "./dist"),
},
//在module设置不同文件的loader
module: {
//因为loader会有很多,所以采用数组的方式
rules: [
{
//告诉webpack匹配什么文件
//在后面使用正则表达式
test: /\.css$/,
//使用什么laoder处理,
//使用数组类型,因为一个文件有可能使用多个loader
//css-loader仅是可以识别css文件,并不能将样式添加进去
//style-loader是将样式添加到元素中
//因为先识别css-loader,所以要写在后面
use: [{ loader: "style-loader" }, { loader: "css-loader" }],
},
],
},
};
对less文件处理
与处理css文件类似
- 首先通过
npm install less-loader
安装less-loader - 之后对 webpack.config.js进行配置
js
const path = require("path");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: [{ loader: "style-loader" }, { loader: "css-loader" }],
},
{
//匹配less文件
test: /\.less$/,
//先对less文件进行解析
//将less文件生成的css进行解析
//最后将样式进行解析
//这是简写
use: ["style-loader", "css-loader", "less-loader"],
},
],
},
};
postcss-loader
这是一个工具,可以通过引入插件的方式,将我们写的css,自动做一个浏览器的适配,注意,需要安装相关插件
- 首先使用
npm install postcss-loader
安装post-loader - 之后在 module中引入 post-loader即可
js
const path = require("path");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: [{ loader: "style-loader" }, { loader: "css-loader" },{loader:"postcss-loader"}],
},
{
//匹配less文件
test: /\.less$/,
//先对less文件进行解析
//将less文件生成的css进行解析
//最后将样式进行解析
//这是简写
use: ["style-loader", "css-loader", "less-loader"],
},
],
},
};
-
但是这样引入,并不能实现 css样式浏览器适配的打包,需要安装其余的插件
-
通过
npm install autoprefixer
安装插件即可 -
之后对 postcss-loader进行配置
js
const path = require("path");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{
loader: "postcss-loader",
//对某个loader进行单独的配置
options: {
//loader中设置使用的插件
postcssOptions: {
plugins: ["autoprefixer"],
},
},
},
],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
],
},
};
-
同时 postcss-loader的配置可以单独使用一个文件
-
创建 postcss.config.js
- 在webpack.config.js使用 **loader:"postcss-loader"**会自动查找 postcss.config.js配置文件
js
module.exports = {
plugis: ["autoprefixer"],
};
//在webpack.config.js文件中,直接使用loader:"postcss-loader"即可
postcss-preset-env
上面我们用到了postcss的一个插件,而postcss-preset-env是将常用的插件集成到了一起
- 此插件,继承了postcss常用的插件,包含上面提到过的 autoprefixer
- 使用
npm install postcss-preset-env
安装插件 - 在 webpack.config.js文件中使用该插件
js
module.exports = {
plugis: ["post-preset-env"],
};
Webpack打包图片
在webpack环境中,每一个文件都是模块,只需要引入模块即可
import testImg from "./img/test.jpg";
基本使用
-
在webpack5之前对图片资源进行打包的时候,是需要安装一些loader的,raw-loader url-loader file-laoder
-
在webpack5之后,我们可以直接使用 **资源模块类型(asset module type)**来替代上面的loader,即不用单独安装以上的loader
-
我们仅需在 webpack.config.js的module属性中完成配置即可
js
const path = require("path");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
},
//对图片资源进行打包设置
{
test: /\.(png|jpe?g|svg)/,
type: "asset",
},
],
},
};
认识 asset module type
-
在上面的配置中,我们设置了type:asset
-
type的类型有以下设置
- **asset/resource:**发送一个单独的文件并导出URL
- 之前通过file-loader实现
- **asset/inline:**导出一个资源的data URI
- 之前通过url-loader实现
- **asset/source:**导出资源的源代码
- 之前通过raw-loader实现
- asset :在导出一个data URI和发送一个单独的文件之间自动选择
- 之前通过url-loader,并且配置资源体积限制实现
- **asset/resource:**发送一个单独的文件并导出URL
-
asset/resource:使用该设置,会将图片打包成单独的单独的文件,放在dist文件夹中,通过url进行引入
- 缺点就是,每一张图片都会进行一次网络请求,图片资源过多的时候,网络请求就会过多
- **asset/inline:**使用该设置,会将图片设置成base64编码的格式,放在 bundle.js 文件中
- 缺点就是,当图片资源过大的时候,会增加bundle.js文件的体积,造成下载资源缓慢
- asset :会根据图片资源的大小,去判断打包成新的文件,还是打包成base64编码格式
- 在 webpack.config.js中进行设置
js
const path = require("path");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
},
//对图片资源进行打包设置
{
test: /\.(png|jpe?g|svg)/,
type: "asset",
//设置多大的图片会进行base64编码
parser: {
dataUrlCondition: {
//单位是byte,60*1024代表60kb
//60kb之前会生成base64编码
//大于60kb会打包成单独的文件
maxSize: 60 * 1024,
},
},
},
],
},
};
对打包资源图片进行重命名
- 在 webpack.config.js中进行设置
- 通过 generator进行设置
js
const path = require("path");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
},
//对图片资源进行打包设置
{
test: /\.(png|jpe?g|svg)/,
type: "asset",
//设置多大的图片会进行base64编码
parser: {
dataUrlCondition: {
maxSize: 60 * 1024,
},
},
generator: {
//占位符
//name:源文件名
//ext:文件名的后缀.png .jpg
//hash:webpack生成的hash
//前面可以加上路径,代表打包之后,放到哪个文件夹中
filename: "img/[name]_[hash][ext]",
},
},
],
},
};
Webpack对js代码的babel处理
我们知道,webpack默认会对js文件进行打包的,但是仅仅是将代码进行压缩以及丑化
并不能将ES5+的代码转换成ES5的代码,保持浏览器的兼容
因此这时候需要用到babel工具
Babel工具
- Babel是一个 **工具链,**主要用于就浏览器或者环境中将 ES5+的代码转换成ES5的代码
- 与 postcss工具类似,可以单独使用,不用借助于Webpack
- 此处主要学习Webpack中的babel设置
- 在webpack中使用
npm install babel-loader
安装Babel工具
Babel预设babel/preset-env
常见的预设有三个env react TypeScript
- 与postcss-loader类似,我们可以单独安装插件进行单独的配置
- 但是随着插件数量的增多,有了预设插件
npm install @babel/preset-env
- 安装完成之后,创建 babel.config.js文件,在里面完成配置
js
module.exports = {
presets: ["@babel/preset-env"],
};
- 在 webpack.config.js中的配置
js
const path = require("path");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
module: {
rules: [
{
//对js文件使用babel-loader工具
test: /\.js/,
//会自动去寻找babel.config.js中的设置
use: ["babel-loader"],
},
{
test: /\.css$/,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
},
//对图片资源进行打包设置
{
test: /\.(png|jpe?g|svg)/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 60 * 1024,
},
},
generator: {
filename: "img/[name]_[hash][ext]",
},
},
],
},
};
Webpack文件路径的解析和配置
- 在我们实际发开中,会引入很多不同的依赖,通过 import/require的方式进行引入
- 而webpack通过 enhanced-resolve模块对我们引入文件的路径进行一个解析
- webpack能够解析三种文件路径
- 绝对路径
- 此种路径不会再做解析
- 相对路径
- 模块路径 (require("vue"))
- 在resolve.modules中指定所有目录的检索模块
- 默认值是["node_modules"],所以默认会从 node_modules中查找相应的文件
- 绝对路径
- 那么怎么区分是文件还是文件夹呢
import {name} from "./until"
import {name} from "./until.js"
- 如果是一个文件:
- 如果文件具有扩展名,则直接打包文件
- 否则,将会使用resolve.extensions选项作为文件扩展名的解析
js
const path = require("path");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
//对文件会自动进行添加后缀
//即我们写出import {name} from "./until"这样的代码,会在until后面自动拼接extensions数组里面的内容
resolve: {
extensions: [".js", ".json", ".jsx", ".vue"],
alias: {
//最好使用绝对路径
//现在 /untils就代表了.src/untils
utils: path.resolve(__dirname, ".src/untils"),
},
},
module: {
rules: [
],
},
};
- 如果是一个文件夹
- 会在文件夹中根据 resolve.mainFiles配置选项中指定的文件顺序查找
- 默认值是 [index]
- 再根据 resolve.extensions解析扩展名
Webpack常见的插件和模式
认识plugin
- 很多人会吧 plugin插件 与 Loader弄混
- Loader是用于特定的模块类型进行转换:如对.css .vue .jsx等文件进行转换
- 而 plugin可以用于更加广泛的任务,比如打包的优化,资源的管理,环境变量的注入等等
CleanWebpackPlugin
当我们修改了代码,重新打包的时候,需要手动的清除dist,再重新打包才是最新的
我们可以借助 CleanWebpackPlugin插件,完成手动清除dist文件夹的操作
-
首先,我们先安装此插件
npm install clean-webpack-plugin -D
-
在 webpack.config.js文件中完成配置即可
js
const path = require("path");
//引入插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
//使用插件
plugins: [new CleanWebpackPlugin()],
resolve: { },
module: {
rules: [],
},
};
HtmlWebpackPlugin
在之前的学习中,当我们打包一个项目,生成的dist文件中并没有html文件,此插件的目的就是自动生成一个html文件
- 首先通过
npm install html-webpack-plugin -D
安装此插件 - 之后再 webpack.config.js 文件中使用此插件
- 此插件可以传入 title (设置html标题)、template(设置使用html的模板)
js
const path = require("path");
//引入插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
//使用插件
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "zhangcheng",
//自己引用模板的路径
// template: "相对路径",
}),
],
resolve: { },
module: {
rules: [],
},
};
DefinePlugin的介绍
此插件已经集成到了 webpack中,因此我们直接引入即可
- 此插件的目的是,在打包代码的过程中,生成全局变量
- 此插件默认配置了
process.env.NODE_ENV
用于区分开发环境和生成环境的
js
const path = require("path");
//引入插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { DefinePlugin } = require("webpack");
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
//使用插件
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "zhangcheng",
//自己引用模板的路径
// template: "相对路径",
}),
new DefinePlugin({
//使用key:value形式
//value中会当成js代码
counter: "1+1", //2
counterStr: "'1+1'", //1+1字符串
}),
],
resolve: { },
module: {
rules: [],
},
};
Mode配置
- Mode配置选项,可以告知 webpack 使用相应模式的内置优化
- 默认值是 production(什么都不配置的情况下)
- 可选值有:none|development|production
js
const path = require("path");
module.exports = {
//Mode配置项
mode:"development"
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist"),
},
//使用插件
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "zhangcheng",
//自己引用模板的路径
// template: "相对路径",
}),
new DefinePlugin({
//使用key:value形式
//value中会当成js代码
counter: "1+1", //2
counterStr: "'1+1'", //1+1字符串
}),
],
resolve: { },
module: {
rules: [],
},
};
Webpack搭建一个本地服务器
前面的学习中,我们编写完成代码后,需要手动执行build命令,完成项目的打包,效率会很低
-
通过Webpack搭建一个本地的服务器,代码发生变化的时候,就自动打包,并刷新浏览器
-
需要借助webpack-dev-server来完成以上操作
-
首先通过
npm install webpack-dev-server -D
安装 webpack-dev-server -
在package.json文件的scripts中增加相应的脚本
js
"scripts": {
"build": "webpack",
"serve": "webpack serve"
},
-
之后运行
npm run serve
即可 -
实际上webpack-dev-server会将代码打包到内存中,之后开启一个服务器,浏览器访问本地的服务器读取内存中的代码,并不会生成本地的文件
HMR模块热替换
-
当我们只对某个模块发生了改变,则只会对改变的模块进行替换,添加以及删除等操作,从而无需刷新整个页面
-
HMR通过一下几种方式,来提高开发的效率
- 不重新加载整个页面,这样可以保留某些应用程序的状态不丢失
- 只更新需要变化的内容,节省开发的时间
- 修改了css、js源代码,会立即在浏览器更新
-
目前webpack是默认开启HMR的
- 同时我们可以手动开启,在 webpack.config.js 文件中,配置 devServer属性
jsdevServer:{ hot:true }
-
在代码中,我们需要指定哪些模块发生变化时,进行HMR
js
//判断是否开启了HMR
if(module.hot){
module.hot.accept("./until.js",()=>{
console.log("更新了")
})
}
本地服务的配置
js
devServer:{
hot:true,
//修改端口号
port:8888
//修改主机
host:"0.0.0.0"
//自动打开浏览器
open:true
//是否对文件进行压缩
compress:true
}