前端工程化

前端工程化

1、如何理解webpack
webpack 是一个静态模块打包工具,会从入口点构建一个 依赖图,把项目中所需的每一个模块组合成一个或多个 bundles。可以用来管理模块依赖,并编译输出模块们所需要的静态文件。可以通过loader、plugin增强webpack的能力。
2、webpack打包过程

  • 初始化阶段:从配置文件和 Shell 语句中读取与合并参数,加载所有配置的Plugin。
  • 编译构建阶段:根据配置中的 entry 找出所有的入口文件,从 Entry 发出,调用所有配置的Loader对模块进行翻译,再找出该模块依赖的模块,递归地进行编译处理。
  • 输出阶段:Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系图。根据依赖关系图,组装成一个个包含多个模块的Chunk,再把每个Chunk转化成一个单独的文件加入到输出列表,根据配置确定输出的路径和文件名,并输出。
    3、loader和plugin
    loader:
    webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。
    常用的loader:
  • vue-loader:允许以一种名为单文件组件 (SFCs)的格式撰写 Vue 组件; 为每个组件模拟出 scoped CSS; 允许为 Vue 组件的每个部分使用其它的 webpack loader,例如在

plugin:
用于增强webpack的能力,比如打包优化和代码压缩等

  • html-webpack-plugin:处理html资源,默认会创建一个空的HTML,自动引入打包输出的所有资源。
  • webpack-bundle-analyzer: 可视化 Webpack 输出文件的体积 (业务组件、依赖第三方模块)

区别:

  • loader运行在编译阶段,plugins 在整个周期都起作用
  • Loader本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果;Plugin就是插件,可以扩展 Webpack 的功能,Plugin 在合适的时机通过 Webpack 提供的 API 改变输出结果。

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异同**

  • Rollup基于es6module,Webpack基于commonjs
  • Rollup将项目中的细小模块打包成整块代码,原生支持tree-shaking,打包的体积小,一次性加载;webpack 拆分代码, 按需加载;
  • Rollup仅仅是一款ESM打包器,不支持代码分割、热更新等功能, webpack结合插件可以完成前端工程化的绝大多数工作
  • Rollup适合类库/框架,小而美;Webpack适合应用,大而全;

8、Vite为什么会比webpack快

  • 启动快:vite启动时不需要打包编译等,浏览器请求对应模块时才按需编译;webpack启动需要打包、分析模块依赖、编译
  • 热更新快:webpack使用热更新时,改动一个模块,其他有依赖的模块也会重新打包;vite使用热更新时改动一个模块,仅需让浏览器重新请求该模块即可,效率更高。
  • Vite 将会使用 esbuild 预构建依赖。Esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。

9、vue-cli和vite

  • Vue CLI 基于 Webpack 构建,配置好了打包规则
  • Vue cli 在服务启动之前,要把所有代码打包成 Bundle 再启动服务
  • vite比vue-cli快10-100倍
  • vite只支持vue3,浏览器兼容性较差
  • Vite在开发环境下基于浏览器原生ES6 Modules,生产环境基于Rollup

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

你可能感兴趣的:(面试,前端,webpack,javascript)