开发时性能优化
其实在很多文章中,这一步也被划分到了加载性能或者网络层面中,但笔者还是觉得这个东西对于用户来说是没有感知的,只是会影响我们日常开发或者说打包的速度,应该单独提出来说。
这一步其实主要是构建打包方面的问题,其实具体的操作与Vite和Webpack等工具是强耦合的,在此我还是只提方向举一小部分例,具体实现还需要各位针对不同工具去实践
缩小加载范围:配置include/exclude缩小Loader对文件的搜索范围,好处是避免不必要的转译。不然所有node_modules都跑一边那不是卡死了。
打包缓存:很多工具都可以开启打包的缓存,这一步能大大减少构建时间。如Umi的MFSU或者hardsource-webpack-plugin等实现缓存效果的工具都是笔者见过效果立竿见影的。
提前构建:配置DllPlugin将第三方依赖提前打包,好处是将DLL与业务代码完全分离且每次只构建业务代码。(这个玩意儿非常老了,并且我在三年前的实践中就感觉他速度提升不是很明显,可以不用提及)
并行构建:释放CPU多核并发的优势。诸如happyPack、thread-loader 等工具都可以在不同阶段开启CPU多核进行并行构建,大大提升开发时效率。
可视化分析:对打包后的文件大小进行可视化分析,能够更好的分析哪些包比较大,或者小的进行合并。如Vite的rollup-plugin-visualizer、和Webpack的webpack-bundle-analyzer。
Tree-Shaking
基于ES6模板语法(import与exports),主要是借助ES6模块的静态编译思想,
- 编译阶段利用ES6 Module判断哪些模块已经加载,确定模块的依赖关系,以及输入和输出的变量
- 判断那些模块和变量未被使用或者引用,进而删除对应代码,削减项目的体积。
原理
在vue3源码引入tree shaking特性,按需加载组件,将全局 API 进行分块。
// webpack.config.js
module.exports = {
optimization: {
usedExports: true, // 启用Tree Shaking
minimize: true, // 启用代码压缩
},
};- 静态分析:打包工具(如Webpack、Rollup)对项目中的所有ES6模块进行静态分析,构建模块依赖图。
- 标记未使用代码:通过依赖图,标记出未被引用的模块和函数。
- 代码删除:在打包阶段,删除所有标记为未使用的代码。
在Vue2中,无论我们使用什么功能,它们最终都会出现在生产代码中。主要原因是Vue实例在项目中是单例的,捆绑程序不能检测该对象的哪些属性在代码中被使用到。 - ES5 构建: Vue 2的构建版本基于 ES5 ,它不太支持按需引入。
- 组件导入方式: 在 Vue 2中,大部分组件是通过直接引入 Vue 对象的属性来使用的,这导致整个 Vue 对象以及所有的属性都会被包含进最终的构建中,无法精确地按需引入。
- 组件间关系: Vue 2组件在定义和使用时的关系较为复杂,可能会造成不同组件之间的依赖关系和引用关系,这也会影响 Tree-shaking 的效果。
当使用 Vue 时有下面一些办法来减小打包产物体积:
- 尽可能地采用构建步骤
- 如果使用的是相对现代的打包工具,许多 Vue 的 API 都是可以被 tree-shake 的。举例来说,如果你根本没有使用到内置的
组件,它将不会被打包进入最终的产物里。Tree-shaking 也可以移除你源代码中其他未使用到的模块。 - 当使用了构建步骤时,模板会被预编译,因此我们无须在浏览器中载入 Vue 编译器。这在同样最小化加上 gzip 优化下会相对缩小 14kb 并避免运行时的编译开销。
- 如果使用的是相对现代的打包工具,许多 Vue 的 API 都是可以被 tree-shake 的。举例来说,如果你根本没有使用到内置的
- 在引入新的依赖项时要小心包体积膨胀!在现实的应用中,包体积膨胀通常因为无意识地引入了过重的依赖导致的。
- 如果使用了构建步骤,应当尽量选择提供 ES 模块格式的依赖,它们对 tree-shaking 更友好。举例来说,选择 lodash-es 比 lodash 更好。
- 查看依赖的体积,并评估与其所提供的功能之间的性价比。如果依赖对 tree-shaking 友好,实际增加的体积大小将取决于你从它之中导入的 API。像 bundlejs.com 这样的工具可以用来做快速的检查,但是根据实际的构建设置来评估总是最准确的。
- 如果你只在渐进式增强的场景下使用 Vue,并想要避免使用构建步骤,请考虑使用 petite-vue (只有 6kb) 来代替。
webpack来优化前端性能
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。 - 压缩代码:删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的 UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩]S文件,利用cssnano(css-loader?minimize)来压缩css
- 利用CDN加速:在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于 output 参数和各loader的 publicPath 参数来修改资源路径
- Tree Shaking:将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数–optimize-minimize 来实现
- Code Splitting:将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利用浏览器缓存
- 提取公共第三方库: Split Chunks Plugin插件来进行公共模块抽取,利用浏览器缓存可以长期缓存这些无需频繁变动的公共代码
Webpack打包原理。Webpack优化 - 初始化流程:从配置文件和 Shell 语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数
- 编译构建流程:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理
- 输出流程:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统
设计理念与功能:
- Webpack 是一个全能型的模块打包工具,不仅支持 JavaScript 模块的打包,还能处理 CSS、HTML、图片等各种静态资源。
- 提供了丰富的Loader机制,可以转换非JavaScript资源(如Sass转CSS、图片转Base64编码等)。
- 支持代码分割(Code Splitting),可以根据路由懒加载代码块,有效提升页面加载速度。 将构建后的 JavaScript 包拆分为多个较小的,可以按需或并行加载的文件。通过适当的代码分割,页面加载时需要的功能可以立即下载,而额外的块只在需要时才加载,从而提高性能。可以通过分析 ES Module(ESM)动态导入的语法来自动进行代码分割
- 内置了热模块替换(Hot Module Replacement, HMR),实现开发过程中的实时刷新。
- 配合Plugin系统,可以实现复杂的构建流程定制,比如提取公共代码、压缩代码、优化图片等。
Loader与Plugin
- loader 是文件加载器,运行在打包文件之前,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中
- plugin 赋予了 webpack 各种灵活的功能,例如打包优化、资源管理、环境变量注入等,目的是解决 loader 无法实现的其他事,在整个编译周期都起作用
使用场景:
- 大型SPA(Single Page Application)或企业级Web应用,这类项目往往需要处理多种资源和复杂的构建流程。
- 需要做代码分割和按需加载的场景。
- 对于有大量第三方库依赖和复杂业务逻辑的项目。
热模块替换(HMR)原理
- 通过webpack-dev-server创建两个服务器:提供静态资源的服务(express)和Socket服务
- express server 负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)
- socket server 是一个 websocket 的长连接,双方可以通信
- 当 socket server 监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js文件(update chunk)
- 通过长连接,socket server 可以直接将这两个文件主动发送给客户端(浏览器)
- 浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新
rollup和webpack有什么区别
https://juejin.cn/post/7097493230572273700
Rollup
设计理念与功能:
- Rollup 主要是针对库(library)开发设计的,专注于ES6模块规范,采用严格静态分析的方式,因此具有出色的tree-shaking能力。
- 不像Webpack那样内置处理非JavaScript资源的能力,Rollup专注于JavaScript模块的打包和优化,更适合构建无运行时副作用的、纯净的JavaScript库。
- 输出的bundle倾向于更小、更纯净,适合那些希望发布最小化且高效利用模块化的库。
使用场景: - 开发和发布独立的JavaScript库或组件,特别是那些遵循ES6模块规范的库。
- 当项目主要关注代码大小和纯净性,而非需要处理大量非JS资源的时候。
Rollup
Webpack
应用场景
更适合用于库的打包,尤其是那些专注于 ES6 模块的库
能够分析所有的 ES6 模块,删除不需要的代码,并将计算合并在一起,从而产生出更小更快的代码,这样的输出可以在所有的现代浏览器中逐字解析
用于复杂应用的打包,这种应用大多是由多个单独的模块组成的,并且使用了多种资源(例如图片、样式表等)。
Webpack 适合这种复杂应用的打包,因为它能够处理 JavaScript 资源以外的任何文件,同时还支持各种插件,例如代码压缩、代码分离、热更新等等。
打包方式
默认是只生成一个文件,会从入口文件开始遍历整个依赖图,并只将项目的所需部分包含在生成的 JavaScript 文件中。这种方式有效地清除了生成文件不需要的部分并生成更小,更快的输出。
更好地利用 Tree Shaking 等技术消除不必要的代码。
将所有的文件打包在一起,以形成一个或多个文件,这些文件包含了所有的 JavaScript、样式表、图像和字体等等。同时还需要处理比较复杂的代码和依赖关系,还需要进行一系列的优化和处理,比如加载和解析模块,分离出共享代码等,所以 Webpack 会相对慢一些。。
访问速度
输出文件更小,所以它需要更少的时间去下载,同时它不包含任何多余的代码,因此它可以更快地加载和运行。
Webpack 打包后的文件较大,所以它需要花费更长的时间下载。此外,由于其中包含运行时环境,因此它需要时间来解析代码
生态和扩展性
扩展性就比较弱,它不能很好的处理 JavaScript 之外的其他资源,但是我们可以使用一些 Rollup 的插件来帮助我们处理其他类型的文件,来实现更加丰富的功能
扩展性非常强大,它有着众多的插件和 Loader 可以使用,因此我们可以为我们的应用添加各种功能和特性,而不用自己去实现一个
选择Webpack:
- 当项目包含多个资源类型,需要综合处理HTML、CSS、图片等资源时。
- 当项目需要实现复杂的代码分割和动态加载策略时。
- 当项目规模较大,需要高度定制化构建流程时。
选择Rollup: - 当项目主要是编写一个独立的、面向外部发布的JavaScript库时。
- 当你需要最大程度地优化代码大小,去除无用的模块时。
- 当项目比较简单,不涉及过多的非JS资源处理,只需要专注JS模块打包优化时。
Rollup 是 ESModule 的产物,那么为什么 ESModule 会比 CommonJS 快呢?
ESModule 和 CommonJS 都是模块化的标准化方案,但它们在加载模块时的实现方式不同。
CommonJS require 是同步加载模块,也就是说,一个模块在被引入后,引入模块的代码会等待模块加载完成才继续往下执行。
CommonJS 模块是 ESModule 提出前的一种暂时性解决方案,未来发展缓慢。
而 ESModule import 是异步加载模块,它允许浏览器在解析 JavaScript 代码时,将模块的加载放到后台去,让执行线程不被阻塞。这种并行加载的方法能够提高 JavaScript 代码的执行效率。
ESModule 可以在编译时进行静态优化,还支持 Tree shaking,可以在代码打包时删除未使用的代码,从而减少打包后代码的体积和加载时间,这也是 ESModule 比 CommonJS 更快的原因之一。同时还提供了一些高级特性,比如循环引用和实时绑定
最关键的两个原因就是 TreeShaking 和 异步加载
同时 ESModule 的兼容性更佳,在未来将变得更加重要。
vite是怎么实现的
https://blog.csdn.net/weixin_44803406/article/details/135654812
Vite是一个基于ES模块的前端构建工具,与传统的构建工具(如Webpack)不同,Vite在开发模式下使用原生ES模块化。它通过服务端渲染(SSR)将源代码转换为浏览器可识别的模块,实现了快速的启动时间和开发体验。相较于Webpack等工具,Vite在开发环境下提供了更快的冷启动和热模块替换(HMR)。
核心特性
- 极快的开发服务器启动时间:Vite 通过利用 ES Modules 的原生支持,在开发模式下不需要打包整个应用,而是直接在浏览器中加载模块。这大大缩短了开发服务器的启动时间。
- 即时热模块替换(HMR):Vite 提供了几乎即时的热模块替换功能,当你修改代码时,仅更新发生变化的模块,而不是整个页面刷新,从而显著提高开发效率。(Vite通过WebSocket与开发服务器保持连接,当源代码发生变化时,服务器会推送更新的模块到客户端,实现即时的热模块替换,无需刷新整个页面)
- 原生 ES 模块支持:Vite 充分利用了现代浏览器对 ES 模块的原生支持,避免了传统的打包过程,使得开发和生产环境的表现更加一致。
- 插件系统:Vite 支持丰富的插件生态系统,允许开发者根据需要扩展构建过程。
- 多种框架支持:除了 Vue.js,Vite 还支持 React、Svelte 等多种前端框架。
Vite 中的 Tree Shaking 是如何工作的。
A: Tree Shaking是一种通过静态分析代码,删除未使用代码的技术。在 Vite 中,Tree Shaking通过原生ES模块的特性,只导入用到的代码,未使用的代码不会被打包。
如何在 Vite 项目中实现服务端渲染(SSR)?
A: 安装 vite-plugin-vue@ssr 插件,并在配置文件中使用。npm install -D vite-plugin-vue@ssr
// vite.config.js
import VitePluginVue from ‘vite-plugin-vue’;
export default {
plugins: [VitePluginVue({ ssr: true })],
};
如何自定义 Vite 的配置?
在项目根目录下创建 vite.config.js 文件,然后在文件中导出配置对象。
// vite.config.js
export default {
server: { //server用于配置开发服务器,例如端口、代理等。常见的配置项有 port、outDir、proxy 等
port: 3000,
},
build: { // build 主要用于生产环境的配置,包括输出目录、资源引用路径等
outDir: ‘dist’,
},
};
在 Vite 中配置环境变量
在项目根目录下创建 .env 文件,例如 .env.development 和 .env.production,然后在配置文件中使用 import.meta.env 来访问环境变量
// .env.development
VITE_APP_MODE=development
// 在代码中使用
console.log(import.meta.env.VITE_APP_MODE);
Vite 中使用插件
使用 vite.config.js 文件中的 plugins 字段来配置插件
// vite.config.js
import VitePluginSass from ‘vite-plugin-sass’;
export default {
plugins: [VitePluginSass()],
};
用过哪些 Vite 插件?请分享一些你认为有用的插件。
一些常用的插件包括 vite-plugin-compression(用于启用 Gzip 压缩)、vite-plugin-vue(用于 Vue 项目)等。
npm install -D vite-plugin-compression
// vite.config.js
import ViteCompressionPlugin from ‘vite-plugin-compression’;
export default {
plugins: [
ViteCompressionPlugin({
algorithm: ‘gzip’,
ext: ‘.gz’,
}),
],
};
Vite 中进行代码分割(Code Splitting)
Vite默认支持动态导入实现代码分割,也可以手动配置 import.meta.glob 来进行文件的自动导入和分割。
// vite.config.js
export default {
build: {
chunkSizeWarningLimit: 2000,
},
};
Vite 中添加 Sass 支持,你会怎么做
npm install -D vite-plugin-sass
// vite.config.js
import VitePluginSass from ‘vite-plugin-sass’;
export default {
plugins: [VitePluginSass()],
};
Vite 中创建一个新项目?
使用命令 npm create vite my-project,也可以指定模板(如 vue、react)来创建具体的项目。
Vite 是如何支持模块化开发的?有什么优势?
Vite使用原生ES模块化,无需预打包,支持按需加载,提高了开发体验。可以直接在项目中使用 import/export 语法。
怎样在 Vite 中调试独立文件,而不需要重新构建整个项目?
使用命令 vite serve --open src/main.js,其中 src/main.js 指定了入口文件,只会编译和加载该文件及其依赖。
Vite 与 Vue CLI 的提升和区别
Vue CLI 其实包含两个,一个是早期的 Vue CLI,打包基于 webpack,另一个是最新的 CLI,打包基于 vite
Vue CLI 的背后是 vue-cli-service 提供支持
任何包的 package.json 文件中,都有两个参数用来指定入口,分别为:main、lib ,
Main 指定的是包作为依赖时的入口文件配置
lib 指定的是当该包被全局安装时创建软链接的文件。
Vue CLI 是 Vue.js 的一个官方脚手架工具,提供了项目初始化、开发服务器启动、构建等功能。但随着项目规模的增大,Vue CLI 在开发服务器启动和热更新方面逐渐显现出性能瓶颈。Vite 的出现正是为了解决这些问题。
Vite 相较于 Vue CLI 在性能上有显著提升,主要体现在以下几个方面:
- 开发服务器启动时间:Vite 利用 ES 模块的特性,避免了传统打包工具(如 Webpack)的打包过程,从而使开发服务器的启动时间大大缩短。一个简单的 Vue 项目,Vite 可以在几百毫秒内启动,而 Vue CLI 可能需要几秒钟。
- 热更新速度:Vite 的热更新速度几乎是实时的,因为它仅重新加载发生变化的模块。而 Vue CLI 在进行热更新时,可能需要重新打包整个应用,导致更新速度较慢。
Vite
Vue CLI
启动时间
通常只需几百毫秒
通常需要几秒钟到几十秒,取决于项目规模。
构建
比 Vue CLI 快,尤其是在大型项目中
利用了现代浏览器的原生 ES 模块支持,避免了打包过程,从而实现了极快的开发服务器启动时间和即时热更新
通常需要几十秒到几分钟,取决于项目规模
使用 Webpack 进行模块打包,这会导致启动时间较长,尤其是在大型项目中。尽管 Vue CLI 提供了热模块替换(HMR),但在处理大量文件时,HMR 的性能可能不如 Vite。
热模块替换(HMR)
HMR 几乎是即时的,因为它仅重新加载发生变化的模块,而不需要重新打包整个应用
使用 Webpack 的 HMR 机制,虽然功能强大,但在处理大量文件时可能会出现延迟
插件生态
有一个不断增长的插件生态系统,支持 Vue、React、Svelte 等多种框架。Vite 的插件系统设计得非常灵活,允许开发者根据需要扩展构建过程。
丰富的插件生态系统,提供了大量的官方和社区插件,可以满足各种开发需求。Vue CLI 的插件系统基于 Webpack,因此可以集成各种 Webpack 插件
vite和webpack的区别
https://www.wbolt.com/vite-vs-webpack.html
