webpack学习
webpack
webpack本身
- 支持CommonJs语法
- 只能编译js json,
- js的es语法,这样可以让浏览器识别es语法,但是对于ES6老浏览器不支持,需要用babel转成ES5
Loader
处理css资源
npm i css-loader style-loader -D
1
2
3
4
5
6
7
8
9
10
2. ```js
//使用loader
rules: [{
//test: 正则匹配 文件
//use: 按数组顺序从右向左执行
test: /\.css$/,
use: ['style-loader','css-loader']
}
],public/index.html
下引入1
2<!-- 导入webpack打包的文件 -->
<script src="../dist/index.js"></script>在
src/index.js
下导入1
import './css/index.css'
打包
1
npx webpack
style-loader
的作用是把CSS
插入到DOM
中,就是处理css-loader
导出的模块数组,然后将样式通过style
标签或者其他形式插入到DOM
中。
处理sass
npm i sass-loader sass -D
1
2
3
4
5
6
7
8
9
10
2. ```js
//使用loader
rules: [{
//test: 正则匹配 文件
//use: 按数组顺序从右向左执行
test: /\.less$/,
use: ['style-loader','css-loader','less-loader']
}
],
less-loader的作用:把less转化成css
sass 的作用:less-loader依赖包
处理stylus
npm i stylus-loader -D
1
2
3
4
5
6
2. ```js
{
test: /\.styl$/,
use: ['style-loader','css-loader','stylus-loader']
},
处理图片
file-loader
url-loader
已内置在webpack5里面
1 | { |
打包后:/dist下出现了图片
而样式文件被打包到index.js 文件里了
把小图片转换成base64
优缺:减少请求,文件体积变大
1 | { |
Babel
作用:ES6 => ES5
npm i babel-loader @babel/core @babel/preset-env -D
1
2
3
4
5
6
7
8
9
2. `webpack.config.js `导入babel loader
```js
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},在根目录下新建
babel.config.js
1
2
3
4module.exports = {
//预设
presets: ['@babel/preset-env'],
}@babel/preset-env
: 一个智能预设,允许您使用最新的 JavaScript。@babel/preset-react
:一个用来编译 React jsx 语法的预设@babel/preset-typescript
:一个用来编译 TypeScript 语法的预设
Webpack配置
1 | //webpack 配置文件使用CommonJs语法 |
type: "asset/resource"
将文件转化成 Webpack 能识别的资源,其他不做处理type: "asset"
相当于url-loader
, 将文件转化成 Webpack 能识别的资源,同时小于某个大小的资源会处理成 data URI (base64)形式mode
- none: 此时webpack不会对入口文件进行任何的优化,webpack直接把模块打包至数组之中
- development: 它实现了3个插件功能
- NamedModulesPlugin 对打包出来的模块加上名字
- NamedChunksPlugin 对每个chunks命名
- DefinePlugin 对环境变量
process.env.NODE_ENV
的值设置为'development'
[ hash:8 ]: hash值取8位, 文件名长度
[ chunkhash] :根据一个入口文件一个hash
[ contenthash ] : 根据内容生成hash
Plugin
Eslint
npm i eslint-webpack-plugin eslint -D
1
2
3
4
5
6
7
8
9
10
11
12
2. `webpack.config.js `导入eslint 插件
```js
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
module.export = {
...
plugin: [{new ESLintWebpackPlugin({
//指定要检查的根目录
context: path.resolve(__dirname, "src")
})},]
}在根目录下新建
.eslintrc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38module.exports = {
//1. 解析选项
parserOptions: {
ecmaVersion: 6,
sourceType: "module", //ES模块化
ecmaFeatures: {
jsx: true //ES其他特性-jsx
}
},
/* 2. 检查规则
off / 0 关闭规则
warn/ 1 开启规则,报警告
error/2 开启规则,直接报错
*/
rules: {
semi: "off", //是否使用分号
'array-callback-return': 'warn',//数组方法回调函数里有return
'default-case': [//switch-case 语法必须要有default
'warn',
{commentPattern: '^no default$'} //允许在最后注释no default,就不会报警告
],
eqeqeq: [
'warn', //强制使用=== 和 !==
'smart', //少数情况不会报警告
],
'no-var': 'error'//禁止使用var定义变量
},
/* 3. 继承其他规则
Eslint官方规则: eslint:recommended
VueCli : plugin:vue/essential
ReactCli: react-app
*/
extends :['eslint:recommended'],
env: {
node: true, //启用node中全局变量
browser: true, //启用浏览器中全局变量
},
}
处理HTML资源
生成的index.html有两个特性
内容与public/index.html 一致
自动引入打包好的js等资源
使用
npm i html-webpack-plugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2. ```js
//webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin")
...
{
new HtmlWebpackPlugin({
template: "./public/index.html",
filename: "index.html",
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true,
removeComments: true
}
})
}
处理CSS—高级
提取css
index.js 引入css文件,然后index.html再引入index.js的模式会创建一个style标签来生成样式,可能会有闪屏现象
npm i mini-css-extract-plugin -D
1
2
3
4
5
6
7
8
9
10
11
12
13
2. ```js
//webpack.prod.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
...
MiniCssExtractPlugin.loader替换掉所有"style-loader"
...
plugins: [
new MiniCssExtractPlugin({
//输出目录和文件名
filename: "src/index.css"
})
]
兼容性处理
npm i postcss-loader postcss postcss-preset-env -D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2. ```js
//webpack.prod.js
rules: [{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader',
//放在所有css-loader后面
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
//可解决大多数兼容问题
"postcss-preset-env"
]
}
}
}]
},
...
]
兼容性控制
1 | /* package.json */ |
合并配置
1 | //webpack.prod.js |
filter 相当于 arr.filter(item=>Boolean(item)) 可以过滤所有Boolean()返回false的值: 例如
0
false
null
undefined
''
``
开发服务器&自动化
npm i webpack-dev-server -D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2. ```js
//webpack.config.js
devServer: {
host: "localhost",
port: 8080,
open: true, //是否自动打开浏览器
hot: true, //是否开启热更新
//自动刷新
// proxy: {
// '/api': {
// target: 'http://localhost:3000',
// changeOrigin: true,
// pathRewrite: {
// '^/api': ''
// }
// }
// }
},npx webpack server
1
2
3
4
5
6
7
8
9
10
11
### 开发和生产环境
在`/config/webpack.prod.js` `/config/webpack.dev.js`
运行对应配置:
```shell
npx webpack --config ./config/webpack.prod.js
配置脚本
1 | //package.json |
减少代码体积
SourceMap
构建后的文件内容和开发时的代码的映射文件
1 | //webpack.config.js |
- cheap-module-source-map: 只包含行映射,打包快
- source-map:包含行列映射
HotModuleReplacement
webpack默认修改后重新打包所有模块
配置后:让开发时只重新编译打包更新变化了的代码,不变的代码使用缓存,从而使更新速度更快。
1 | //webpack.config.js |
此时css以及可以热HMR了,但是js不行,
一般用vue-loader 或者 react-hot-loader 来
OneOf
一个文件有可能被多个rules命中,所以每个文件要和所有规则去test一次
配置后:一个文件只要匹配到一个loader就不继续匹配了
1 | module.exports= { |
Cache
每次打包js要经过Eslint和Babel
配置后:可以缓存之前的Eslint检查和Babel编译结果,打包变快
1 | //webpack.config.js |
Threads
对 js 文件处理主要就是 eslint 、babel、Terser 三个工具,所以我们要提升它们的运行速度。
我们可以开启多进程同时处理 js 文件,这样速度就比之前的单进程打包更快了
略。。。
Tree Shaking
是一个术语,通常用于描述移除 JavaScript 中的没有使用上的代码。
引用第三方工具函数库或组件库,如果没有特殊处理的话我们打包时会引入整个库,但是实际上可能我们可能只用上极小部分的功能
依赖ES Module
webpack 默认开启
优化代码运行性能
code split
将所有 js 文件打包到一个文件中,体积太大了
渲染哪个页面就只加载某个 js 文件,这样加载的资源就少,速度就更快。
实现了:
- 分割文件
- 按需加载
1. 多入口
几个entry,就有几个output
npm i webpack webpack-cli html-webpack-plugin -D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2. 修改配置文件
```js
//webpack.config.js
module.exports= {
entry: {
//两个入口文件
main: './src/main.js',
index: './src/index.js'
},
output: {
path: path.resolve(__dirname, "../dist"),
filename: "src/[name].js",
clean: true
}
}
2. 提取重复代码
如果多个入口文件用到同一份代码,我们不希望这份代码被打包到两个文件中,导致代码重复
我们需要提取多入口的重复代码生成一个 js 文件,其他文件引用它就好。
1 | //webpack.config.js |
3. 按需加载,动态导入
动态导入
1 | import("./math.js").then({sum}=>{ |
动态导入文件命名
1 | // webpackChunkName: "math":这是webpack动态导入模块命名的方式 |
这种写法会导致eslint报错:webpack.config.js里取消使用Eslint
命名配置
1 | //webpack.config.js |
打包出来的文件会叫作:math.chunk.js
runtime 文件
如果:a.js 导入了 b.js ,那么b文件修改后,b的hash值发生变化,a导入b时也会发送变化,所以a和b的都发生了更新。这是我们不想看到的。
runtime文件 里面保存 文件地址,这样当某文件改变时,只有该文件和runtime文件会改变,其他文件不会改变hash值
1 | //webpack.config.js |
Core.js
babel对Es6 的箭头函数,import等编译,但是对于es7的await/async proimise等一些无法解决
core-js
是专门用来做 ES6 以及以上 API 的polyfill
。polyfill
翻译过来叫做垫片/补丁。就是用社区上提供的一段代码,让我们在不兼容某些新特性的浏览器上,使用该新特性。
npm i core-js
1
2
3
4
5
2. ```js
//需要兼容的js文件里
import "core-js" //全局引入
import "core-js/es/promise" //局部引入
PWA
在 离线(offline) 时应用程序能够继续运行功能。
内部通过 Service Workers 技术实现的。
npm i workbox-webpack-plugin -D
1
2
3
4
5
6
7
8
9
10
11
12
2. ```js
//webpack.config.js
const WorkboxPlugin = require("workbox-webpack-plugin");
//plugins 中
new WorkboxPlugin.GenerateSW({
// 这些选项帮助快速启用 ServiceWorkers
// 不允许遗留任何“旧的” ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),//index.js 中 if("serviceWorker" in navigator) { window.addEventListener("load",()=> { navigator.serviceWorker.register("/dist/service-worker.js") .then((registration)=> { console.log("SW registered", registration) }).catch((registrationError)=> { console.log("SW registraion failed: ", registrationError); }) }) }
总结
我们从 4 个角度对 webpack 和代码进行了优化:
提升开发体验
- 使用
Source Map
让开发或上线时代码报错能有更加准确的错误提示。
提升 webpack 提升打包构建速度
- 使用
HotModuleReplacement
让开发时只重新编译打包更新变化了的代码,不变的代码使用缓存,从而使更新速度更快。 - 使用
OneOf
让资源文件一旦被某个 loader 处理了,就不会继续遍历了,打包速度更快。 - 使用
Include/Exclude
排除或只检测某些文件,处理的文件更少,速度更快。 - 使用
Cache
对 eslint 和 babel 处理的结果进行缓存,让第二次打包速度更快。 - 使用
Thead
多进程处理 eslint 和 babel 任务,速度更快。(需要注意的是,进程启动通信都有开销的,要在比较多代码处理时使用才有效果)
减少代码体积
- 使用
Tree Shaking
剔除了没有使用的多余代码,让代码体积更小。 - 使用
@babel/plugin-transform-runtime
插件对 babel 进行处理,让辅助代码从中引入,而不是每个文件都生成辅助代码,从而体积更小。 - 使用
Image Minimizer
对项目中图片进行压缩,体积更小,请求速度更快。(需要注意的是,如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。)
优化代码运行性能
- 使用
Code Split
对代码进行分割成多个 js 文件,从而使单个文件体积更小,并行加载 js 速度更快。并通过 import 动态导入语法进行按需加载,从而达到需要使用时才加载该资源,不用时不加载资源。 - 使用
Preload / Prefetch
对代码进行提前加载,等未来需要使用时就能直接使用,从而用户体验更好。 - 使用
Network Cache
能对输出资源文件进行更好的命名,将来好做缓存,从而用户体验更好。 - 使用
Core-js
对 js 进行兼容性处理,让我们代码能运行在低版本浏览器。 - 使用
PWA
能让代码离线也能访问,从而提升用户体验。