1、如何理解webpack
webpack 是一个静态模块打包工具,会从入口点构建一个 依赖图,把项目中所需的每一个模块组合成一个或多个 bundles。可以用来管理模块依赖,并编译输出模块们所需要的静态文件。可以通过loader、plugin增强webpack的能力。
2、webpack打包过程
plugin:
用于增强webpack的能力,比如打包优化和代码压缩等
区别:
4、webpack优化
压缩文件
1、JS代码压缩;webpack默认压缩了js代码,可以手动调整配置
2、CSS代码压缩;使用css-minimizer-webpack-plugin
3、Html文件代码压缩;使用css-minimizer-webpack-plugin
4、图片压缩;使用image-webpack-loader
Tree Shaking
1、打包过程中检测工程中没有引用过的模块并进行标记,在资源压缩时将它们从最终的bundle中去掉(只能对ES6 Modlue生效) 开发中尽可能使用ES6 Module的模块,提高tree shaking效率
2、禁用 babel-loader 的模块依赖解析,否则 Webpack 接收到的就都是转换过的 CommonJS 形式的模块,无法进行 tree-shaking
代码分离
通过splitChunksPlugin来实现,该插件webpack已经默认安装和集成,只需要配置即可。默认情况下,所有的JavaScript代码(业务代码、第三方依赖、暂时没有用到的模块)在首页全部都加载,就会影响首页的加载速度。如果可以分出出更小的bundle,以及控制资源加载优先级,从而优化加载性能。
5、SourcMap
简单来说,Sourcemap 就是一个信息文件,它里面存储着代码转换前后的对应位置信息,也就是转换压缩后的代码所对应的转换前的源代码位置,是源代码和生产代码的映射, Sourcemap 解决了在打包过程中,代码经过压缩,去空格以及 babel 编译转化后,由于代码之间差异性过大,debug 困难的问题。
sourceMap的格式如下:
{
version : 3, //SourceMap的版本,目前为3
sources: ["foo.js", "bar.js"], //转换前的文件,该项是一个数组,表示可能存在多个文件合并
names: ["src", "maps", "are", "fun"], //转换前的所有变量名和属性名
mappings: "AACvB,gBAAgB,EAAE;AAClB;", //记录位置信息的字符串
file: "out.js", //转换后的文件名
sourcesContent: ["\t// The module cache\n", "xxx"], //转换前的文件内容列表,与sources列表依次对应
sourceRoot : "" //转换前的文件所在的目录。如果与转换前的文件在同一目录,该项为空
}
mappings位置信息详见
6、webpack热更新
轻松理解webpack热更新原理
热更新原理解析
核心流程:
1、使用 webpack-dev-server (后面简称 WDS)托管静态资源,同时以 Runtime 方式注入 HMR 客户端代码;
2、浏览器加载页面后,与 WDS 建立 WebSocket 连接;
3、Webpack 调用compiler.watch方法 监听到文件变化后,增量构建发生变更的模块,并通过 WebSocket 发送 hash 事件;
4、浏览器接收到 hash 事件后,请求 manifest 资源文件,确认增量变更范围;
5、浏览器加载发生变更的增量模块;
6、Webpack 运行时触发变更模块的 module.hot.accept 回调,执行代码变更逻辑;
** 7、Rollup和webpack异同**
8、Vite为什么会比webpack快
9、vue-cli和vite
10、vite原理
深入理解Vite核心原理
vite原理
官方文档-为什么选Vite
使用 Vite 构建前端项目时,Vite 会在一开始将项目中的代码分为依赖和源码两大类。
依赖即开发项目时使用的第三方库,一个稍大的项目会有成百上千个依赖,处理这些依赖库的性能代价是比较高的,而且不同依赖库使用的模块化规则不同(如 UMD、ESM 或 CommonJS),所以还需要将其转成相关的模块化规则。
对于依赖的处理,我们通常称为依赖预构建,Vite 使用 esbuild 来实现依赖预构建,将 CommonJS 和 UMD 的依赖库转为 ESM 形式,此外因为依赖库大多数时候不会变化,Vite 会将构建好的依赖存到 node_modules/.vite 目录中,如果依赖变化(package.json 等文件中依赖变化了)则会重新构建。
Vite 使用 esbuild 这个全新 js 打包工具的原因是该工具使用 Go 开发,相比于 gulp、rollup 等使用 JS 开发的传统打包工具,esbuild 会快上十几倍,因为打包其实是 CPU 密集型操作,编译型语言会比动态语言快很多(目前前端的一个趋势便是使用编译型语言开发的工具去替代已有的一些工具)。
esbuild 目前还比较新,虽然重要的功能都有了,但还是有部分功能缺失,如对 CSS 处理还不太好,所以 Vite 目前只是要 esbuild 实现开发期间的构建操作,项目开发完要正式构建时使用的是 rollup,rollup 非常成熟,虽然慢一点,但正式构建在开发过程中不会太频繁。
对于源码,通常就是我们开发项目时自己写的 JS 代码,这些代码时常被修改,但并不是每次修改都需要重新加载所有源码的,Vite 利用浏览器 ES Modules(ESM),当浏览器发起相应模块的请求时,Vite 内置的基于 Koa 构建的 web 服务器会拦截 ES Module 请求,并通过 path 找到想要目录的文件,通过简单的处理再返回给浏览器。
Vite 跳过了打包的动作,Webpack 每次需要将代码打包成一个完整的 JS,当项目变大时,打包就会变慢,这是根本原因,而 Vite 在开发阶段构建项目时会将其构建成 ESM 的形式,这让浏览器来决定什么使用要加载什么模块,然后 Vite 拦截并处理浏览器对模型加载的请求,从而实现真正的按需加载,不再需要打包。
Vite 是基于浏览器 ESM 形式的构建工具,利用浏览器实现了按需加载,相比打包类型的构建工具快上很多,而且随着项目的增大,热更新等也不会变慢,大大提高了开发效率。
虽然浏览器对 ESM 的支持已经很广泛了,但 Vite 还是选择在生产环境时使用 rollup 来打包,因为在生产环境下,使用未打包的 ESM 会产生比较多的 HTTP 请求,相对打包而言,效率还是比较低下的,所以 Vite 上生产依旧打包,并使用了 tree-shaking、懒加载等技巧让上生产环境的代码更加优雅。
简单而言,Vite 对开发环境与生产环境提供了不同的解决方案,其最终目的是提高开发效率。
面试精简回答:
vite会将项目的代码分为依赖和源码;Vite会使用esbuild(使用go编写,比js大包起快10-100倍)预构建依赖,将commonJS和UMD的依赖库转为ESM形式,如果依赖变化,会重新构建。在开发阶段,vite会把源码构建成ESM的模式,在浏览器请求源码时按需加载,不需要打包,所以会比webpack打包编译会快很多;但在生产环境时vite还是使用了rollup来打包,因为未打包的EMS会产生很多HTTP请求,效率比较低下。总之vite极大提高了开发效率,冷启动和热更新都很快。
11、flutter和rn的区别
Flutter 是 一个跨平台开发框架,可以同时运行在 iOS 和 Android平台, Flutter 提供了丰富的组件、接口。
它是属于自绘UI + 原生。这种技术的思路是:通过在不同平台实现一个统一接口的渲染引擎来绘制UI,而不依赖系统原生控件,所以可以做到不同平台UI的一致性。注意,自绘引擎解决的是 UI 的跨平台问题,如果涉及其他系统能力调用,依然要涉及原生开发。
这种平台技术的优点是:性能高,开发效率高;灵活、组件库易维护、UI外观保真度和一致性高。
不足是:动态性不强,为了保证UI绘制性能,自绘UI系统一般都会采用 AOT(提前编译) 模式编译其发布包,所以应用发布后,不能像 Hybrid 和 RN 那些使用 JavaScript(JIT)作为开发语言的框架那样动态下发代码;dart作为一门强类型语言,对前端开发者来说学习成本会比较高。
React native也是一个跨平台的开发框架,它基于React.js,属于 JavaScript开发 + 原生渲染
React native 生成虚拟 DOM后需要通过 JavaScriptCore 映射为原生控件,
优点:动态化较好,支持热更新;原生渲染,性能相比 H5 提高很多;采用 Web 开发技术、学习成本相对较低
不足:渲染时需要 JavaScript 和原生之间通信,在有些场景如拖动可能会因为通信频繁导致卡顿;渲染依赖原生控件,不够灵活
Flutter 高性能主要靠两点来保证:
第一:Flutter APP 采用 Dart 语言开发。Dart 在 JIT(即时编译)模式下,执行速度与 JavaScript 基本持平。但是 Dart 支持 AOT,当以 AOT模式运行时,JavaScript 便远远追不上了。执行速度的提升对高帧率下的视图数据计算很有帮助。
第二:Flutter 使用自己的渲染引擎来绘制 UI ,布局数据等由 Dart 语言直接控制,所以在布局过程中不需要像 RN 那样要在 JavaScript 和 Native 之间通信,这在一些滑动和拖动的场景下具有明显优势,因为在滑动和拖动过程往往都会引起布局发生变化,所以 JavaScript 需要和 Native 之间不停的同步布局信息,这和在浏览器中JavaScript 频繁操作 DOM 所带来的问题是类似的,都会导致比较可观的性能开销。
webpack参考1
webpack参考2