webpack
- 是一种前端资源构建工具,一个静态模块打包器。前端所有的资源文件(js/json/img/less/...)都会作为模块处理
- 它会根据模块的依赖关系进行静态分析。打包生成对应的静态资源。
5大核心
- Entry:webpack以哪个文件作为入口起点开始打包,分析构建内部依赖图
- Output: webpack打包后的资源,bundle输出到哪里去,以及如何命名
- Loader: Loader让webpack处理非js文件
- Plugins: 插件可以用于执行范围更广的任务。从打包优化,压缩一直到重新定义环境中的变量等
- mode:development和production。开发模式比较简单。生成模式要各种优化
初体验
-
npm init:初始化一个包描述文件
-
npm i webpack webpack-cli -g 下载
-
创建入口文件
-
在终端执行打包命令:webpack ./src/index.js -o ./bundle mode=development
-
webpack 5.0现在默认生成main.js文件
-
asset列:指构建后输出的资源文件,名称由filename的配置决定
-
emitted列:指文件被输出
-
(name:main):指chunk的name为main
-
如果是生产环境的话,打包之后的文件会被极限压缩
打包css文件
- 配置文件
const {resolve} = require("path")
module.exports={
entry:'./src/index.js',
//出口是个对象,调用path 的resolve方法来设置绝对路径
output:{
filename:"built.js",
path:resolve(__dirname,'build')
},
//module配置对应的loader
module:{
rules:[
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
]
},
mode:'development'
}
- 下载对应的loader:css和style。 style先执行cssloader,讲css文件变成commonjs模块加载js中,里面内容是样式字符串。
再执行style,创建style标签。将js中的样式资源插入。
- 打包成功
plugins的使用
-
下载
-
引入
-
安装
-
HtmlWebpackPlugin:1.如果没有指定的html模板,会自动生成一个空白文件,同时引入打包之后的js文件 2.如果指定了模块,会生成对应的html结构,同时引入打包之后的js文件
图片资源的引入
- 下载url-loader和file-loader
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
//限制图片大小。如果小于8-12kb就用base64去解析
options: {
limit: 8 * 1024,
},
},
],
- 但是无法处理html文件中通过img引入的图片(只能处理通过css引入的图片:背景图)
- 解决:引入npm install --save-dev html-loader
{
test:/\.html$/,
loader:'html-loader'
}
- 同时,url-loader里面的esMudle需要改成false
- 注意,当引入这个模块的时候。只会解析scr的图片模块,不会再解析js文件了!!!
处理字体图标
- 下载字体图片
- 在入口文件导入 import "./font/iconfont.css"
- 导入需要的字体文件
- 设置字体的类名(2个)
- 配置loader,因为处理使用fileloder,所以不需要重新下载
- 注意,此时需要排除。css。js,。html和各种图片文件。不然会报错。写法也有区别,是exclude来做
{
exclude:/\.(css|js|html|png|jpg)$/i,
loader:'file-loader',
options:{
name:"[hash:10].[ext]"
}
},
devServer
- 目前最新版本的devServer只支持webpack-cli 3.3.12才能运行
- 下载
- 配置devServer
//自动化编译,打开浏览器,刷新浏览器
//只会在内存中编译打包,不会有任何输出
devServer:{
//项目构建后路径
contentBase:resolve(__dirname,"build"),
//开启gzip压缩
compress:true,
port:5000,
//执行的时候自动打开浏览器
open:true
},
- 执行npx webpack-dev-server
打包分类
- 将生成的js文件放在这个目录下面
- 别的css(已经集合在js中不用另外生成),其他文件和图片资源要指定路径要这样写
{
exclude:/\.(css|js|html|png|jpg)$/i,
loader:'file-loader',
options:{
name:"[hash:10].[ext]",
//media放在build文件下面,其她资源文件会放到build/media下面
outputPath:'media'
}
},
生产模式
- 因为,webpack都是把css文件压入到js中,所以会导致js文件过大,而且,只有js运行了才会创建css,会导致闪屏。
- 需要在生产模式中,将css文件单独抽离出来。
- 下载一个新插件:
- 引入插件,注册插件
- 这个插件用法放在loader里面。同时注释掉style.loader
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader']
}
]
- 如果想要css放在特定目录,就修改插件下面的属性
//文件名字为build.css,放在build的css文件下面(css文件没有的话会自动创建)
new MiniCssExtractPlugin({
filename:"css/build.css"
})
css的兼容性处理
- 不同浏览器的css样式有些事不同的。
- 用postcss-loader和postcss-preset-env(下载)
- 再webpack.config.js的同级目录下面创建文件:postcss.config.js
- 配置文件(postcss.config.js)
module.exports={
plugins:[
require('postcss-preset-env')
]
}
- 再package.json里面写上浏览器的list
"browserslist":{
"development":[
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production":[
">0.2%",
"not dead",
"not op_mini all"
]
}
再webpack.config.js里面加上这个loader
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader','postcss-loader']
},
- 注意:这里生产的css文件默认是看生产环境的。和mode为开发环境无关
- 如果是要生产环境的话。修改node的环境变量为开发模式
配置babel
- 让es6语法转化为es5语法,让ie浏览器能够识别
- 下载3个依赖包。npm i babel-loader @babel/core @babel/preset-env -D
- 配置loader
{
test:/\.js$/,
//不去修改第三方的库
exclude:/node_modules/,
loader:"babel-loader",
//预设:指示babel做什么样的兼容性处理
options:{
presets:['@babel/preset-env']
}
}
-
但是会有一个问题,就是这些只能识别最基本的es6语法,无法识别高级的比如promise
-
下载npm i @babel/polyfill -D 这个包直接定义了所有的高级语法
-
再入口的js文件引入即可
-
但是这样的js文件会很多有几百kb
-
最终解决方法,按需加载
-
下载core/js npm i core/js -D
-
进行配置,注意要注释掉@babel/polyfill
-
修改预设
presets:[
[
'@babel/preset-env',
{
//按需加载
useBuiltIns:'usage',
//指定版本
corejs:{
version:3
},
//指定兼容性做到哪个版本
targets:{
chrome:"60",
firefox:"60",
ie:"9",
safari:"10",
edge:"17"
}
}
]
]
js和html压缩
- 在生产环境下会自动压缩js代码,因为生产环境会自动调用很多plugins。包括uglyfy。所以只有将mode改成production就可以了
- html,需要在htmlwebpackplugin配置2个参数为true
new HtmlWebpackPlugin({
template:"./src/index.html",
minify:{
//移除空格
collapseWhitespace:true,
//移除注释
removeComments:true
}
}),
对于js文件需要同时执行eslint和babel
- 要先进行eslint
- 给eslint加上enforce:'pre'
开发模式下的HMR
- 需要:我们只想在更新1个js或者1个css代码模块时,就只重新构建这个模块,而不重新构建所有的模块
- 开启dev的HMR:hot module replacement。
source-map
- 一种 提供源代码到构建后代码映射的技术(如果构建后代码出错了,可以通过映射追踪到源代码)
-
- 生成一个map文件
- inline-source-map 内联式(不生成map文件,代码集合在js文件中)
- hidden-source-map 外联式(生成map文件)
- eval-source-map 内敛(每一个文件都生成对应的source-map,都在eval函数中一一对应)
在vue和react的脚手架中,都是用eval-source-map
开发优化
oneOf
- 一个文件会被所有的loader,都会检查是否命中,这样速度会慢
- 因此,我们可以设计这个一个东西:如果一个文件被一个loader命中,那么他不会被后面的loader进行检查
- oneOf出来了,同时由于js需要babel和eslint去处理,那么把eslint放在最前面,每个文件都需要被eslint的loader所检查。
rules: [
{
//这里放eslint的loader文件
},
{
//把所有的loader都复制进去
oneOf:[
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.html$/,
loader: 'html-loader'
}
]
}
]
其他知识
生产环境
放到服务器上的环境,展示给用户看的
缓存
相当于开发环境的HRM(基于devServer),修改其中一个js文件,只更新这个js文件,别的不变的js代码都直接拿缓存。而且最多的也是js代码,css和其他代码都很少。所以对babel进行处理,因为babel会对所有的js代码进行编译处理。
- babel缓存
- 用hash值来做缓存(和协商缓存差不多)
- 原理:每次webpack生成的文件名都带有哈希值,如果重新构建哈希值不同的话,就会重新请求,如果文件没变,重新请求就会向缓存里请求数据。
- 问题:js或者css变,都会变化
treeShaking
- 就是把没有用到的js代码不打包
但是会对一些没有引用的css代码进行省略,这时候去package.json里面配置sideeffect
- 代表不去检查css文件
code_split
- 可以提供多入口文件
- 可以将依赖单独作为一个chunk,而且如果多入口文件同时依赖这个包的话,会自动分析,单独打包,不会打包成多份!只会打包为1分
懒加载!
- 前提是会分隔代码
- 预加载(兼容性比较差)
pwa(兼容性较差)
- pwa:渐进式网络开发应用程序(离线可访问)
- 下载插件
- 注册插件
- 在入口文件index.js写执行代码
多进程打包
- 优点:多个进程进行打包
- 缺点:进程启动会消耗时间和进程通信也会有消耗,因此小项目不用这个
- 而且只在babel里面用这个插件
- 下载插件
- 在babel里面注册
- 进程数量可以调整(最多为cpu核数-1)
extrenals
- 将一些包通过cdn引入而不去打包
dll
- 将node——module的包单独打包,单独引入
- 与external区别是,dll第一次打包后面就不用再次打包了,加快了构建速度