1.底层的语言
webpack
是基于nodejs
构建,js
是以毫秒计数。
vite
是基于esbulid
预构建依赖,esbulid
是采用go
语言编写的,go
语言是纳秒级别的。
因为js
是毫秒级别,go
语言是纳秒级别。所以vite
比webpack
打包器快10-100倍。
2.打包过程
webpack:分析各个模块之间的依赖=>然后进行编译打=>打包后的代码在本地服务器渲染。随着模块增多,打包的体积变大,造成热更新速度变慢。
vite:启动服务器=>请求模块时按需动态编译显示。(vite遵循的是ES Modlues模块规范来执行代码,不需要打包编译成es5模块即可在浏览器运行。)
vite启动的时候不需要分析各个模块之间的依赖关系、不需要打包编译。vite可按需动态编译缩减时间。当项目越复杂、模块越多的情况下,vite明显优于webpack
3.热更新
webpack:模块以及模块依赖的模块需重新编译
vite:浏览器重新请求该模块即可
4.使用方面
vite开箱即用,更加简单,基于浏览器esm,使得hmr更加优秀,达到极速的效果;
webpack更加灵活,api以及插件生态更加丰富。
5.原理不同
webpack是bundle,自己实现了一套模块导入导出机制。
vite是利用浏览器的esm能力,是bundless。
打包速度优化:
1、使用高版本的webpack和Node.js
2、多进程打包:happyPack或thread-loader
3、多进程并行压缩:parallel-uglify-plugin、uglifyjs-webpack-plugin 开启 parallel 参数、terser-webpack-plugin 开启 parallel 参数
4、预编译资源模块:DLLPlugin
5、缓存(babel-loader、terser-webpack-plugin、cache-loader)
6、exclude、include缩小构建目标,noParse忽略、IgnorePlugin
7、resolve配置减少文件搜索范围(alias、modules、extensions、mainFields)
打包体积优化:
1、Tree-shaking擦除无用代码
2、Scope Hoisting优化代码
3、图片压缩(image-webpack-loader)
4、公共资源提取(CommonsChunkPlugin)
5、动态Polyfill
6、分包设置Externals,使用 html-webpack-externals- plugin,将 react、react-dom 基础包通过 cdn 引入,不打入 bundle 中
7、删除无用CSS代码(purgecss-webpack-plugin)
8、JS、CSS压缩(UglifyJsPlugin(3)、terser-webpack-plugin(4)、optimize-css-assets-webpack-plugin)
HtmlWebpackPlugin:将打包后的JS、CSS等文件自动注入到HTML文件中,方便开发者使用。
MiniCssExtractPlugin:将CSS文件从JS文件中分离出来,避免JS文件过大,提高页面加载速度。
CleanWebpackPlugin:每次打包前清空输出目录,避免旧文件对新文件的影响。
DefinePlugin:定义全局变量,方便在代码中使用。
HotModuleReplacementPlugin:热更新插件,可以在不刷新页面的情况下更新代码,提高开发效率。
UglifyJsPlugin:压缩JS代码,减小文件体积,提高页面加载速度。
CopyWebpackPlugin:将静态资源文件复制到输出目录中,方便开发者使用。
通过webpack
优化前端的手段有:
terser
是一个JavaScript
的解释、绞肉机、压缩机的工具集,可以帮助我们压缩、丑化我们的代码,让bundle
更小
在production
模式下,webpack
默认就是使用 TerserPlugin
来处理我们的代码的。如果想要自定义配置它,配置方法如下:
1const TerserPlugin = require('terser-webpack-plugin')
2module.exports = {
3 ...
4 optimization: {
5 minimize: true,
6 minimizer: [
7 new TerserPlugin({
8 parallel: true // 电脑cpu核数-1
9 })
10 ]
11 }
12}
属性介绍如下:
CSS
压缩通常是去除无用的空格等,因为很难去修改选择器、属性的名称、值等
CSS的压缩我们可以使用另外一个插件:css-minimizer-webpack-plugin
1npm install css-minimizer-webpack-plugin -D
配置方法如下:
1const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
2module.exports = {
3 // ...
4 optimization: {
5 minimize: true,
6 minimizer: [
7 new CssMinimizerPlugin({
8 parallel: true
9 })
10 ]
11 }
12}
使用HtmlWebpackPlugin
插件来生成HTML
的模板时候,通过配置属性minify
进行html
优化
1module.exports = {
2 ...
3 plugin:[
4 new HtmlwebpackPlugin({
5 ...
6 minify:{
7 minifyCSS:false, // 是否压缩css
8 collapseWhitespace:false, // 是否折叠空格
9 removeComments:true // 是否移除注释
10 }
11 })
12 ]
13}
设置了minify
,实际会使用另一个插件html-minifier-terser
对文件的大小进行压缩,减少http
传输过程中宽带的损耗
1npm install compression-webpack-plugin -D
1new ComepressionPlugin({
2 test:/\.(css|js)$/, // 哪些文件需要压缩
3 threshold:500, // 设置文件多大开始压缩
4 minRatio:0.7, // 至少压缩的比例
5 algorithm:"gzip", // 采用的压缩算法
6})
一般来说在打包之后,一些图片文件的大小是远远要比 js
或者 css
文件要来的大,所以图片压缩较为重要
配置方法如下:
1module: {
2 rules: [
3 {
4 test: /\.(png|jpg|gif)$/,
5 use: [
6 {
7 loader: 'file-loader',
8 options: {
9 name: '[name]_[hash].[ext]',
10 outputPath: 'images/',
11 }
12 },
13 {
14 loader: 'image-webpack-loader',
15 options: {
16 // 压缩 jpeg 的配置
17 mozjpeg: {
18 progressive: true,
19 quality: 65
20 },
21 // 使用 imagemin**-optipng 压缩 png,enable: false 为关闭
22 optipng: {
23 enabled: false,
24 },
25 // 使用 imagemin-pngquant 压缩 png
26 pngquant: {
27 quality: '65-90',
28 speed: 4
29 },
30 // 压缩 gif 的配置
31 gifsicle: {
32 interlaced: false,
33 },
34 // 开启 webp,会把 jpg 和 png 图片压缩为 webp 格式
35 webp: {
36 quality: 75
37 }
38 }
39 }
40 ]
41 },
42 ]
43}
Tree Shaking
是一个术语,在计算机中表示消除死代码,依赖于ES Module
的静态语法分析(不执行任何的代码,可以明确知道模块的依赖关系)
在webpack
实现Trss shaking
有两种不同的方案:
两种不同的配置方案, 有不同的效果
配置方法也很简单,只需要将usedExports
设为true
1module.exports = {
2 ...
3 optimization:{
4 usedExports
5 }
6}
使用之后,没被用上的代码在webpack
打包中会加入unused harmony export mul
注释,用来告知 Terser
在优化时,可以删除掉这段代码
如下面sum
函数没被用到,webpack
打包会添加注释,terser
在优化时,则将该函数去掉
预览
sideEffects
用于告知webpack compiler
哪些模块时有副作用,配置方法是在package.json
中设置sideEffects
属性
如果sideEffects
设置为false,就是告知webpack
可以安全的删除未用到的exports
如果有些文件需要保留,可以设置为数组的形式
1"sideEffecis":[ "./src/util/format.js", "*.css" // 所有的css文件]
上述都是关于javascript
的tree shaking
,css
同样也能够实现tree shaking
css
进行tree shaking
优化可以安装PurgeCss
插件
1npm install purgecss-plugin-webpack -D
1const PurgeCssPlugin = require('purgecss-webpack-plugin')module.exports = { ... plugins:[ new PurgeCssPlugin({ path:glob.sync(`${path.resolve('./src')}/**/*`), {nodir:true}// src里面的所有文件 satelist:function(){ return { standard:["html"] } } }) ]}
将代码分离到不同的bundle
中,之后我们可以按需加载,或者并行加载这些文件
默认情况下,所有的JavaScript
代码(业务代码、第三方依赖、暂时没有用到的模块)在首页全部都加载,就会影响首页的加载速度
代码分离可以分出出更小的bundle
,以及控制资源加载优先级,提供代码的加载性能
这里通过splitChunksPlugin
来实现,该插件webpack
已经默认安装和集成,只需要配置即可
默认配置中,chunks仅仅针对于异步(async)请求,我们可以设置为initial或者all
1module.exports = { ... optimization:{ splitChunks:{ chunks:"all" } }}
splitChunks
主要属性有如下:
可以通过InlineChunkHtmlPlugin
插件将一些chunk
的模块内联到html
,如runtime
的代码(对模块进行解析、加载、模块信息相关的代码),代码量并不大,但是必须加载的
1const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin')const HtmlWebpackPlugin = require('html-webpack-plugin')mod
webpack-dev-server
创建两个服务器:提供静态资源的服务(express)和Socket服务webpack proxy
,即webpack
提供的代理服务
基本行为就是接收客户端发送的请求后转发给其他服务器
其目的是为了便于开发者在开发模式下解决跨域问题(浏览器安全策略限制)
想要实现代理首先需要一个中间服务器,webpack
中提供服务器的工具为webpack-dev-server
webpack-dev-server
是 webpack
官方推出的一款开发工具,将自动编译和自动刷新浏览器等一系列对开发友好的功能全部集成在了一起
目的是为了提高开发者日常的开发效率,只适用在开发阶段
关于配置方面,在webpack
配置对象属性中通过devServer
属性提供,如下:
1// ./webpack.config.js
2const path = require('path')
3
4module.exports = {
5 // ...
6 devServer: {
7 contentBase: path.join(__dirname, 'dist'),
8 compress: true,
9 port: 9000,
10 proxy: {
11 '/api': {
12 target: 'https://api.github.com'
13 }
14 }
15 // ...
16 }
17}
devServetr
里面proxy
则是关于代理的配置,该属性为对象的形式,对象中每一个属性就是一个代理的规则匹配
属性的名称是需要被代理的请求路径前缀,一般为了辨别都会设置前缀为 /api
,值为对应的代理匹配规则,对应如下:
proxy
工作原理实质上是利用http-proxy-middleware
这个http
代理中间件,实现请求转发给其他服务器
举个例子:
在开发阶段,本地地址为http://localhost:3000
,该浏览器发送一个前缀带有/api
标识的请求到服务端获取数据,但响应这个请求的服务器只是将请求转发到另一台服务器中
1const express = require('express');
2const proxy = require('http-proxy-middleware');
3
4const app = express();
5
6app.use('/api', proxy({target: 'http://www.example.org', changeOrigin: true}));
7app.listen(3000);
8
9// http://localhost:3000/api/foo/bar -> http://www.example.org/api/foo/bar
在开发阶段, webpack-dev-server
会启动一个本地开发服务器,所以我们的应用在开发阶段是独立运行在 localhost
的一个端口上,而后端服务又是运行在另外一个地址上
所以在开发阶段中,由于浏览器同源策略的原因,当本地访问后端就会出现跨域请求的问题
通过设置webpack proxy
实现代理请求后,相当于浏览器与服务端中添加一个代理者
当本地发送请求的时候,代理服务器响应该请求,并将请求转发到目标服务器,目标服务器响应数据后再将数据返回给代理服务器,最终再由代理服务器将数据响应给本地
预览
在代理服务器传递数据给本地浏览器的过程中,两者同源,并不存在跨域行为,这时候浏览器就能正常接收数据
注意:服务器与服务器之间请求数据并不会存在跨域行为,跨域行为是浏览器安全策略限制
loader
用于对模块的"源代码"进行转换,在 import
或"加载"模块时预处理文件
webpack
做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。如下图所示:
预览
在webpack
内部中,任何文件都是模块,不仅仅只是js
文件
默认情况下,在遇到import
或者load
加载模块的时候,webpack
只支持对js
文件打包
像css
、sass
、png
等这些类型的文件的时候,webpack
则无能为力,这时候就需要配置对应的loader
进行文件内容的解析
在加载模块的时候,执行顺序如下:
预览
当 webpack
碰到不识别的模块的时候,webpack
会在配置的中查找该文件解析规则
关于配置loader
的方式有三种:
关于loader
的配置,我们是写在module.rules
属性中,属性介绍如下:
rules
是一个数组的形式,因此我们可以配置很多个loader
loader
对应一个对象的形式,对象属性test
为匹配的规则,一般情况为正则表达式use
针对匹配到文件类型,调用对应的 loader
进行处理代码编写,如下形式:
1module.exports = {
2 module: {
3 rules: [
4 {
5 test: /\.css$/,
6 use: [
7 { loader: 'style-loader' },
8 {
9 loader: 'css-loader',
10 options: {
11 modules: true
12 }
13 },
14 { loader: 'sass-loader' }
15 ]
16 }
17 ]
18 }
19};
这里继续拿上述代码,来讲讲loader
的特性
从上述代码可以看到,在处理css
模块的时候,use
属性中配置了三个loader
分别处理css
文件
因为loader
支持链式调用,链中的每个loader
会处理之前已处理过的资源,最终变为js
代码。顺序为相反的顺序执行,即上述执行方式为sass-loader
、css-loader
、style-loader
除此之外,loader
的特性还有如下:
package.json
的 main
来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用 loader
字段直接引用一个模块可以通过 loader 的预处理函数,为 JavaScript 生态系统提供更多能力。用户现在可以更加灵活地引入细粒度逻辑,例如:压缩、打包、语言翻译和更多其他特性
在页面开发过程中,我们经常性加载除了js
文件以外的内容,这时候我们就需要配置响应的loader
进行加载
常见的loader
如下:
下面给出一些常见的loader
的使用:
分析 css
模块之间的关系,并合成⼀个 css
1npm install --save-dev css-loader
1rules: [
2 ...,
3 {
4 test: /\.css$/,
5 use: {
6 loader: "css-loader",
7 options: {
8 // 启用/禁用 url() 处理
9 url: true,
10 // 启用/禁用 @import 处理
11 import: true,
12 // 启用/禁用 Sourcemap
13 sourceMap: false
14 }
15 }
16 }
17]
如果只通过css-loader
加载文件,这时候页面代码设置的样式并没有生效
原因在于,css-loader
只是负责将.css
文件进行一个解析,而并不会将解析后的css
插入到页面中
如果我们希望再完成插入style
的操作,那么我们还需要另外一个loader
,就是style-loader
把 css-loader
生成的内容,用 style
标签挂载到页面的 head
中
1npm install --save-dev style-loader
1rules: [
2 ...,
3 {
4 test: /\.css$/,
5 use: ["style-loader", "css-loader"]
6 }
7]
同一个任务的 loader
可以同时挂载多个,处理顺序为:从右到左,从下往上
开发中,我们也常常会使用less
、sass
、stylus
预处理器编写css
样式,使开发效率提高,这里需要使用less-loader
1npm install less-loader -D
1rules: [
2 ...,
3 {
4 test: /\.css$/,
5 use: ["style-loader", "css-loader","less-loader"]
6 }
7]
在 webpack
中通过 import
方式导入文件内容,该loader
并不是内置的,所以首先要安装
1npm install --save-dev raw-loader
然后在 webpack.config.js 中进行配置
1module.exports = { ..., module: { rules: [ { test: /\.(txt|md)$/, use: 'raw-loader' } ] }}
把识别出的资源模块,移动到指定的输出⽬目录,并且返回这个资源在输出目录的地址(字符串)
1npm install --save-dev file-loader
1rules: [ ..., { test: /\.(png|jpe?g|gif)$/, use: { loader: "file-loader", options: { // placeholder 占位符 [name] 源资源模块的名称 // [ext] 源资源模块的后缀 name: "[name]_[hash].[ext]", //打包后的存放位置 outputPath: "./images", // 打包后文件的 url publicPath: './images', } } }]
可以处理理 file-loader
所有的事情,但是遇到图片格式的模块,可以选择性的把图片转成 base64
格式的字符串,并打包到 js
中,对小体积的图片比较合适,大图片不合适。
1npm install --save-dev url-loader
复制1rules: [ ..., { test: /\.(png|jpe?g|gif)$/, use: { loader: "url-loader", options: { // placeholder 占位符 [name] 源资源模块的名称
webpack
是一个用于现代JavaScript
应用程序的静态模块打包工具
这里的静态模块指的是开发阶段,可以被 webpack
直接引用的资源(可以直接被获取打包进bundle.js
的资源)
当 webpack
处理应用程序时,它会在内部构建一个依赖图,此依赖图对应映射到项目所需的每个模块(不再局限js
文件),并生成一个或多个 bundle
webpack
的能力:编译代码能力,提高效率,解决浏览器兼容问题
模块整合能力,提高性能,可维护性,解决浏览器频繁请求文件的问题
万物皆可模块能力,项目维护性增强,支持不同种类的前端模块类型,统一的模块化方案,所有资源文件的加载都可以通过代码控制
不同的作用:
loader
。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。不同的用法:
module.rules
中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object
,里面描述了对于什么类型的文件(test
),使用什么加载(loader
)和使用的参数(options
)plugins
中单独配置。 类型为数组,每一项是一个plugin
的实例,参数都通过构造函数传入。WebPack是一个模块打包工具,可以使用 WebPack管理模块依赖,并编译输岀模块所需的静态文件。它能够很好地管理与打包Web开发中所用到的HTML、 JavaScript 、CSS以及各种静态文件(图片、字体等),让开发过程更加高效。对于不同类型的资源, WebPack有对应的模块加载器。Web Pack模块打包器会分析模块间的依赖关系,最后生成优化且合并后的静态资源。
WebPack的两大特色如下。
(1)代码切割( code splitting)
(2) loader可以处理各种类型的静态文件,并且支持串行操作WebPack以 CommonJS规范来书写代码,但对 AMD/CMD的支持也很全面,方便对项目进行代码迁移。
WebPack具有 require.js和 browserify的功能,但也有很多自己的新特性,
(1)对 CommonJS、AMD、ES6的语法实现了兼容。
(2)对 JavaScript、CSS、图片等资源文件都支持打包
(3)串联式模块加载器和插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、 EMAScript 6的支持
(4)有独立的配置文件 webpack.config. js。
(5)可以将代码切割成不同的块,实现按需加载,缩短了初始化时间。
(6)支持 SourceUrls和 SourceMaps,易于调试。
(7)具有强大的 Plugin接口,大多是内部插件,使用起来比较灵活
(8)使用异步I/O,并具有多级缓存,这使得 WebPack速度很快且在增量编译上更加快。