一. 什么是webpack?
本文代码执行环境:node 10 以上,webpack 4 以上
1.概念
官网的定义:
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。
当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),
其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
大白话理一下:
1)看看你的项目
- 有各种各样的文件格式:
.vue,.js,.css/less/scss/sass
,图片,字体图标…… - 用到了ES6/7/8 语法 or 特性,以及更高级的语法
- 体积庞大的
node_modules
- src文件夹下,业务代码文件的数量惊人
- 开发环境的跨域问题,解决时头发抓到秃
- 控制台爆红,点击进去后发现和自己写的源代码不一样
- 开发时,每次修改代码都要手动刷新浏览器,调个样式调到头皮发麻
- 部署上线时,蹲守公司,王者打到没电,月亮西斜,项目还在打包
- ...
2)试想一下
-
这样的数量的文件直接若是上传到服务器,得传多久?
-
浏览器挨个读取这么多数量的js文件,然后挨个分析,挨个结合这么多数量的css文件,最后组装呈现在用户面前,用户得等多久?
-
ES6/7/8等高级语法浏览器不认识,怎么办?
-
……
3)然后,你突然发现这些问题webpack都轻松搞定了。如图所示
这张图中,webpack做了大量工作
- 文件种类多,业务代码复杂,webpack通过分析依赖进行模块合并,归类后压缩,文件体积变小了
- 高级/新兴语法,webpack进行代码校验,转译,变成浏览器认识的 js
- 考虑到速度痛点,webpack在分析依赖的时候使用了高级手段,大大增速
node_modules
体积庞大,只要你告诉webpack,它就会智能忽略一些你没用到的部分,加快打包速度- webpack在打包的时候还进行了代码分割/分离,多模块共享,防止重复分析/加载
针对上边列举的痛点/问题,贴心的webpack同样解决了
- webpack可以让浏览器自动刷新,而且是局部刷新,让你实时看到代码修改效果
- 开发环境的跨域问题,跨域通过webpack配置轻松解决
- SPA应用,通过按需加载,懒加载,代码分割,使用缓存动态打包等,可以大大加快首屏速度,让你的用户小可爱不再久等
通过上边的一堆文字,此时你的心中应该明白了webpack是干什么的,它有什么用。
世上任何概念的定义,都是从其性质,适用范围,作用来下的。
看到这里的你,脑中已经有了webpack的概念吧?
2. 核心组成
- 入口(Entry)
- 出口(Output)
- loaders
- 插件 (Plugins)
- mode (模式:开发or生产)
- Browser Compatibility 浏览器兼容(webpack5.0新增)
- Environment 环境(webpack5.0新增)
开始配置前,你需要在根目录创建一个 webpack.config.js
文件
2.1 入口与出口
这两个的配置只需要注意两点:出入口数量对应,出入口的路径
数量一致:一入口 VS 一出口,多入口vs 多出口
出入口路径:入口:相对路径;出口:绝对路径
为保证路径准确,需要用到node内置的 path模块,直接require即可
//关于path的用法,小可爱们自行百度
const path = require('path')
// webpack的配置文件遵循着CommonJS规范。什么是ommonJS规范?小可爱们自行百度
module.exports = {
entry: './src/main.js',
output: {
// path.resolve() : 该方法解析当前相对路径的绝对路径
// path.join():用于路径拼接
// output 必须是绝对路径,否则报错
// 方法一:path: path.resolve(__dirname, './dist/'),
// 方法二:path: path.join(__dirname, './dist/'),
filename: 'bundle.js' //指定打包后的文件名
},
}
2.2 loaders
webpack默认只处理js文件,其他非js文件,就需要loaders
出马
(1)注意loaders
的执行顺序:从下到上,从右到左
在平时配置的时候要在查清楚各个loaders的使用前后规则,否则会报错
(2)可以手动干预它们的执行顺序吗?
可以,在use后再加个enforce属性进行配置即可
enforce 可选值:pre:提前;post:后置
(3)webpack 所有类型loaders
的执行顺序:pre > inline > normal > post
inline 指的是在模块中使用
import
等语法导入,进行单独处理的情况,具体小可爱们自行查看官网/百度
(4)通用的配置
无高级语法的情况下
loaders
在webpack的低版本中的写法与现在不同,4,5版本的写法一致,记住以下写法即可
module
与出入口平级:
module : [ rules : [ {test:// , use:[]/''} ]
下面的代码中url-loader
用于处理,归类图片,打包后项目中的图片都会集中放在配置的文件夹下,这里体现了webpack的压缩,归类功能
一定要记住!!!
-
先npm装一下包,然后再配置
-
配置
exclude: /node_modules/
忽略该文件夹的解析,校验和转译,配置后将大大加快打包速度!
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist/'),
filename: 'bundle.js' //指定打包后的文件名
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /\.s(a|c)ss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
// url-loader 基于file-loader 两个功能差不多,只是url-loader 比后者多了些可设置的options
{
test: /\.(jpg|jpeg|png|bmp|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 5 * 1024, //此大小范围内的图片转换成base64,节省请求开销
outputPath: 'images', //dist下创建images文件夹,统一放图片
name: '[name]-[hash:4].[ext]' // 图片文件名+hash值取4位数,ext:原后缀名
}
}
},
{
test: /\.(woff|woff2|eot|svg|ttf)$/,
use: 'url-loader'
},
{
test: /\.js$/,
use: {
loader: 'babel-loader',
// options: {
// presets: ['@babel/env'],
// plugins: [
// '@babel/plugin-proposal-class-properties',
// '@babel/plugin-transform-runtime'
// ]
// }
},
exclude: /node_modules/,
}
]
},
}
(5)不可忽视的 babel
高级语法的情况下
babel 的主要作用用于转译,将高级语法转换成浏览器识别的语法
随着项目的不断扩大,你会发现你不知不觉中用了很多 babel 家族的loader和插件,这个时候官方建议我们在根目录下创建一个.babelrc
文件,专门用来配置babel 家族
有个特别需要注意的点:
配置完babel-loader
后,项目可以转换ES6诸如class定义类这样的语法,但是原型新增的方法[].inculdes()这种,babel 默认是无法转换的,需要装一个补丁polyfill
npm i @babel/polyfill -S
在入口处配置
entry: ['@babel/polyfill', './src/main.js'],
或者,在使用新方法的地方引入:
import '@babel/polyfill'
webpack 官方说5.x以后将取消这个补丁,粗略看了一下更新好像没有移除,辛苦小可爱们给我科普一下,这个补丁后来怎么样了
2.3 插件 (Plugins)
loader做不到的事,插件做!
步骤:
- npm装包
- webapck官网查看你装的包怎么配置
这一块,实在不知不知道还要讲啥,就上图示范一下配置位置吧
plugins 与出入口平级
const path = require('path')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist/'),
filename: 'bundle.js' //指定打包后的文件名
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /\.s(a|c)ss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
// url-loader 基于file-loader 两个功能差不多,只是url-loader 比后者多了些可设置的options
{
test: /\.(jpg|jpeg|png|bmp|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 5 * 1024, //此大小范围内的图片转换成base64,节省请求开销
outputPath: 'images', //dist下创建images文件夹,统一放图片
name: '[name]-[hash:4].[ext]' // 图片文件名+hash值取4位数,ext:原后缀名
}
}
},
{
test: /\.(woff|woff2|eot|svg|ttf)$/,
use: 'url-loader'
},
{
test: /\.js$/,
use: {
loader: 'babel-loader',
// options: {
// presets: ['@babel/env'],
// plugins: [
// '@babel/plugin-proposal-class-properties',
// '@babel/plugin-transform-runtime'
// ]
// }
},
exclude: /node_modules/,
}
]
},
plugins: [
//以下插件是举例:
new CleanWebpackPlugin(),
new CopyWebpackPlugin([{
from: path.join(__dirname, 'assets'),
to: 'assets'
}]),
],
}
特意将整段代码贴上,让小可爱们有个直观的认识。
二. webpack高级配置(性能优化方向)
其实就是各种loader和插件的组合
我太饿了 ,我先去吃饭了,后续补充