Webpeack
1. 介绍
Webpack是一种前端资源构建工具,一个静态模块打包器(module bundler)
在 Webpack看来,前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理
他根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)
2. 五个核心概念
2.1 Entry
入口(entry)指示Webpack以哪个文件为入口起点开始打包,分析构建内部依赖图
2.2 Output
输出(output)指示webpack打包后的资源bundles输出到哪里去,以及如何命名
2.3 Loader
Loader让Webpack能够去处理那些非js文件(webpack本身只理解js)
2.4 Plugins
插件(plugins)可以用于执行范围更广的任务,插件的范围包括,从打包优化和压缩,一直到重新定义环境的变量等
2.5 Mode
模式(Mode)指示Webpack使用相应模式的配置
选项 | 描述 | 特点 |
---|---|---|
development | 会将process.env.NODE_ENV的值设为development。 启用NamedChunksPlungs和N阿么的M哦读了书PLUgin。 | 能让代码本地调试运行环境 |
production | 会将process.env.NODE_ENV的值设为 production。启用FaglgDependencyUsagePlugin,FalgIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin,Occur人侧耳OrderPLUgin,SideEffectsFlagPlugin 和 UglifyJsPlugin。 | 能让代码优化上线运行环境 |
打包指令
npm i webpack webpack-cli -D // 安装webpack
// 开发环境
webpack ./src/index.js -o ./build/built.js --mode=development
// 生产环境
webpack ./src/index.js -o ./build/built.js --mode=production
- 结论
webpack 只能打包 js/json 文件
生产环境和开发环境将es6 模块化编译成浏览器能识别的模块化
生产环境比开发环境多一个压缩js
3. webpack.config.js
webpage.config.js webpack 配置文件
作用: 指示webpack干哪些活 (当你运行webpack指令时,会加载里面的配置)
所有构建工具都是基于node平台运行的 模块化采用 common.js
// loder 下载 使用
// plugins 下载 引入 使用
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.export = {
// 入口起点
entry:‘./src/index.js’,
// 输出
output:{
// 输出文件名
filename:'',
// 输出路径
// __dirname nodejs 的变量,代表当前文件的目录的绝对路径
path:resolve(__dirname,'build')
},
// loder 的配置
module:{
rules:[
// 详细的loder配置
{
// 匹配哪些文件
test:/\.css$/,
use:[
// use执行顺序 自下到上 自右到左
// 创建style标签 将js中的样式资源添加到head中生效
'styele-loader',
// 将css文件编程commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
},
// 匹配less
{
test:'/\.less$/',
use:[
'styele-loader',
'css-loader',
// 将less转换为css 注意需要下载 less 和 less-
'less-loder'
]
},
// 匹配img
{
test:'/\.(jpg|png|gif)$/',
loader:'url-loader', // 只引入一个可以使用字符串
options:{
// 图片大小 小于8kb 就会被base64处理
// 优点 减少请求数量(减轻服务器压力),缺点:文件体积会变大
limit:8*1024,
// 问题:url-loder 默认是es6模块化解析 而html-loader
// 引入图片是commonjs 所以解析会出问题
esModule:false,
// 给图片重命名 [hash:10] 去吐排尿前十位hash值 [ext]取图片原来拓展名
}
name:'[hash:10].[ext]'
},
// 匹配 html的img图片
{
test:'/\.html$/',
loader:'html-loader', // 只引入一个可以使用字符串
},
// 打包其他资源(除了html/js/css 资源以外的资源)
{
// 排除css/js/html 资源
exclude:/\.(css|js|html|less)$/,
loader:'file-loader',
options:{
name:'[hash:10].[ext]'
}
}
]
},
// 插件
plugins:[
// 详细配置
new HtmlWebpackPlugin({
// 复制 ./src/index.html 文件 并自动引入打包输出的所有资源(js、)
template:'./src/index.html'
})
],
// 模式
mode:'development' // 开发模式
// mode:'production' // 生产
// dev-Server // npm webpack-dev-server -D
devServer:{
contentBase:resolve(__dirname,'build'),
// 启动gzip压缩
compress:true,
// 端口号
port:3000,
// 自动打开浏览器
open:true
}
}
4. devServer
开发 服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
特点:只会在内存中编译打包,不会有任何输出
启动devServer指令为:npx webpack-dev-server
5. 提取css为单独文件
-
引入插件 mini-css-extract-plugin
-
使用插件
-
使用插件的loader 替换 style-loader
module:{ rules:[ { test:'/\.css$/', use:[ // 取代style-loader 作用:提取js中的css成单独文件 MiniCssExtractPlugin.loader, 'css-loader' ] } ] }, plugins:[ new MiniCssExtractPlugin({ // 对输出的css文件进行重命名 filename:'css/built.css' }) ]
6. css 兼容性处理
-
postcss —> psotcss-loader postcss-preset-env
-
使用 loader 在loader配置plungins
npm i psotcss-loader postcss-preset-env -D
webpack.config // 设置node环境变量 为 开发环境 process.env.NODE_ENV = 'development' module:{ rules:[ { test:'/\.css$/', use:[ // 取代style-loader 作用:提取js中的css成单独文件 MiniCssExtractPlugin.loader, 'css-loader', // loader 的默认写法 // loader 的配置写法 { loader:'postcss-loader', options:{ ident:'postcss', // 配置插件 作用:帮postcss找到package.josn中的 // browerslist里面的配置,通过配置加载指定的css兼容 plugins:()=>{ require('postcss-preset-env')() } } } ] } ] }, // package.json 文件 ”browerslist“:{ // 开发环境 --> 需要在webpack.config.js 中设置环境变量: //process.env.NODE_ENV = developement "development":[ "last 1 chrome version" // 兼容最近的谷歌 "last 1 firefox version" // 兼容最近的火狐 "last 1 safari version" // 兼容最近的safari ], // 生产环境:默认是看生产环境(如果不配置node环境变量的话) "production":[ // 兼容大部分浏览器 不兼容启用的 不兼容欧朋mini ">0.2%", "not dead", "not op_mini all" ] }
## 7. 压缩css文件
- optimize-css-asset-webpack-plugin 插件
```js
const OptimizeCssAssetsWebpackPlugin require('optimize-css-asset-webpack-plugin')
plugins:[
new OptimizeCssAssetsWebpackPlugin()
]
8. eslint 语法检查
语法检查 依赖:eslint-loader eslint
module:{
rules:[
{
test:'/\.js$/',
// 忽略
exclude:/mode_modules/,
loader:'eslint-loader',
options:{
// 自动修复eslint 的错误
fix:true
}
}
]
},
// package.json 文件
"eslintConfig":{
"extends":"airbub-base"
}
// airbub ->>> eslint eslint-config-airbub-base eslint-plugin-import
js 兼容性处理
js兼容性处理:babel-loader @babel/core
1. 基本js兼容性处理 --》 @babel/preset-env
2.需要作兼容处理的就做:按需加载 --》 core-js (这两个结合使用)
module:{
rules:[
{
test:'/\.js$/',
// 忽略
exclude:/mode_modules/,
loader:'babel-loader',
options:{
// 预设
presets:[
[
'@babel/prest-env',
{
//按需加载
useBuitIns:'usage',
// 指定core-js版本
corejs:{
version:3
},
targets:{
chrome:'60',
firefox:'60',
ie:'9',
safari:'10',
edge:'17'
}
}
]
]
}
}
]
},
js 和 html 压缩
1. js文件在production 环境会自动压缩
2. html压缩
// 在HtmlWebpackPlungin 里添加minify配置
minify:{
// 移除空格
collapseWhitespace:true,
// 移除注释
removeComments:true
}
优化
生产环境优化
-
优化打包构建速度
-
优化代码运行的性能
开发环境优化
-
优化打包速度
-
优化代码调试
HMR
hot module replacement 热模块替换
作用:一个模块发生变化,只会重新打包这一个模块,极大提升构建速度
devServer:{
contentBase:resolve(__dirname,'build'),
// 启动gzip压缩
compress:true,
// 端口号
port:3000,
// 自动打开浏览器
open:true,
// 开启HMR 改了webpack 需要
hot:true
}
-
样式文件:可以使用HMR功能,因为style-loader内部实现了
-
js文件:默认不能使用HMR功能, 注意:HMR功能对js的处理,只能处理非入口js文件的其他文件
-
html文件:默认不能使用HMR功能,同时会出现问题:html文件不能热更新了
解决:修改entry 入口 将html文件引入
// 入口起点 entry:['./src/index.js','./src/index.html'],
source-map
source-map : 一种 提供源代码到构建后代码映射技术 (如果构建后代码出错,通过映射可以追踪到代码错误)
module.export = {
entry:'',
...
devtool:'eval-source-map' // 开发环境推荐
// devtool:'source-map' // 生产环境推荐
}
oneOf
// 一下loader只会匹配一个 注意不能有两个配置处理同一个类型文件(oneOf提升构建速度)
module:{
rules:[
oneOf:[
{},
{},
...
]
]
}
缓存
-
babel 缓存
cacheDirectory:true 让第二次打包速度更快
{ test:'/\.js$/', // 忽略 exclude:/mode_modules/, loader:'babel-loader', options:{ .... } // 第二次构建会读取之前缓存 cacheDirectory:true }
-
文件资源缓存
hash:每次webpack构建都会生成一个唯一的hash值
问题:因为js和css同时使用会有一个一样的hash值 如果重新打包,会导致所有缓存失效(可能没有改动所有资源)
chunkhash:根据chunk生成的hash值,如果打包来源于一个chunk,那么hash值一样
问题:css在js中被引入 属于一个hash
contenhash:根据文件内容生产hash,不同文件值不一样
作用: 让代码运行缓存更好使用
// 用法 filename:'css/built[contenthash:10].css'
tree shaking
-
前提:1. 必须使用es6 模块化 2. 开启production
-
作用: 减少代码体积 去除无用代码
在package.json 中配置
"sideEffects":false // 所有代码都没有副作用 (都会进行tree shaking)
// 问题:可能会把 css / @babel/polyfill 文件干掉
"sideEffects":["*.css"]
code split
- 通过写单入口 和 多入口
多入口写法: entry:{
index:'./js/index.js',
test:'./js/test.js'
}
- 配置optimization
-
可以将node_modules中的代码单独打包到一个chunk最终输出
-
自动分析多个入口chunk中,有没有公共的文件,如果有会打包成一个单独的chunk
optimiazation:{
splitChunks:{
chunks:'all'
}
}
- 通过js代码,让某个文件被单独打包成一个chunk
import动态导入语法:能将某个文件单独打包
PWA
Progressive Web Application,全称“渐进式网页应用”,是谷歌主导的一种新时代网页(应用)。
简单的理解,就是你的网页,可以通过某种方式达到离线使用。
-
eslint 不认识window,navigator全局变量
解决:修改package.json 中 eslintConfig配置
“env”:{
“borwer”:true
}
-
sw代码必须运行在服务器上
// 下载并引入 workbox-webpack-plugin
// 在plugins 中使用
new WorkboxWebpackPlugin.GenerateSw({
// 帮住serviceworker快速启动 删除就得serviceworker
// 生成一个serviceworker 配置 文件
clientsClaim:true,
skipWaiting:true
})
// 在入口文件注册serviceworker
// 注册一个serviceworker 处理兼容性问题
if('serviceworker' in navigator) {
window.addEventListener('load',()=>{
navigator.serviceworker
.register('/service-worker.js')
.then(()=>{
console.log('sw注册成功了')
})
.catch(()=>{
console.log('sw注册失败了')
})
})
}
多进程打包
依赖 npm i thread-loader -D
- 开启多进程打包 进程启动大概为600ms, 进程通讯也要有开销 只有工作消耗时间较长,才需要多进程
{
test:'/\.css$/',
use:[
// 取代style-loader 作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
'css-loader', // loader 的默认写法
{ // 写在需要多进程的loader 后面(因为loader自下而上)
loader:'thread-loader',
options:{
workers:2 // 进程
}
},
// loader 的配置写法
{
loader:'postcss-loader',
options:{
ident:'postcss',
// 配置插件 作用:帮postcss找到package.josn中的
// browerslist里面的配置,通过配置加载指定的css兼容
plugins:()=>{
require('postcss-preset-env')()
}
}
}
]
}
externals
externals:{
// 拒绝JQ被打包进来
juqery:"jQuery"
}
// 同时CDN 引入
dll
plugins:[
// 告诉webpack那些库不参与打包,同时使用时名称也得
new webpack.DllReferencePlugin({
manifest: resolve(__dirname,'dll/manifest.json')
})
// 将某个文件打包输出去,并在html中自动引入
new AddAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,'dll/jquery.js')
})
]
// 新建一个webpack.dll.js
// 使用dll技术,对某些库(第三方)单独打包
// 当运行webpack时 默认去找webpack.config.js 所有要用 wenpack --config webpack.dell.js
const {resolve} = require('psth')
const webpack = require('webpack')
module.export = {
entry:{
// 最终生产[name] --》 jquery ['jquery'] --> 要打包的库时juqery
jquery:['jquery']
},
output:{
filename:'[name],js'
path:resolve(__dirname,'dll'),
library:'[name]_[hash]' // 打包库里面想外暴露的
},
plugins:[
// 打包生成一个manifest.json --》 提供和jquery映射
new webapck.DllPugin({
name:'[name]_[hash]',
path:resolve(__dirname,'dll/manifest.json') // 输出文件路径
})
],
mode:'production'
}