安装
-
npm i webpack webpack-cli
第一个是webpakc工具 第二个是webpack的指令工具 可通过在终端上输入指令来操纵webpakc帮助对项目进行处理.
webpack概念
-
loader
webpack只可以对js文件和json文件进行处理,对其它格式文件不能处理,需要loader对其先进行处理之后,才能交由webpack处理.
webpack指令
-
运行指令
- webpack "entry路径" -o "output路径" --mode=development/production
该命令会将入口路径的文件打包到出口路径的文件,并指令环境为开发环境.
打包后会输出一个hash值可以用来唯一标识这次打包文件的id,以及一些其它额外信息,如打包的时间,以及大小等.
- 开发环境和生产环境所做的事可以将es6的模块化转化为浏览器可识别的模块化,生产环境会比开发环境对一个压缩代码.
webpack.config.js
-
文件的意义
自己在项目的根目录下创建这个文件,且名字只能是这个,然后可在这里写配置,使得webpack可通过这里的配置对项目进行管理.
注意点:构建工具都是基于node环境下的,也就是说只能使用commonjs的规范来导入导出模块.
文件的基本配置
const path =require("path")
module.exports={
//入口文件 需要将所有依赖的文件最后都通过直接或间接的方式 最终放到这个文件里
entry:"./src/index.js",
// 出口文件
output:{
filename:"build2.js",
path:path.join(__dirname,'build')
},
// 配置loader 即让webpack可对其它非js文件以及json文件处理
module:{
//每一个规则对应一种文件的处理
rules:[
]
},
//配置插件,可让webpack做更多事
plugins:[],
//配置环境 有development 和production
mode:"development"
}
样式文件的处理
module:{
//每一个规则对应一种文件的处理
rules:[
{
test:/\.css$/,
// use使用的包是从右向左,从下网上执行
use:[
"style-loader", //创建一个style标签, 并将其放入head标签里,将转化为字符串的css样式放入这里.
"css-loader" //将css文件转化为js的字符串
]
},
{
test:/\.less$/,
use:[
"style-loader",
"css-loader",
"less-loader" //将less转化为css
]
}
]
}
html文件的处理
html文件可通过插件处理
//该插件需要导入 由于需要调用插件的构造函数来处理.
const webPackPlugin=require("html-webpack-plugin")
plugins:[
new webPackPlugin({
//文件打包后将自动处理并输出到一个index.html文件里,此文件与打包的文件同一级目录,而那个index.html以这个html文件为模板,只是多了一个引入.
template:"./src/template.html",
//压缩html代码
minify:{
collapseWhitespace:true,
removeComments:true
}
})
]
图片资源的打包
样式文件的图片背景图片需通过url-loader处理,不过该loader依赖file-loader所以两个都要下,而html里的图片则需要html-loader辅助url-loader进行处理.
module:{
//每一个规则对应一种文件的处理
rules:[
{
//对图片的处理 根据样式文件的引入图片的路径可通过下面这个loader进行处理,不过如果是处理图片的话该loader还需要依赖一个file-loader.
test:/\.(jpg|png|jpeg)$/,
loader:"url-loader", //如果只需要一个插件 可使用loader属性.
//options是对插件的配置 ,这里的limit是对文件大小的配置,如果图片小于14Kb则已base64处理,会生成一个图片的字符串,不需要产生新文件即可引入. 超过的还需要生成一个新文件.文件名根据图片内容产生的hash值.
options:{
limit:14*1024,
esModule:false //由于html-loader使用的是commonjs引入 ,所以需将es引入关闭,避免冲突.
}
},
//需要注意的是,如果html标签里直接引入的文件,需要html-loader先进行处理,由于html不会将文件输出到js里,所以先将html文件引入的文件,交由url-loader在处理.
{
test:/\.html$/,
loader:"html-loader"
}
]
}
其它资源打包
{
//表示除了这些文件 其它都用下面的loader.
exclude:/\.(png|jpg|jpeg|js|html|json|less|css|ts)/,
loader:"file-loader"
}
使用devServer
使用devserver可让webpack在内存中进行打包编译,并且会根据文件的变化来自动编译.
是webpack下的一个额外的配置项.
要使用这个配置,依赖一个webpack-dev-server的指令包,且需要通过npx 运行.
为npx webpack-dev-server
devServer:{
contentBase:path.join(__dirname,'build'), //路径
open:true, //自动打开默认浏览器
port:3000, //指定端口
compress:true, //压缩代码,
quiet:true, //指示启动时其它额外信息不要显示
//配置开发环境下的跨域问题 当想向其它服务器请求东西的时候,可通过前端路由所在的端口向其它域发送请求 .
proxy:{
'/api':{
//当访问/api/xxx路径时,可将请求转给自己的服务器,让自己的服务器在去访问下面的路径
target:'http://localhost:3000',
pathRewrite:{
'^api/':'' //将api去掉
}
}
}
}
打包输出目录的配置
默认所有文件除了引入到js文件里的样式被特殊处理外,其它资源文件也都会输出到出口文件,这样不利于查看.
若想让打包文件目录结构更清晰,可以指定输出目录. 但所有文件依然会输出出口文件里只是分配一个文件夹.
- 对于总的js文件 可以在filename的前面加入路径 如: "js/filename",
- 对于其它资源问价 可在module的每种文件的配置项里options选项里添加outputPath ,如outputPath:'img' 即可输出到出口文件里的img文件夹下.
生产环境的特殊处理
开发环境下只需要代码可以运行,测试代码.并不需要对代码的执行速度,兼容性有要求.
-
问题:
生产环境下需要对代码进行特殊处理,由于之前都是将css代码以字符串的形式放入到js里,在由js将样式插入到标签里,可能导致页面加载很慢,以及出现闪屏的现象
打包后的js等代码需要进行压缩处理.
-
解决办法
- 下载一个mini-css-extract-plugin来,并对其进行配置后,然后用它代替style-loader,由于style-loader只能将js里的样式引入到head里,但还是和js在一起.
用miniCssExtractPlugin.loader来取代style-loader,由于该loader可以生产css文件,
且在下面的插件里将其配置的filename用路径添上,可以使得有一个css文件夹.
```javascript
const miniCssExtractPlugin=require('mini-css-extract-plugin')
module:{
//每一个规则对应一种文件的处理
rules:[
{
test:/\.css$/,
// use使用的包是从右向左,从下网上执行
use:[
//"style-loader", //创建一个style标签, 并将其放入head标签里,将转化为字符串的css样式放入这里.
miniCssExtractPlugin.loader,
"css-loader" //将css文件转化为js的字符串
]
},
{
test:/\.less$/,
use:[
// "style-loader",
miniCssExtractPlugin.loader,
"css-loader",
"less-loader" //将less转化为css
]
}
]
},
plugins:[
new miniCssExtractPlugin({
filename:"css/index.css"
})
],
```
-
压缩css
依赖的包(插件) optimize-css-assets-webpack-plugin
只需要引入 再在插件出new使用即可
css兼容性的处理
为了让写的css样式可以兼容大部分浏览器,需要对其做一些处理.
需要依赖两个包,一个是postcss-loader 可以对css的兼容性样式进行处理,而postcss-preset-env,可以找到项目下的package.json下的浏览器配置,可对指定的浏览器以及根据当前所处的环境对css样式进行兼容配置
//webpack.config.json
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
//use可以使用多个插件,但是如果某个插件还需要单独配置,可用{}将其阔气来,然后通过options进行配置
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}]
}
//package.json
//process可以获取电脑的环境变量 打包的时候默认以生产环境配置 这个可以指定当前是开发环境
"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"
]
}
js文件的兼容
需要用到babel-loar对其进行处理, 然而这个插件又依赖babel,@babel/core,
可使用@babel/preset-env对js代码做简单的兼容,若需要兼容更多,又需要下载core-js
{
test:/\.js$/,
// 需要将这个文件jia下的代码给去除
exclude:/node_modules/,
loader:"babel-loader",
options:{
presets:[
[
//可对js代码做简单的检查
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本 检查比较大
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]}
},
性能优化
-
开发优化
-
热模块替换 (hmr)
即让模块在打包的时候,如果某个模块变了,只对那个单独的文件做替换,其它不变.
-
```javascript
devServer:{
contentBase:path.join(__dirname,'build'), //路径
open:true, //自动打开默认浏览器
port:3000, //指定端口
compress:true, //压缩代码
hot:true
}
```
可在webpack的内存加载中加入Hot:true即可热模块替换,但是只是会对css起效,对js以及html不起效.html不需要单独配置,由于html只有一个模块变化了肯定要变,
js 可以在入口文件的js处加上进行处理.
```javascript
if(module.hot){
module.hot.accept('模块文件',回调函数)
}
```
- 代码调试
默认的时候,如果打包的时候代码出错,由于所有文件都打包到一起,所以很难找到出错的位置,
在配置的根目录下进行devtool配置可解决问题.
值都不一定 source-map虽然慢 但是可以定位到行,而eval不可以
devtool:'eval-source-map' //开发调试 执行快 产生的代码块和源文件的映射直接写在打包的代码里
//devtool:'source-map'//生产调试 执行稍慢 产生的代码块单独用一个文件存放
-
开发和生产通用
- 加快打包速率之oneOf
通过oneOf包裹,默认rules里放的是每一个对象规则,但是默认的规则是 比如css文件自己通过某个loader处理完之后,还要继续往下找看是否还有处理css的loader,如果有则更好,没有显然浪费了时间,所以为了节省时间,如果知道某些文件只需要通过一组loader处理,则可以写在oneOf里,这样对应的文件处理完之后,则不在处理.
需要注意的是如果一种文件需要几组loader处理,则不能将几组loader都写在oneOf里 不然可能值处理了一组
module:{
//每一个规则对应一种文件的处理
rules:[
//默认rules里放的是每一个对象规则,但是默认的规则是 比如css文件自己通过某个loader处理完之后,还要继续往下找看是否还有处理css的loader,如果有则更好,没有显然浪费了时间,所以为了节省时间,如果知道某些文件只需要通过一组loader处理,则可以写在oneOf里,这样对应的文件处理完之后,则不在处理.
// 需要注意的是如果一种文件需要几组loader处理,则不能将几组loader都写在oneOf里 不然可能值处理了一组
{oneOf:[
{
test:/\.css$/,
// use使用的包是从右向左,从下网上执行
use:[
//"style-loader", //创建一个style标签, 并将其放入head标签里,将转化为字符串的css样式放入这里.
miniCssExtractPlugin.loader,
"css-loader", //将css文件转化为js的字符串
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}
]
},
{
test:/\.less$/,
use:[
// "style-loader",
miniCssExtractPlugin.loader,
"css-loader",
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
},
"less-loader" //将less转化为css
]
},
{
//对图片的处理 根据样式文件的引入图片的路径可通过下面这个loader进行处理,不过如果是处理图片的话该loader还需要依赖一个file-loader.
test:/\.(jpg|png|jpeg)$/,
loader:"url-loader", //如果只需要一个插件 可使用loader属性.
//options是对插件的配置 ,这里的limit是对文件大小的配置,如果图片小于14Kb则已base64处理,会生成一个图片的字符串,不需要产生新文件即可引入. 超过的还需要生成一个新文件.文件名根据图片内容产生的hash值.
options:{
limit:14*1024,
esModule:false , //由于html-loader使用的是commonjs引入 ,所以需将es引入关闭,避免冲突.
outputPath:'img'
},
},
//需要注意的是,如果html标签里直接引入的文件,需要html-loader先进行处理,由于html不会将文件输出到js里,所以先将html文件引入的文件,交由url-loader在处理.
{
test:/\.html$/,
loader:"html-loader"
},
// {
// //若有eslint,需要加
// // enfore:'pre' 来保证其优先执行
// }
//处理js的兼容性问题
{
test:/\.js$/,
// 需要将这个文件夹下的代码给去除
exclude:/node_modules/,
loader:"babel-loader",
options:{
presets:[
[
//可对js代码做简单的检查
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本 检查比较大
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]}
},
{
//表示除了这些文件 其它都用下面的loader.
exclude:/\.(png|jpg|jpeg|js|html|json|less|css|ts)/,
loader:"file-loader",
options:{
outputPath:'fontimg'
}
}
]
},
]
}
-
缓存处理
- babel
由于在生产环境下没有hmr 但是babel进行处理的时候 每次都会对模块进行转化,显然每次都这样处理不是很好.
设置 cacheDirectory:true
{ test: /\.js$/, // 需要将这个文件夹下的代码给去除 exclude: /node_modules/, loader: "babel-loader", options: { presets: [ [ //可对js代码做简单的检查 '@babel/preset-env', { // 按需加载 useBuiltIns: 'usage', // 指定core-js版本 检查比较大 corejs: { version: 3 }, // 指定兼容性做到哪个版本浏览器 targets: { chrome: '60', firefox: '60', ie: '9', safari: '10', edge: '17' } } ] ], //第二次会读取缓存 cacheDirectory:true, } }
-
服务器强制缓存
由于用户访问服务器的时候,(是服务器,要通过域名ip地址访问),浏览器会强制将服务器的资源进行缓存一段时间,此时若服务器想修改一些代码,由于浏览器有缓存的东西,所以不会更新.
解决办法,每次打包的时候,文件名后面加上hash值,那么只要改东西,hash值就会变,浏览器检查到新的资源必然会进行加载.
但是这样写有一个问题,由于一开始合并文件的时候css和js都合并到一个chunk,所以css的hash值和js的hash值是一样的,所以当只改变一个文件的时候,hash都变,所以重新请求的时候两个文件都要重新请求,即使之改变了一个.
output: { filename: "js/4打包其它资源.[hash:10].js", path: path.join(__dirname, 'build') }, plugins: [ //处理css,指定到输出目录 new miniCssExtractPlugin({ filename: "css/index.[hash:10].css" }), ],
所以为了区分
做了一些修改 只根据文件内容的hash来取名
output: { filename: "js/4打包其它资源.[contenthash:10].js", path: path.join(__dirname, 'build') }, plugins: [ //处理css,指定到输出目录 new miniCssExtractPlugin({ filename: "css/index.[contenthash:10].css" }), ],
tree shaking
将没有用到的代码可去除掉
使用条件 mode需开启为production 且模块之间的导入是以es6的导入方式
注意事项:需要在package.json目录配置不需要去除掉的代码
不然可能会将这些文件误删
"sideEffects":["*.css","*.less"]
split chunk
根目录配置该 优化可以将node_module里打包的代码和其它代码分开,且可让多入口的文件都同时依赖一个node_modules打包的代码.
默认情况下 无论开发还是依赖,多个js文件同时依赖某个node_moduls这个文件也只会打包一次,不会多次打包.
optimization:{
splitChunks:{
chunks:'all'
}
}
如果不是多入口,但是某些js文件也需要和其它js代码分割,那么可在导入的时候进行处理即可
//导入的时候
//注意的是这里的注释有用 指定分离后的名字 返回一个promise 在then里调用 导出的函数
import(/*webpackChunkName:'test'*/'路径').then(({那个路径下的东西解构值})=>{
)
lazy-load(js文件的懒加载)
配合上面的js分离,可对某些js文件懒加载
//如
//这样即可对这个文件懒加载
document.querySelector('.class').onclick=function(){
import(/*webpackChunkName:'test'*/'路径').then(({那个路径下的东西解构值})=>{
)
}
预加载
//正常加载都是一个个加载,预加载则是一开始不加载等到其它资源加载完毕,浏览器空闲了,在加载这个. (慎用 有兼容问题)
document.querySelector('.class').onclick=function(){
import(/*webpackChunkName:'test',webpackPrefetch:true*/'路径').then(({那个路径下的东西解构值})=>{
)
}
pwd(渐进式网络开发应用)
依赖 workbox-webpack-plugin
externals
打包的时候忽略某个node_module下导入的包
可在html 用script 标签引入 cdn方式. 这样项目还是照常运行
externals:{
jquery:"jquery"
}
dll
对node_modules导入的文件都进行单独打包
详细配置
都是相对于根配置
entry
-
值有三种类型 String,Array,Object.
string若output没写filename则会打包成main.js,只会打包成一个文件
Array 多入口 也只会打包成一个文件,可将htmL放进来,可开启html的hmr.
Object 多入口 多出口 出口名为键 {键:"文件路径"},需要output的filename改为
'[name].js'
每个键后面还可以跟数组 ,将这些文件打包成一个js
output
output: {
filename: "js/4打包其它资源.[contenthash:10].js",
path: path.join(__dirname, 'build'),
// publicPath:"/" 所以资源引入的路径前缀 打包后再资源引入的前面加上/ 上线的时候使用,
// chunkFilename:"" 用于非入口文件的chunk的名字 就是有些文件最后也会生产一个文件 以这个来命名,
library:'[name]' //name是前面entry定义的键如果没定义就是main,因为默认output输出main library可将打包后的整个文件通过name这个变量暴露出去,使得其他东西可以访问.
libraryTarget:'window'//客户端 绑定给window对象
},
resolve
和路径有关
//解析模块的规则
resolve:{
//配置路径别名
alias:{
别名:"路径"
},
//配置省略文件路径的后缀名 默认有js和json
extensions:['.css','.less','vue'],
//告诉webpack找模块在哪个目录找 node_modules
modules:[]
}
optimization
只在生产环境下起效
optimization:{
splitChunks:{
chunks:'all',
minSize:30*1024, //指定分割的chunk最小为30kb
maxSize:0, //意思最大没有限制
minChunks:1, //要提取的chunk最少被引用一次
},
//当打包的时候会多出一个runtime模块,由于将入口文件和node_moudles文件分离,以及其它模块分离,若其它模块分离,又希望其它文件不变,但是由于入口文件时通过hash值记录的其它文件的依赖关系,其它文件变了,必然导致其它文件的hash值变化,也就导致入口文件变了,所以对引入的模块的hash值特别处理,这样哪个文件变化了,只改变那个模块以及对应hash值文件.
runtimeChunk:{
name:entrypoint=>`runtime-${entrypoint.name}`
},
minimizer:[
//配置生产环境的压缩方案: js和css
//webpack在4.26以上生产环境不再使用uglify压缩代码 由于其不再维护,使用terser来压缩
//需下这个包 才可以进行配置
new TerserWebpackPlugin({
//开启缓存
cache:true,
parallel:true, //开启多进程
})
]
}