您现在的位置是:首页 >其他 >webpack食用指北网站首页其他
webpack食用指北
何为webpack
wepack即一个模块打包器。它的主要目标是将 JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用。
那么为什么需要把文件打包呢,我的理解是因为在现代web开发中所涉及的资源越来越多,代码越来越复杂,维护和更新都十分的困难,所以才需要webpack来帮助我们管理项目,提升开发效率
webpack前置知识
html
和css
和JavaScript
- 会用
npm
或yarn
或其他包管理工具
webpack项目初始化
我这里使用npm
来进行包管理,用yarn
或其他也都可以的
npm init -y
在此之后我们就需要安装webpack
了
npm install webpack webpack-cli -D
或者使用简写
npm i webpack webpack-cli -D
其中webpack-cli
为便于我们在命令行键入webpack
命令的模块
现在我们在项目中新建一个index.html
文件和其他必要文件夹
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>123</p>
<div id="app"></div>
</body>
</html>
此时我们项目的文件结构如下
我们在src目录下新建一个main.js
文件
import { sum } from "./js/math"
console.log(111)
console.log(222)
console.log(sum(1, 2))
同时我们在js目录下新建math.js
文件
export function sum(num1, num2) {
return num1 + num2;
}
那么我们项目的初识化就完成了
webpack配置文件
webpack
安装完后我们还需要对webpack
进行配置,在项目根目录创建一个webpack.config.js
的文件
const path = require("path")
module.exports = {
//这里就放着webpack的具体配置
mode: "development",//为webpack的打包环境,development为开发环境,production为生产环境
entry: "./src/main.js",//为webpack项目的打包入口,从哪个js文件开始打包
output: {//为webpack项目的打包出口
path: path.resolve(__dirname, "./dist"),//把打包好的文件放在哪里
filename: "bundle.js"//打包好的文件名
},
}
接下来我们还需要修改package.json
在script
中加入一行dev
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"dev": "webpack"
},
接下来我们在命令行中进入项目文件夹,运行命令
运行webpack
npm run dev
等待打包完成
接下来我们需要在index.html
中引入bundle.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>123</p>
<div id="app"></div>
<script src="./dist/bundle.js"></script>
</body>
</html>
运行index.html
,浏览器中查看结果
打包成功
loader
其实webpack
不仅仅能打包js文件,现代网页所需的资源,例如图片,css,字体文件,vue文件等等其实都可以通过webpack
来进行打包。但要知道的是,webpack
本身只能打包js文件,想要在webpack
中打包其他文件的话需要依赖一种模块,这种模块的名字叫loader
css引入
如果想要打包css
文件就需要css-loader
和style-loader
首先通过npm
来安装
npm i css-loader style-loader -D
我们在css
文件夹下创建一个style.css
文件
p {
color: red;
}
我们在main.js
中引入style.css
文件
import "./css/style.css"
然后我们对webpack.config.js
进行修改
const path = require("path")
module.exports = {
mode: "development",
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "./dist"),
filename: "bundle.js"
},
module: {//对loader的配置都写在这里
rules: [//rules为一个数组,数组里面是一个个对象,里面存放着不同文件使用什么loader的规则
{
test: /.css$/,//test为匹配规则,使用正则表达式
use: [//use为此文件要使用什么loader,use是一个数组,里面也是一个个对象
{
loader: "style-loader",//loader为使用什么loader
options:{//不是必须的,这里存放这一些此loader的配置信息,比如打包到哪个文件夹,打包的文件名等等
}
},
{
loader:"css-loader"
}
]//注意:use里的loader的执行顺序为从下到上
}
]
}
}
对loader的配置的几种写法
第一种:
rules: [
{
test: /.css$/, //正则表达式
// 1.loader的写法(语法糖)适用于只需要一个loader的情况
loader: "css-loader"
}
]
第二种:
rules: [
{
test: /.css$/, //正则表达式
//适用于需要多个loader但不需要对单独的loader进行配置的情况
use: [
"style-loader",
"css-loader",
"postcss-loader"
]
},
]
最后让我们运行一下看看结果
可以看到css
已被成功应用
图片引入
图片的引入我们需要file-loader
和url-loader
首先通过npm
来安装
npm i file-loader url-loader -D
我们寻找一张图片,并在main.js
中引入
import { sum } from "./js/math"
import "./css/style.css"
import bg from "./img/sucai.jpg"
import pic from "./img/nhlt.jpg"
console.log(111)
console.log(222)
console.log(sum(1, 2))
var div = document.createElement("div");
div.style.height = '500px';
div.style.backgroundImage = `url(${bg})`;
var img = document.createElement("img");
img.src = pic;
var app = document.querySelector("#app");
app.appendChild(div);
app.appendChild(img);
接下来我们对webpack.config.js
来进行修改
module: {
rules: [
//此为之前的配置。。。
{
test: /.(jpe?g|png|gif|svg)$/,
use:[
{
loader:"url-loader",
}
]
}
]
}
让我们运行一下看看
图片已被成功显示,但此时的图片是以base64
的形式展现的,但大图片转换base64
来显示的话会十分占用性能,如果是小图片的话则会节省性能,所以我们需要配置只有图片小于多大的时候才会以base64
的形式展现
url的options
我们还是对webpack.config.js
文件进行修改
{
test: /.(jpe?g|png|gif|svg)$/,
use: [
{
loader: "url-loader",
options: {
limit: 100 * 1024//limit即为转换base64的范围,单位是字节,只有小于100*1024字节(100KB)的图片才转换为base64,否则就不转化
}
}
]
}
我们再次运行看看结果
这回我们可以看到上面的大图片没有转换成base64
,而下面的小图片则转换成了base64
这时我们发现在dist
目录下多出了一个jpg文件,而在我们配置limit
之前dist
目录是没有出现过jpg文件的,由此我们也可以知道:没有被转换为base64
的图片会被打包到我们之前配置好的目录之中
dist
目录下的jpg文件名为一串不明所以的字符,在实际开发中我们经常需要把图片放在一个文件夹内,并且每个文件名都要有语义性同时也要有能标识它唯一的标志,那么该怎么写呢
我还是修改webpack.config.js
文件
{
test: /.(jpe?g|png|gif|svg)$/,
use: [
{
loader: "url-loader",
options: {
name: "img/[name]_[hash:6].[ext]",//这里写着文件的命名规则,规则指出文件要存放在img文件夹下,命名为“文件原本的名字”+_+“6位哈希值”+原本后缀名
limit: 100 * 1024
}
}
]
}
运行之后我们再看文件结构
图片成功放进了img
文件夹并且也成功改名了,但上次运行时打包的资源依旧还在
自动清除上次打包遗留的资源
webpack
可以自动清理上次打包的遗留资源,但初始并不是开启状态
我们可以通过修改webpack.config.js
来手动开启它
output: {
clean: true,//开启自动清理
path: path.resolve(__dirname, "./dist"),
filename: "bundle.js"
},
我们再次运行查看结果
这时上次打包所遗留的资源就没有了
资源模块类型
以上的图片打包方式多适用于webpack5
以前,在webpack5
中webpack
官方推荐使用asset
在webpack5
中我们可以使用资源模块类型(asset module type)来替代上面的loader
,asset
共有四种类型
asset/resource
--不管文件大小,直接以文件形式导出asset/inline
--不管文件大小,直接以base64的形式导出asset/source
--导出资源的源代码asset
–webpack自动帮我们决定以什么方式导出
图片的webpack5引入方式
{
test: /.(jpe?g|png|gif|svg)/,
type: "asset",//asset的类型
generator: {
filename: "img/[name]_[hash:6].[ext]"//导出文件的路径和命名规则
},
parser: {
dataUrlCondition: {
maxSize: 100 * 1024//类似于limit
}
}
},
字体的webpack5引入方式
字体文件如何引入这里就不再赘述,以下是webpack5
中对字体文件的配置
{
test: /.(eot|ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "font/[name]_[hash:6][ext]",
},
},
webpack插件
和loader
不同的是,loader
只能完成一些特定的任务,如特定模块的转换,而插件却能完成更多更广泛的任务,如打包优化,资源管理,接下来将介绍几种开发中常用的插件
html-webpack-plugin
在我们的项目中其实有一个不规范的地方,即我们的html
文件是在根目录下的,而最终打包的文件夹中并没有index.html
文件,这意味着我们还需要对html
文件进行打包,而对html
文件打包就用到了这个插件
我们用npm
来安装这个插件
npm i html-webpack-plugin -D
安装完了之后我们需要在webpack.config.js
里面引入使用
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
plugins: [
new HtmlWebpackPlugin()
]
}
我们再次运行,此时的dist文件夹下就有了index.html
文件了
然而这里的index.html
和我们根目录下的index.html
并不是同一个东西,dist
目录里的index.html
是由插件中内置的模板生成的,那么如果我们想要使用自己的index.html
为模板的话该怎么办呢
我们新建一个public
的文件夹并将根目录的index.html
放进去
修改webpack.config.js
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html"
})
]
做完之后再次打包,此时dist目录下的index.html
就是由public
文件夹中的index.html
打包完成的了
copy-webpack-plugin
这个插件最主要的作用就是将一些不便打包的资源复制到目标文件夹中,比如网站图标
我们一般习惯性的把这些不便打包的资源放入public
文件夹中
我们通过npm
来安装这个插件
npm i copy-webpack-plugin -D
接下来我们在webpack.config.js
中引入插件
const CopyWebpackPlugin = require("copy-webpack-plugin")
plugins: [
new CopyWebpackPlugin({
patterns: [//匹配规则,一个数组有多个对象,每个对象都是一个不同的匹配规则
{
from: "public",//从哪个文件夹开始复制
to: "./",//复制到那个文件夹,注意:此时的文件目录是从打包文件夹,也就是dist开始的
globOptions: {//忽略某个文件不做复制
ignore: [
"**/index.html"//忽略这个文件夹下的index.html文件
]
}
}
]
}),
]
最后我们运行一下就能看到文件复制到dist
目录下了
Babel
虽然在现代浏览器中,很多的浏览器都支持es6语法,但还有一些老旧浏览器没有支持,为了对那一部分浏览器做适配,我们就需要将es6
语法转换为那些浏览器看得懂的语法,这个步骤就由Babel
来实现
我们使用npm
来安装Babel
npm i @babel/core @babel/cli -D
如果安装了@babel/cli则可以在命令行单独使用babel,我们这里主要是babel和webpack一起使用的情景,单独使用的命令可以参照官方文档
安装完这两个之后babel
还并不能使用,我们还需安装其他插件来配合babel
运行
@babel/plugin-transform-arrow-functions
这个插件主要是将箭头函数转换为普通函数的
npm i @babel/plugin-transform-arrow-functions -D
@babel/plugin-transform-block-scoping
这个插件主要是将const,let转换为var的
npm i @babel/plugin-transform-block-scoping -D
@babel/preset-env
这个插件相当于是一些常用插件的集合,用了它就不需要再下其他的插件了
npm i @babel/preset-env -D
在webpack中配置babel
我们通过loader
的方式来使用babel
下载babel-loader
npm i babel-loader -D
我们修改webpack.config.js
文件
{
test: /.js$/,
use: {
loader: "babel-loader",
options: {
presets: [
"@babel/preset-env"
]
}
}
}
再次运行时我们js中的es6
语法就会转换成兼容语法了
watch
每当我们修改了文件后想要查看打包效果就要重新打包,而每次打包耗时少则几秒,多则上十秒,严重降低了开发效率,那么有没有一种东西,能在我每次保存时都自动打包,而且降低每次打包的耗时呢
webpack
里提供一个叫做watch
的功能,打开它之后webpack
依赖图中的所有文件只要发生了改变,那么就会重新打包
module.exports = {
mode: "development",
watch: true,
}
这样我们就开启了watch
然后我们手动运行打包一下,以后再对文件进行修改的时候就不用手动再打包了
devtool
有时候,我们代码可能会有写错的地方,当我们打开控制台准备调试时却发现我们的问题被控制台定位到了已经打包好了的一堆完全看不懂的js文件中,这时候如果我们想要知道问题具体出在了源代码的哪一行时我们就需要devtool
module.exports = {
mode: "development",
devtool: "source-map",//将我们打包好的js文件和我们的源代码进行一个映射
}
这样devtool就开启了
webpackServer
让资源自动打包的方法不止watch
一种,webpack-server
也行
首先下载webpack-server
npm i webpack-dev-server -D
watch
方法可以实时监听文件的变化,但事实上他无法刷新浏览器,而webpack-server
却可以
我们在package.json
中增加一行
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"dev": "webpack",
"server": "webpack serve"//npm run server 就是启动webpack-server
},
接下来我们修改webpack.config.js
文件
module.exports = {
mode: "development",
devtool: "source-map",
devServer: {
static: {
directory: path.join(__dirname, './public'),//如果webpack需要某些文件但src目录下找不到就回来这个目录找,如index.html和favicon.ico
},
host: "0.0.0.0",//设定服务器的本地IP地址
port: 7777,//设置服务器的端口号
open: true,//是否在打包完成后自动开启浏览器
compress: true,//是否以gzip格式压缩资源来提升传输性能
},
}
注意:static
为webpack5
新语法,在webpack5
以前如果想实现这种功能则要
devServer: {
contentBase: "./public",//webpack5以前的写法,现在使用webpack5对其进行打包的话会报错并推荐你使用上面那种写法
host: "0.0.0.0",//设定服务器的本地IP地址
port: 7777,//设置服务器的端口号
open: true,//是否在打包完成后自动开启浏览器
compress: true,//是否以gzip格式压缩资源来提升传输性能
},
运行npm i server
就能看到此时浏览器运行成功
热替换
无论是watch
还是webpack-server
,他们只要检测到了一个模块的修改,就会对这个项目重新打包并且刷新整个页面,但我其实只对其中一个模块进行了更改,其他模块我还想保存它的运行状态的话该怎么做呢
热替换能在应用程序运行中替换,添加,删除模块而不需要刷新整个页面
webpack-server
本身就支持模块热替换功能,我们只需开启就好。
devServer: {
static: {
directory: path.join(__dirname, './public'),
},
hot: true,//开启热替换功能
host: "0.0.0.0",
port: 7777,
open: true,
compress: true,
},
此时虽然开启了热替换,但webpack
并不知道哪些模块需要进行热替换,这些模块还需要我们进行配置
我们在main.js
中添加这么一段代码
if (module.hot) {
module.hot.accept("./js/math.js", () => {//第一个参数为哪个模块需要进行热替换,第二个参数为回调函数,他会在模块发生热替换之后运行
console.log("math.js模块更新了")
})
}
接下来我们再运行npm run server
并尝试修改math.js
并回到浏览器查看结果
config的分离
随着我们配置越写越多,配置文件阅读起来也越来越麻烦,而且生产环境和开发环境所以来的配置也不同,所以我们就需要对目前的一个配置文件进行分割
分割配置文件我们需要一个插件 webpack-merge
npm i webpack-merge -D
接下来我们在根目录新建一个config
文件夹,里面新建三个js文件
我们将原本的配置文件复制到这三个文件中
webpack.comm.config.js
为公共配置文件,无论是开发环境还是生产环境都需要的
webpack.dev.config.js
为开发环境配置文件
webpack.prod.config.js
为生产环境配置文件
接下来我们需要对这三个文件进行删减,比如公共文件就放公共部分,开发文件就放开发部分,生产部分就放生产部分
分完之后我们需要在webpack.dev.config.js
和webpack.prod.config.js
中引入webpack.comm.config.js
文件
dev
const { merge } = require('webpack-merge')
const commonConfig = require("./webpack.comm.config")
module.exports = merge(commonConfig, {
//配置...
})
prod
const { merge } = require("webpack-merge")
const commonConfig = require("./webpack.comm.config")
module.exports = merge(commonConfig, {
//配置...
})
之后我们还需要在package.json
中修改script
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"dev": "webpack --config ./config/webpack.dev.config.js",
"server": "webpack serve --config ./config/webpack.dev.config.js",
"build": "webpack --config ./config/webpack.prod.config.js"
},//--config为使用什么config文件
之后一切就做完了
结语
第二篇博客,感觉还是有些不够清楚的,有些知识点也没写出来,可能以后还会再写一篇关于webpack
的博客当做这篇博客的补充吧
非常感谢能看到这里,最后,还是希望我们变得更强:)