三天吃透Web前端工程化面试实战指南(2025最新整理),面试通过率高达90%

39 阅读46分钟

图片

1.[Webpack]配置代码太多,达到数千行,这个时候该如何优化配置代码【热度: 186】

当Webpack配置代码变得冗⻓和难以管理时,可以采取以下⽅法来优化配置:

• 配置⽂件拆分

将配置⽂件分成多个部分,每个⽂件只负责⼀部分逻辑。⽐如基础配置、开发环境配置、⽣产环境配置等。

图片

• 使⽤环境变量

通过环境变量来区分不同的配置环境,使⽤ webpack-merge 或 env-cmd 这样的库来合并配置。

图片

• 模块化配置

将常⽤的loader、plugins、entry等配置项封装成函数或者模块,然后在主配置⽂件中引⼊。

图片

图片

• 使⽤webpack-merge抽离通⽤配置

检查配置中的重复部分,将它们抽象成共⽤的配置,再使⽤ webpack-merge 来合并多个配置⽂件,保持配置的清晰和可维护性。

图片

• 统⼀管理插件和加载器

如果项⽬中使⽤了⼤量插件和加载器,请考虑将它们的实例化和配置逻辑封装在单独的函数或⽂件中。然后根据不同的环境,直接pick不同的配置即可。可以达到配置的loader和plugin集中管理。

  1. [Webpack]你用过哪些可以提高效率的插件?【热度: 179]

• webpack-dashboard:可以更友好的展⽰相关打包信息。

• webpack-merge:提取公共配置,减少重复配置代码

• speed-measure-webpack-plugin:简称SMP,分析出Webpack打包过程中Loader和Plugin的耗时,有助于找到构建过程中的性能瓶颈。

• size-plugin:监控资源体积变化,尽早发现问题

• HotModuleReplacementPlugin:模块热替换

• webpack.ProgressPlugin:打包进度分析

• webpack-bundle-analyzer:打包结果分析

• friendly-errors-webpack-plugin:代码源码编译报错友好提⽰

3.在做eslint和commitlint的时候,可以使用--no-verify 跳过,这种情况下该如何强制卡点【热度:233】

跳过 eslint 和 commitlint 的钩⼦,使⽤ --no-verify (对于 git commit 来说是 -n ),的确是⼀个容许开发者在紧急情况下超越钩⼦检查的⼿段。然⽽,这也削弱了代码质量保证的制度。以下是⼀些⽅法,可以⽤来加强这些卡点的靠谱办法:

• CI/CD流⽔线中增加检查:在你的CI/CD流程中增加 eslint 和 commitlint 的检查步骤。如果检查失败,则阻⽌代码合并或部署。

• 强制挂钩:虽然开发者可能在本地禁⽤钩⼦,但你不能控制别⼈的本地环境。相反,你可以编写服务器端的钩⼦,⽐如在Git仓库的服务器上使⽤ pre-receive 钩⼦,来拒绝不符合规范的提交。

• 定期⾃动化检查:定期运⾏⼀个⾃动化的脚本或GitHubAction,检查代码库的eslint与commitlint违规情况,并⾃动创建⼀个修复问题的issue或拉取请求。

你可以最⼤限度地减少绕过 eslint 和 commitlint 检查的情况。然⽽,值得记住的是,在极少数情况下,可能存在合法的理由需要紧急提交代码。因此,为了灵活性和效率,完全禁⽌ --noverify 可能不是⼀个最佳的选择。好的实践中应该找到安全和灵活性之间的平衡,核⼼在于建⽴⼀个质量意识,制定明智的操作规范。

4.如何做commit lint【热度: 425】

5.编写npm包的时候,可以办法自动生成changlog与自动更新tag【热度:455】

  1. [Webpack] ts编写的库,在使用webpack构建的时候,如何对外提供d.ts【热度:224】

7.测试前端代码覆盖率一般有什么手段?【热度: 550】

前端代码的测试覆盖率通常是指衡量在测试过程中有多少代码被执⾏了的⼀个指标。测试覆盖率有助于了解测试的全⾯性,以下是测试前端代码覆盖率常⽤的⼿段:

  1. 单元测试:

◦ 使⽤测试框架(例如Jest,Mocha,Jasmine等)编写单元测试。

◦ 利⽤测试框架或插件⽣成覆盖率报告(例如Istanbul/nyc⼯具可以与这些框架集成以⽣成覆盖率数据)。

  1. 集成测试:

◦ 使⽤测试⼯具(⽐如Cypress,Selenium等)编写集成测试来模拟⽤⼾操作。

◦ 通常这些⼯具也⽀持收集代码覆盖率信息。

  1. ⼿动测试与覆盖率⼯具结合:

◦ 在⼿动测试过程中,可以开启浏览器的覆盖率⼯具(如ChromeDevTools中的CoverageTab)记录覆盖率。

◦ 可以通过浏览器扩展程序或者⾃动化脚本来启动这些⼯具。

  1. 测试覆盖率服务:

◦ 使⽤像Codecov或Coveralls这样的服务,在CI/CD流程中集成覆盖率测试和报告。

  1. [Webpack]如何提取复用代码给多个entry使用?【热度:292]

在Webpack中提取源码⾥被多个⼊⼝点复⽤的代码,例如⼀个 utils ⽂件,可以通过配置optimization.splitChunks 来实现。Webpack会将这些频繁复⽤的模块提取出来,打包到⼀个独⽴的chunk中,使得浏览器可以单独缓存这部分代码,并在多个⻚⾯间共享使⽤,优化加载性能。

使⽤ splitChunks 的基本配置如下:

图片

这个配置的含义是:

• chunks: 'all' 指定要优化的chunk类型,这⾥设置为 all 代表所有的chunk,不管是动态还是⾮动态加载的模块。

• cacheGroups 是⼀个对象,⽤于定义缓存组,可以继承和/或覆盖 splitChunks 的任何选项。每个缓存组可以有⾃⼰的配置,将不同的模块提取到不同的⽂件中。

• cacheGroups.commons 定义了⼀个缓存组,专⻔⽤于提取 initial chunk(最初依赖的模块)中被⾄少两个chunk所共享的模块。

• name: 'commons' 为⽣成的⽂件定义了⼀个⾃定义名称。

• minChunks: 2 表⽰模块⾄少被两个⼊⼝点引⽤时,才会被提取。

• minSize: 0 指定模块的最⼩体积是0,即任意⼤⼩的模块都被提取。

这会让任何从 node_modules ⽬录导⼊,并在⾄少两个⼊⼝点中使⽤的模块,都会被打包到⼀个名为 commons.js 的⽂件中(当然,实际的⽂件名会受到 output 配置的影响,例如是否包含哈希值等)。

正确配置这些参数后, utils 这样的模块就会被⾃动提取并共享,⽽不是在每个⼊⼝点的bundle中重复包含。这样做的好处是,任何更新业务逻辑的时候,只要 utils 没有发⽣变化,⽤⼾浏览器上已缓存的 commons.js ⽂件就不需要重新下载。

  1. [Webpack]如何将一些通用的依赖打包成一个独立的bundle【热度: 643】

在Webpack中,将⼀些通⽤的依赖,如React、ReactDOM、ReactRouter等库和框架,打包成⼀个独⽴的bundle,通常是为了⻓期缓存和减少每次部署更新的下载量。这可以通过"代码分割"(codesplitting)和"优化"(optimization)配置来实现。

以下是Webpack中分离通⽤依赖的⼏个步骤:

  1. 使⽤ entry 来定义不同的⼊⼝点:可以通过配置⼀个额外的⼊⼝来创建⼀个只包含通⽤库的bundle,也就是所谓的"vendor"bundle。

图片

  1. 使⽤ SplitChunksPlugin :这个插件可以将共享代码分割成不同的chunks,并可以通过配置将其从业务代码中分离出来。在Webpack4及之后的版本中,默认内置了 optimization.splitChunks ,就是这个插件的配置⽅法。

图片

图片

  1. 配置 output :虽然不是必须的,你还可以在output中定义 filename 和 chunkFilename ,来控制主⼊⼝和⾮主⼊⼝chunks的⽂件名。

图片

通过这样的配置,Webpack在打包时会⾃动将node_modules中的依赖和业务代码分离开来,业务代码会被打包到 main chunk中,⽽第三⽅库则会打包到 vendors chunk。

10.[Webpack] output配置里面, chunkFilename和filename区别是什么?【热度:210】

11.[Webpack]多入口打包共享模块【热度: 337】

12.[Webpack]如何使用ts来编写配置文件?【热度:251】

13.[Webpack]内部执行原理【热度:668】

14.[Webpack]为何不支持CMD模块化【热度: 255】

15.[Webpack]支持哪些模块化加载?【热度:154】

16.前端视角-如何保证系统稳定性【热度: 566】

前端视⻆来做稳定性,本是⼀个开放性话题,这⾥没有统⼀的解法,作者在此提供⼏个思路和反向:

  1. 静态资源多备份(需要有备份)

  2. ⾸屏请求缓存

  3. 请求异常报警

  4. ⻚⾯崩溃报警

  5. E2E定时全量跑⽤例

17.webpack的主要配置项有哪些【热度:766】

Webpack是⼀个现代JavaScript应⽤程序的静态模块打包器。配置⽂件名通常为webpack.config.js ,它提供了⼀种配置Webpack的⽅式。下⾯是⼀些主要的Webpack配置选项:

  1. entry:⼊⼝起点(entrypoint)指⽰webpack应该使⽤哪个模块,来作为构建其内部依赖图的开始。可以指定⼀个或多个⼊⼝起点。

  2. output:output属性告诉webpack在哪⾥输出它所创建的bundles,以及如何命名这些⽂件,默认值为 ./dist 。

  3. module:module属性⽤于决定如何处理项⽬中的不同类型的模块。

◦ rules:配置模块的读取和解析规则,通常⽤来配置loader。

  1. resolve:配置模块如何解析。

◦ extensions:⾃动解析确定的扩展,此选项能够使⽤⼾在引⼊模块时不带扩展。

  1. plugins:插件是⽤来扩展webpack功能的。它们会在构建流程中的特定时机注⼊运⾏逻辑来改变构建结果或做你想要的事情。

  2. devServer:通过来⾃ webpack-dev-server 的这些选项能够对开发服务器的⾏为进⾏控制。

  3. devtool:此选项控制是否⽣成,以及如何⽣成sourcemap。

  4. mode:通过设置 development 或 production 之中的⼀个,来为流程提供相应模式下的内置优化。

  5. optimization:包含⼀组可⽤来调整构建输出的选项。

◦ splitChunks:配置模块的拆分,可以将公共的依赖模块提取到已有的⼊⼝chunk中,或者提取到⼀个新⽣成的chunk。

◦ runtimeChunk:为每个entry创建⼀个运⾏时⽂件。

  1. performance:允许webpack根据某些参数,控制资产和⼊⼝起点的最⼤⼤⼩。

  2. externals:防⽌将某些import包(package)打包到bundle中,⽽是在运⾏时(runtime)再去从外部获取这些扩展依赖。

每个项⽬的具体需求不同,Webpack的配置也会有所不同。这些选项提供了强⼤的配置能⼒和灵活性,可以⽤来定制Webpack的打包、加载和转换⾏为。

18.[webpack] optimize配置中,分割代码配置splitChunks怎么使用【热度:546】

  1. [webpack] optimize配置有哪些作用【热度: 280】

  2. [webpack] mode是做什么用?【热度:475】

21.v8里面的I是什么?【热度: 694】

22.单元测试中,TDD、BDD、DDD分别指?【热度: 166]

23.husky 作用是啥,有哪些重要配置【热度: 192]

Husky是⼀个基于Node的Git钩⼦管理⼯具,⽤于在你的⼯作流程中强制执⾏Git钩⼦。Husky允许你定义脚本,这些脚本会在不同的Git⽣命周期事件触发时⾃运⾏,⽐如在提交、推送或合并前。

使⽤Husky可以:

  1. 保证提交质量:Husky可以在你提交代码之前运⾏代码校验,确保代码符合项⽬规范,提⾼代码质量。

  2. 维护代码⻛格:可以在提交时检查代码⻛格,确保代码⻛格⼀致性。

  3. ⾃动化流程:⽀持在推送前执⾏代码部署、测试脚本,让整个开发流程⾃动化。

  4. 预防错误:例如在允许推送到远程仓库之前检查代码中是否有遗留的更改。

Husky的⼀些重要配置如下:

  1. npm install husky@latest --save-dev :安装husky。

  2. npx husky install :在新建的项⽬管理下⽣成husky的配置⽂件。

  3. npx husky add .husky/*.sh :添加Git钩⼦脚本,这⾥的 *.sh 是你想触发的钩⼦点,例如:pre-commit 、 commit-msg 等。

Husky⽀持的钩⼦包括:

• apply-patch-msg :应⽤⼀个补丁到暂存区并⽣成提交信息时。

• pre-applypatch :打补丁前。

• post-applypatch :打补丁后。

• pre-commit :提交前,常⽤于检查代码、分析代码⻛格等。

• prepare-commit-msg :提交准备⼯作完成后,修改提交信息之前运⾏。

• commit-msg :检查提交信息有效性。

• post-commit :提交后。

• pre-rebase :回滚操作开始前。

• post-checkout :检出操作后(如切换分⽀)。

• post-merge :合并和变基操作后。

记得在 .husky ⽂件夹⾥配置这些钩⼦脚本,你可以根据项⽬需求来写⾃⼰的hook脚本。⽐如,设置⼀个 .husky/pre-commit 脚本(可能是⼀个shell脚本和Node.js脚本的组合),当你尝试提交代码时,Husky将会运⾏这个脚本作为 pre-commit 钩⼦。

在⼀些场景下的 .husky/pre-commit 脚本,你可以指定运⾏如下:

图片

以上脚本将确保代码在提交前通过了linter检查,并通过prettier快速格式化以及TypeScript编译。

使⽤的时候,请确认你的项⽬已经有了Node.js环境,并且已经安装了Husky和相应的代码检查、格式化⼯具。

24.Husky和lint-staged有什么区别?【热度:387】

Husky和lint-staged都是与Git钩⼦(hooks)配合使⽤的Node.js库,但它们的⽤途和⼯作⽅式有所不同:

  1. Husky:

◦ Husky是⼀个Git钩⼦管理器,它允许你触发⾃定义脚本在git事件发⽣时运⾏,如 precommit , pre-push , post-merge 等。

◦ 它的主要⽬的是⾃动化你的版本控制⼯作流程,例如在提交(commit)前运⾏代码检查、格式化代码或执⾏测试,以确保代码库的质量和⼀致性。

  1. lint-staged:

◦ lint-staged是⼀个运⾏在Husky钩⼦之上的⼯具,它专⻔⽤于对暂存区(staged)⽂件的检查。

◦ 当你运⾏ git commit 并且Husky触发 pre-commit 钩⼦时,lint-staged会检查你即将提交的代码(即 git add 后的⽂件列表),并运⾏你配置好的检查脚本,如代码格式化程序、linter或其他⼯具。

◦ 它的⽬的是确保在提交之前,只有没有检查错误的代码会被提交。

简⽽⾔之,Husky是⼀个可以触发多种钩⼦事件的⼯具,⽽lint-staged是⼀种专⻔⽤于检查Git暂存区⽂件的⼯具。它们通常是配合使⽤的,因为lint-staged需要通过Husky来触发钩⼦。在你初始化项⽬并配置CI/CD流程时,通常会同时⽤到它们。

  1. [webpack]打包时hash码是如何生成的【热度:167】

26.如何从o到1搭建前端基建【热度:404】

27.[React]为什么react组件,都必须要申明一个import React from 'react';【热度:115】

28.babel核心库有哪些?【热度: 35】

29.在Babel里, stage0、stage1、stage2和stage3分别代表什么含义?

⽆意中看到别⼈⼀个⾯试问题,个⼈感觉问这个问题的⾯试官,不是蠢就是坏。
没有任何⾯试价值,⽆法考察候选⼈⽔平。
仅仅作为科普类型参考-热度为0

Babel是⼀个流⾏的JavaScript编译器,它允许开发者使⽤新的语⾔特性,然后将它们编译成可以在当前和低版本的浏览器或环境中运⾏的代码。

在Babel⾥,stage0、stage1、stage2和stage3这些术语指的是ECMAScript提案的不同阶段。ECMAScript是JavaScript语⾔的标准化规范,新的特性进⼊标准之前会通过⼏个阶段的提案。

这些阶段表⽰了⼀个特性在正式成为ECMAScript标准的⼀部分之前的成熟度。这个过程有⼀个官⽅的5个阶段流程,即从Stage0(strawman)到Stage4(finished)。下⾯是这些阶段的含义:

• Stage0-Strawman(稻草⼈阶段):初始阶段,任何尚未被TC39(ECMAScript的标准化组织)官⽅审议的提案都属于这⾥。这些都是某个委员或者社区成员提交的想法,还不算是正式的提案。

• Stage1-Proposal(提案阶段):这个阶段的特性是值得进⼀步探讨的。它们需要有⼀个形式化的提案和⼀个负责⼈。在这个阶段,主要是确定问题和解决⽅案,以及进⾏初步探讨。

• Stage2-Draft(草案阶段):⼀旦⼀个提案到达这个阶段,它就被认为是初步规格的草案。特性的描述应该⾜够具体和详细,并且有初步的实现。这个阶段通常需要提案的规格⽂本和⾄少⼀种实验性实现。

• Stage3-Candidate(候选阶段):在候选阶段,提案的规格已经基本完成,并且需要更多的⽤⼾反馈来发现潜在问题。通常在这个阶段,实现者和开发者开始在⽣产环境中尝试使⽤这些特性,发现问题并提出改善建议。

• Stage4-Finished(完成阶段):当⼀个提案达到这个阶段,它已经准备好被集成到下⼀个版本的ECMAScript标准中了。这意味着它已经获得了多个独⽴环境的实现,通过了综合的可⾏性和稳定性测试,并且已经被TC39委员会接受。

开发者们可以根据特性的稳定性和⾃⼰的需求,选择使⽤Babel的哪个阶段的预设。然⽽,请注意,使⽤较低阶段的提案特性在⽣产环境中是有⻛险的,因为它们还没有被完全确定并可能会在将来发⽣变更。

30.Webpack项目中通过script标签引入资源,在项目中如何处理?【热度: 100】

也是作者⽆意中看到的⼀个有意思的问题。
虽然有意思,但是没有任何价值,如果说在项⽬中遇到过的,⽽且处理过的同学,肯定知道怎么回答。
但是压根没有碰到过得,就算是你⼯作⼗年的⽼油条也是⼲望着。所有没有任何⾯试价值。
故此,可以当做科普来看看就⾏。

在使⽤Webpack打包的项⽬中,通常资源(如JavaScript、CSS、图⽚等)会被Webpack处理,因为Webpack的设计初衷就是将所有资源视为模块,并进⾏有效的管理和打包。但有时候可能需要通过

  1. 在HTML⽂件中直接引⼊:

可以在项⽬的HTML⽂件中直接使⽤

图片

  1. 这种⽅法简单直接,但要记住,由于这些资源不会被Webpack处理,它们不会被包含在Webpack的依赖图中,并且也不会享受到Webpack的各种优化。

  2. 使⽤Webpack管理:

如果想要Webpack来处理这些通过

◦ html-webpack-plugin 可以帮助你⽣成⼀个HTML⽂件,并在⽂件中⾃动引⼊Webpack打包后的bundles。

◦ externals 配置允许你将⼀些依赖排除在Webpack打包之外,但还是可以通过 require或 import 引⽤它们。

◦ script-loader 可以将第三⽅全局变量注⼊的库当作模块来加载使⽤。

  1. 例如,使⽤ html-webpack-plugin 和 externals ,你可以将⼀个库配置为external,然后通过 html-webpack-plugin 将其引⼊:

图片

  1. 然后,在你的 index.html 模板⽂件中可以这样引⼊资源:

图片

  1. 使⽤ externals 的⽅法能让你在Webpack打包的模块代码中⽤正常的 import 或 require语句来引⽤那个全局变量:

图片

应根据项⽬需求和现有的架构来决定使⽤哪种⽅法。上述两种⽅法中,第⼆种可以更好地利⽤ Webpack的功能,第⼀种则更加简单直接。

31.为什么Vite速度比 Webpack快?【热度: 382】

32.web系统里面,如何对图片进行优化?【热度: 789】

33.[webpack] webpack-dev-server为何不适用于线上环境?【热度: 88】

  1. [webpack] webpack-dev-server 作用是啥?【热度: 387】

35.vite和webpack在热更新上有啥区别?【热度: 530]

36.esbuild和rollup都是vite的基础依赖,那么他们有啥不同?【热度: 129】

37.vite编译器有啥特点?【热度:237】

38.vite编译器的组成部分【热度: 335】

39.vite涉及到了哪些底层原理?【热度: 510】

Vite涉及到以下⼏个底层原理:

  1. ES模块:Vite使⽤了ES模块来管理和加载模块。ES模块是JavaScript的标准模块系统,相⽐于传统的CommonJS或AMD,ES模块具有更好的静态分析能⼒和更⾼的性能。Vite通过使⽤浏览器原⽣的ES模块加载器,可以实现按需加载和快速构建。

  2. HTTP/2:Vite借助于现代浏览器的HTTP/2⽀持来实现更⾼效的资源加载。HTTP/2⽀持多路复⽤,可以同时请求多个资源,避免了传统的HTTP/1中的队头阻塞问题,加快了资源加载速度。

  3. 编译器:Vite使⽤了⾃定义的编译器来处理开发时的模块解析和转换。它能够识别模块的依赖关系,并将模块转换为浏览器可直接执⾏的代码。Vite的编译器⽀持热模块替换(HMR),可以在代码修改时⾃动更新浏览器中的⻚⾯,提⾼开发效率。

  4. 中间件:Vite使⽤了基于Koa框架的中间件来处理开发服务器。通过中间件,Vite可以拦截和处理开发时的HTTP请求,并根据请求的路径返回相应的模块⽂件。中间件还可以处理各种开发时的特殊需求,如代理API请求、路由转发等。

Vite基于ES模块、HTTP/2、⾃定义编译器和中间件等底层原理,实现了快速的模块加载和开发体验。这些原理的运⽤使得Vite在开发环境下能够提供更快的构建速度和更好的开发体验。

40.页面加载速度提升(性能优化)应该从哪些反向来思考?【热度: 1,099】

⻚⾯加载优化

「⻚⾯加载链路+流程优化+协作⽅」的多级分类思考

• ⻚⾯启动

◦ serviceworker缓存重要的静态资源

◦ ⻚⾯保活

• 资源加载

◦ ⽹络连接

▪ NDS

• 减少NDS解析

• NDA预解析

▪ HTTP

• 开启HTTP2多路复⽤

• 优化核⼼请求链路

◦ HTML加载

▪ 内容优化

• 代码压缩

• 代码精简(tailwindcss)

• 服务端渲染SSG

▪ 流程优化

• 服务端渲染SSR

• 流式渲染

• 预渲染

◦ 静态资源加载

▪ 内容优化

• JS、CSS代码压缩

• 均衡资源包体积:复⽤代码抽离为⼀份资源打包、同时开启

• 精简代码

• 雪碧图

• 动态图⽚降质量

• 动态polyfill(根据浏览器的⽀持情况,动态加载需要的polyfill(填充)脚本)

• 不常变的资源单独打包

• 根据浏览器版本打包,⾼版本浏览器,直接使⽤es6作为输出⽂件

▪ 流程优化

• 配置前端缓存:资源、请求

• 使⽤CDN

• CDN优化

• 协调资源加载优先级

• 动态资源转静态CDN链接加载(例如⼤图⽚等)

• 静态资源使⽤serviceworker离线存储

• ⾮⾸屏资源懒加载

• 资源和业务请求预加载

• 微前端加载应⽤

• 微组件加载核⼼模块资源

• 代码执⾏

◦ 减少执⾏

▪ 减少重复渲染

▪ ⼤体量计算场景,尽量使⽤缓存函数

▪ 使⽤防抖节流

◦ 速度提升

▪ 使⽤worker多线程加速

▪ 充分利⽤异步请求的线下之间来进⾏核⼼代码的加载或者执⾏

▪ wasm处理⼤量计算场景

▪ 渲染⾼耗时场景,迁移到canvas、虚拟dom等

▪ 动态渲染:动态渲染可视区内容,例如图⽚懒加载等;

◦ 流程优化

▪ ⾮⾸屏模块,延迟加载与渲染

▪ longtask任务拆分执⾏

▪ 利⽤请求闲暇时间,请求后续⻚⾯资源

• 数据获取

◦ 内容优化

▪ 减少请求、合并请求、BFF

▪ ⾸屏数据使⽤模板注⼊到前端应⽤

◦ 流程优化

▪ 数据预请求

▪ 常量数据缓存

▪ ⾮⾸屏请求,延迟到⾸屏加载完成之后请求

▪ 请求并⾏

• 渲染相关

◦ 虚拟列表

◦ 延迟渲染

◦ 减少重绘重排

◦ 图⽚预加载到内存

41.对比一下pnpm、npm、yarn特性【热度: 399】

42.[低代码]代码平台一般渲染是如何设计的?【热度: 399】

43.[低代码]代码平台一般架构设计如何【热度:517】

  1. [Webpack] Webpack vs Vite的核心差异【热度: 620】

45.对babel的理解?【热度:551】

46.[Webpack]有哪些优化项目的手段?【热度: 1,163】

47.[Webpack]全面了解tree shaking

48.[Vue]响应式为何要从 Object.defineProperty改为proxy?【热度:352】

Vue在早期版本中使⽤了 Object.defineProperty 来实现响应式系统。但是,在 Object.defineProperty 中存在⼀些限制和局限性,导致在某些场景下⽆法完全满⾜需求。因此,Vue在最新的版本中引⼊了 Proxy 来替代 Object.defineProperty 。

以下是⼀些 Proxy 相对于 Object.defineProperty 的优势:

  1. 功能更强⼤:Proxy 可以代理整个对象,⽽ Object.defineProperty 只能对已存在的属性进⾏拦截。使⽤ Proxy 可以在对象级别上进⾏拦截、代理、验证等操作。

  2. 更易于使⽤和理解:Proxy 提供了⼀组更直观和易于理解的API,使开发者可以更容易地创建和管理代理。

  3. 性能优化:Proxy 针对属性的访问和修改都提供了更佳的性能优化。⽽Object.defineProperty 在拦截属性访问和修改时会有⼀定的性能损耗。

  4. 更好的嵌套⽀持:Proxy 可以代理嵌套对象的属性,⽽ Object.defineProperty 只能对顶层对象的属性进⾏拦截。

总的来说, Proxy 相对于 Object.defineProperty 在功能上更强⼤、使⽤更便捷、性能更优,并且在更复杂的场景下也能提供更好的⽀持。因此,Vue在新版本中选择了使⽤Proxy 来实现响应式系统

49.在你的项目中,使用过哪些webpack loader,说一下他们的作用

50.在webpack 中,通常用于css提取的工具是什么?【热度: 69】

在webpack中,通常使⽤ mini-css-extract-plugin 来提取CSS。它是⼀个独⽴的插件,可以将CSS从JavaScript⽂件中提取出来,⽣成独⽴的CSS⽂件。

使⽤ mini-css-extract-plugin 可以优化代码分离和缓存,以及提⾼加载速度。

通过配置webpack的插件选项,可以将 mini-css-extract-plugin 添加到webpack构建流程中。在配置中,需要将该插件实例化,并指定输出的CSS⽂件名和路径。

⼀旦配置完成并运⾏webpack构建, mini-css-extract-plugin 就会将CSS提取到独⽴的⽂件中,⽽不是将其嵌⼊到JavaScript⽂件中。

⽰例代码如下:

图片

在上述⽰例中, MiniCssExtractPlugin.loader 是⽤于提取CSS的loader。css-loader ⽤于处理CSS⽂件的导⼊和解析。

MiniCssExtractPlugin 则是插件实例,⽤于配置输出的CSS⽂件名。

51.将静态资源缓存在本地的方式有哪些?【热度: 584)]

52.SPA首屏加载速度慢的怎么解决【热度:868】

  1. git 中回滚代码有哪些操作?【热度: 237】

  2. git reset 作用是啥,有哪些操作?【热度:275】

55.为什么现代前端应用需要打包工具进行打包编译?【热度:1,588】

现代前端应⽤需要打包⼯具进⾏打包编译的主要原因有以下⼏点:

  1. 模块化管理:现代前端应⽤通常采⽤模块化的开发⽅式,将代码划分为多个模块,每个模块具有独⽴的功能和依赖关系。打包⼯具可以将这些模块进⾏分析,将它们打包成⼀个或多个静态⽂件,⽅便管理和维护。

  2. 解决浏览器兼容性问题:不同的浏览器对于JavaScript和CSS的⽀持程度不同,⽽且随着新特性的不断出现,旧版浏览器可能⽆法完全⽀持。打包⼯具可以通过转译、压缩和兼容性处理等⼿段,将当前前端代码转化为浏览器可识别和运⾏的代码,解决兼容性问题。

  3. 静态资源处理和优化:现代前端应⽤涉及⼤量的静态资源,如图⽚、字体等。打包⼯具可以对这些资源进⾏处理和优化,如图⽚压缩、字体⽂件打包等,以减⼩资源⽂件的体积,提⾼⻚⾯的加载速度和性能。

  4. 代码分割和按需加载:打包⼯具可以将应⽤程序拆分成多个⼩块,实现代码分割和按需加载。这样可以实现懒加载,只在需要时加载特定的代码块,提⾼⻚⾯的加载速度。

  5. 开发环境⽀持:打包⼯具通常提供开发服务器和热模块替换(HMR)等功能,⽅便开发⼈员进⾏开发和调试。开发服务器可以实时预览代码变化,HMR可以在修改代码后只替换修改的部分,⽽不是整个⻚⾯刷新,提⾼开发效率。

  6. 提升性能:打包⼯具可以通过代码优化、压缩和混淆等技术⼿段,减⼩⽂件体积,提升应⽤程序的加载速度和执⾏效率。

  7. ⽀持多种前端技术:现代前端应⽤通常使⽤多种前端技术和语⾔,如JavaScript、CSS、TypeScript、Sass等。打包⼯具可以集成这些技术,并提供相应的编译、转译和处理功能,使开发⼈员能够更轻松地使⽤这些技术。

  8. ⾃动化⼯作流程:打包⼯具可以配合其他构建⼯具和⾃动化任务运⾏器,如Webpack配合Grunt或Gulp,实现⾃动化的构建和部署流程。这可以减少⼿动操作,提⾼开发效率和代码质量。

  9. 第三⽅库管理:现代前端应⽤通常使⽤⼤量的第三⽅库和框架,这些库可能包含多个⽂件和依赖关系。打包⼯具可以⾃动管理这些库的依赖关系,并将它们打包为单个⽂件,减少⽹络请求和提⾼代码的可维护性。

  10. ⾼度可定制化:打包⼯具通常提供丰富的插件和配置选项,允许开发⼈员根据项⽬需求进⾏定制。可以灵活配置打包过程中的各种处理和优化⽅式,以满⾜项⽬的具体需求。

总结-现代前端应⽤需要打包⼯具进⾏打包编译的原因是为了:实现模块化管理、解决兼容性问题、静态资源处理和优化、代码分割和按需加载、开发环境⽀持、性能提升、多技术⽀持、⾃动化⼯作流程、第三⽅库管理和可定制化等⽅⾯的需求。

56.如果用卢反馈说感觉网页很卡顿,这个时候该如何排查问题?【热度: 768】

排查⽹⻚卡顿问题时,可以按照以下步骤进⾏处理:

  1. 验证⽤⼾反馈:⾸先,确认⽤⼾反馈的卡顿问题是否普遍存在,还是个别⽤⼾的特殊情况。可以与其他⽤⼾进⾏沟通或观察其他设备上的表现。

  2. 检查⽹络连接:检查⽤⼾的⽹络连接是否稳定。卡顿问题可能由于⽹络延迟或不稳定导致。可以要求⽤⼾进⾏⽹络速度测试,或者与⽤⼾确认⽹络连接是否正常。

  3. 检查服务器性能:确认服务器是否能够处理⽤⼾的请求。可以检查服务器的负载情况、处理请求的时间以及资源使⽤情况。如果服务器负载过⾼,可能导致⽹⻚卡顿。

  4. 检查前端代码:检查⽹⻚的前端代码是否存在问题。主要看是否有内存泄露、longtask等情况;

  5. 优化⽹⻚性能:对于前端代码存在性能问题的情况,可以尝试优化⽹⻚性能。例如,压缩和合并CSS和JavaScript⽂件、减少⽹络请求次数、使⽤缓存等⽅法来提⾼⻚⾯加载速度。

  6. 做好性能监控:持续监测⽹⻚的性能,并定期更新⽹⻚的代码和设计,以提升⽤⼾体验。

57.前端架构和前端工程化有什么区别?

58.如何理解前端工程化?

59.如何理解前端架构?

60.前端基建设计到哪些方面【热度: 5,782】

  1. webpack tree-shaking在什么情况下会失效?【热度:71】

62.[性能]常见性能指标获取方式?【热度: 654】

常⻅性能指标获取⽅式

指标所反映的⽤⼾体验

下表概述了我们的性能指标如何对应到我们的问题之上:开始了吗?

• ⾸次绘制、⾸次内容绘制FirstPaint(FP)/FirstContentfulPaint(FCP)有⽤吗?

• ⾸次有效绘制、主要元素时间点FirstMeaningfulPaint(FMP)/HeroElementTiming能⽤吗?

• 可交互时间点TimetoInteractive(TTI)好⽤吗?

• 慢会话LongTasks(从技术上来讲应该是:没有慢会话)

⻚⾯何时开始渲染-FP&FCP

这两个指标,我们可以通过performance.getEntry、performance.getEntriesByName、performanceObserver来获取。

图片

⻚⾯何时渲染主要内容-FMP&SI&LCP

FMP ,是⼀个已经废弃的性能指标。在实践过程中,由于FMP对⻚⾯加载的微⼩差异过于敏感,经常会出现结果不⼀致的情况。此外,该指标的定义依赖于特定于浏览器的实现细节,这意味着它不能标准化,也不能在所有Web浏览器中实现。⽬前,官⽅并没有提供有效的获取FMP的接⼝,因此性能分析的时候不再使⽤这个指标。

SI 和FMP⼀样,官⽅也没有提供有效的获取接⼝,只能通过lighthouse⾯板来查看,不作为Sentry等⼯具做性能分析的指标。

LCP ,和FMP类似,但只聚焦⻚⾯⾸次加载时最⼤元素的绘制时间点,计算相对简单⼀些。通过performanceObserver这个接⼝,我们可以获取到LCP指标数据。

图片

何时可以交互-TTI&TBT

TTI , time to ineractive ,可交互时间, lighthouse ⾯板中的六⼤指标之⼀,⽤于测量⻚⾯从开始加载到主要资源完成渲染,并能够快速、可靠地响应⽤⼾输⼊所需的时间,值越⼩约好。

官⽅资料:TTI。

和FMP、SI⼀样, 官⽅并没有提供获取 TTI 的有效接⼝ ,只能通过lighthouse⾯板来查看。计算⽅式⼈如下:

  1. 先进⾏FirstContentfulPaint⾸次内容绘制;

  2. 沿时间轴正向搜索时⻓⾄少为5秒的安静窗⼝,其中,安静窗⼝的定义为:没有⻓任务且不超过2个正在处理的⽹络请求;

  3. 沿时间轴反向搜索安静窗⼝之前的最后⼀个⻓任务,如果没有找到⻓任务,则在FCP步骤停⽌执⾏。

  4. TTI是安静窗⼝之前最后⼀个⻓任务的结束时间(如果没有找到⻓任务,则与FCP值相同)。

理解计算过程如下图:

TTI表⽰的是完全可交互的时间,每个web系统,对TTI时间定义可能并不⼀定相同,上⾯只是提供⼀个计算较为通⽤的TTI的⼀个⽅式。

交互是否有延迟-FID&MPFID&LongTask

FID 和 MPFID 可⽤来衡量⽤⼾⾸次交互延迟的情况, Long Task ⽤来衡量⽤⼾在使⽤应⽤的过程中遇到的延迟、阻塞情况。

FID , first input delay ,⾸次输⼊延迟,测量从⽤⼾第⼀次与⻚⾯交互(例如当他们单击链接、点按按钮或使⽤由JavaScript驱动的⾃定义控件)直到浏览器对交互作出响应,并实际能够开始处理事件处理程序所经过的时间。官⽅资料:FID。

FID指标的值越⼩约好。通过performanceObserver,我们可以获取到FID指标数据。

图片

MPFID , Max Potential First Input Delay ,最⼤潜在⾸次输⼊延迟,⽤于测量⽤⼾可能遇到的最坏情况的⾸次输⼊延迟。和FMP⼀样,这个指标已经被废弃不再使⽤。

Long Task ,衡量⽤⼾在使⽤过程中遇到的交互延迟、阻塞情况。这个指标,可以告诉我们哪些任务执⾏耗费了50ms或更多时间。

图片

⻚⾯视觉是否有稳定-CLS

CLS , Cumulative Layout Shift ,累积布局偏移,⽤于测量整个⻚⾯⽣命周期内发⽣的所有意外布局偏移中最⼤⼀连串的布局偏移情况。官⽅资料:CLS。

CLS,值越⼩,表⽰⻚⾯视觉越稳定。通过performanceObserver,我们可以获取到CLS指标数据。

图片

63.[性能]衡量页面性能的指标有哪些?【热度: 1,045】

64.浏览器本身是不支持模块化的, webpack是如何通过文件打包,让浏览器可以读取到前端各个模块的代码的?【热度:1,153】

65.如何搭建一套灰度系统?【热度: 1,226】

66.如何理解研发流程和研发效率,如何保障研发效率

67.webpack5 Module Federation了解多少

  1. source map了解多少【热度: 396】

69.如何定制前端项目代码规范【热度: 1,155】

当按照上述步骤定制前端代码规范时,可以按照以下详细步骤执⾏:

  1. 选择代码规范⼯具:

◦ 研究可⽤的代码规范⼯具,如ESLint、Prettier等。

◦ ⽐较各⼯具的功能、灵活性和社区⽀持,并选择最适合你团队和项⽬的⼯具。

  1. 定义规范:

◦ 针对项⽬的需求和团队的编码⻛格,制定代码规范的具体规则和约定。

◦ 参考⾏业内的代码规范,如AirbnbJavaScriptStyleGuide、GoogleJavaScriptStyleGuide等,以获取最佳实践和通⽤规则的参考。

◦ 考虑以下⽅⾯进⾏规范定义:

▪ 缩进和空格:确定使⽤的缩进⼤⼩、空格还是制表符等。

▪ 命名约定:定义变量、函数、类、⽂件等的命名约定。

▪ 代码⻛格:确定代码的⻛格规则,如花括号的位置、换⾏符的使⽤等。

▪ 语法约定:定义应该使⽤的语⾔特性和语法约定,如使⽤严格模式、避免使⽤特定的语⾔功能等。

  1. 配置规范⼯具:

◦ 创建代码规范⼯具的配置⽂件,如 .eslintrc.js 或 .prettierrc 。

◦ 在配置⽂件中指定所选规范⼯具的规则和选项,根据定义的规范进⾏配置。

◦ 根据需要,可以启⽤或禁⽤不同的规则,并进⾏其他⾃定义配置。

  1. 集成到开发环境:

◦ 集成代码规范⼯具到开发环境,以实现⾃动检测和修复代码规范问题。

◦ 针对使⽤的编辑器或集成开发环境(IDE),安装相应的插件或扩展来⽀持代码规范检查和格式化。

◦ 配置构建⼯具(如webpack)或版本控制系统(如Git)的钩⼦,以在代码提交前运⾏代码规范检查。

  1. 告知团队:

◦ 与团队成员分享定制的代码规范,并解释规范的⽬的和重要性。

◦ 提供规范的⽂档或指南,以便团队成员参考和遵循。

◦ 组织⼀个会议或培训,介绍代码规范并解答团队成员的疑问。

  1. 定期审查和更新:

◦ 定期审查代码规范的有效性,并根据实际需求进⾏更新和调整。

◦ 接收团队成员的反馈和建议,以改进和优化代码规范。

◦ 在项⽬演进和技术发展的过程中,适时地更新代码规范以适应变化的需求。

以上步骤是⼀个通⽤的指南,你可以根据⾃⼰的团队和项⽬的特定要求进⾏调整和执⾏。此外,团队中的讨论和协商也是⾮常重要的,确保所有成员都参与到代码规范的制定和执⾏中。

70.如何编写一个babel插件【热度: 1,062】

71.SSR了解多少【热度:486】

72.Babel Polyfill了解多少【热度: 200】

73.幽灵依赖是什么

73.如何将JavaScript代码解析成抽象语法树(AST【热度: 1,169】

74.npm script生命周期有哪些?【热度:519】

75.[React] react是如何实现页面的快速响应?【热度: 696】

76.npm包管理了解多少?【热度: 1,321】

npm是如何进⾏依赖管理的?

npm是通过package.json⽂件来进⾏依赖管理的。当在项⽬中使⽤第三⽅库时,我们可以在 package.json中添加对应的依赖项及版本号,npm会根据package.json中的依赖关系,⾃动安装相应的依赖包及其依赖项。当我们执⾏npminstall命令时,npm会⾃动根据package.json中的依赖信息进⾏依赖包的安装。

npm的依赖管理还涉及到依赖的版本控制,可以在package.json中指定对应的版本号,常⻅的版本号控制符号有:

• ^(caret) :匹配到次要版本号(第⼆个数字)的最新版本。例如,^1.2.3表⽰安装1.2.x的最新版本(除了1.3.0)。

• ~(tilde) :匹配到修订版本号(第三个数字)的最新版本。例如,~1.2.3表⽰安装1.2.3到1.2.x的最新版本(除了1.3.0)。

• * :匹配到最新的版本。

• = :匹配到⼤于或等于指定版本的最新版本。

• <、<=、> :匹配到⼩于、⼩于等于或⼤于指定版本的最新版本。

在npm的依赖管理中,还有两种类型的依赖关系:⽣产依赖和开发依赖。⽣产依赖是指在应⽤程序运⾏时必须要加载的依赖,开发依赖是指在应⽤程序开发过程中使⽤的依赖。在package.json中,⽣产依赖使⽤dependencies字段,开发依赖使⽤devDependencies字段。这样可以让项⽬更加清晰地管理其依赖关系。

npm有缓存包的能⼒吗?

npm有缓存包的能⼒。当你第⼀次使⽤npm安装⼀个包时,npm会⾃动将该包缓存在本地。这样,当你下次需要安装相同版本的该包时,npm就不必重新从⽹络上下载该包,⽽是直接使⽤缓存中的包。这样可以提⾼包的下载速度,节省⽹络带宽。

npm的缓存位于本地⽂件系统中的⼀个隐藏⽬录。默认情况下,缓存位于当前⽤⼾的主⽬录下的.npm⽬录中。你可以使⽤以下命令查看npm缓存的路径:

npm config get cache

你也可以通过npmcache命令来管理npm缓存,例如清空缓存:

npm cache clean

或者查看缓存的统计信息:

npm cache ls

npm是如何使⽤缓存中的包的?

使⽤缓存中的包可以通过以下两种⽅式实现:

• 使⽤ npm ci 命令

npmci命令会⾸先检查package-lock.json或npm-shrinkwrap.json⽂件,以确保安装的依赖与锁定的版本⼀致。然后,它会在node_modules⽬录下安装依赖,如果缓存中存在符合要求的包,npmci会直接从缓存中复制到node_modules⽬录下,⽽不需要重新下载和编译。

• ⼿动指定缓存路径

如果需要⼿动使⽤缓存中的包,可以在npminstall命令中指定缓存路径,例如:

npm install --cache /path/to/npm-cache

然后,执⾏npminstall命令时,npm会尝试从指定的缓存路径中获取包,如果找到匹配的包,就会直接复制到node_modules⽬录下。

需要注意的是,⼿动指定缓存路径的⽅式可能会导致不同的项⽬之间共⽤缓存,因此需要确保缓存路径的唯⼀性。

77.npx了解多少?【热度:290】

npx是什么

npx是⼀个由Node.js官⽅提供的⽤于快速执⾏npm包中的可执⾏⽂件的⼯具。它可以帮助我们在不全局安装某些包的情况下,直接运⾏该包提供的命令⾏⼯具。npx会在执⾏时,检查本地项⽬中是否安装了对应的依赖,如果没有安装则会⾃动下载安装,并执⾏命令。如果本地已经存在该依赖,则直接执⾏命令。

使⽤npx时,可以在命令⾏中输⼊要执⾏的包名加上其参数,例如:

npx create-react-app my-app

以上命令会在本地下载并运⾏create-react-app包中的可执⾏⽂件,创建⼀个名为my-app的React应⽤程序。

npx会把远端的包下载到本地吗?

npx不会像npm或yarn⼀样将包下载到本地的node_modules⽬录中。相反,它会在执⾏命令时,在本地缓存中寻找并下载包,然后执⾏该包中的命令。这样可以避免在开发过程中在全局安装⼤量的包,同时也可以确保使⽤的是最新版本的包。

npx执⾏完成之后,下载的包是否会被删除?

是的,npx会在执⾏完命令后删除下载的包。这是因为npx会在执⾏命令之前,将需要执⾏的包下载到⼀个临时⽬录中,并在执⾏完毕后删除该⽬录。这样可以避免在本地留下不必要的依赖包。如果需要保留依赖包,可以使⽤--no-cleanup选项来禁⽌删除下载的包。

78.npm lock文件了解多少?【热度:258】

79.语义化版本SemVer (Semantic Versioning)了解多少?

80.npm script了解多少?【热度: 364】

81.package,json配置了解多少?【热度:747】

82.[webpack] module、chunk 、bundle的区别【热度:136】

83.[webpack]分包的方式有哪些?

  1. [webpack] externals 作用是啥?

webpack 中的 externals 配置项⽤于指定在打包时需要排除掉的模块,这些模块会被视为外部依赖,即不会被打包进最终的输出⽂件中,⽽是通过其他⽅式引⼊。

使⽤ externals 配置项可以使得打包后的代码⽂件更⼩,同时也可以在运⾏时从外部获取依赖,例如通过CDN、全局变量或者通过 require 的⽅式等。

举个例⼦,假设我们需要在项⽬中引⼊ jquery 库,但我们并不想在打包的过程中将其打包进最终的输出⽂件中,⽽是从外部引⼊。我们可以通过以下的配置来实现:

图片

这⾥的 externals 配置项告诉 webpack 在打包时忽略 jquery 模块的引⽤,⽽在代码运⾏时,我们需要⼿动将 jquery 通过 script 标签引⼊,并将其暴露在全局变量 jQuery 下,例如:

图片

这样在代码中引⼊ jquery 模块时, webpack 就会将其作为外部依赖进⾏处理,⽽不是将其打包进输出⽂件中。

需要注意的是,使⽤ externals 配置项需要谨慎,因为如果在运⾏时⽆法正确获取到指定的外部依赖,就会导致代码运⾏出错。

85.[webpack]异步加载原理是啥

Webpack异步加载模块的⽅式主要有以下⼏种

  1. 使⽤动态import:使⽤ES6的 import() 语法,动态加载模块。

图片

  1. 使⽤require.ensure:异步加载模块并将其放置到指定的chunk中。

图片

  1. 使⽤bundle-loader:将模块放置到⼀个单独的⽂件中,按需加载。

图片

  1. 使⽤webpack的require.ensure API

图片

  1. 使⽤webpack的import动态导⼊

图片

这些⽅式都可以在Webpack中使⽤,具体使⽤哪种⽅式,取决于具体的场景和需求。

动态加载的原理

在Webpack中,异步加载组件的原理是利⽤动态导⼊(Dynamicimport)特性。使⽤动态导⼊可以将模块的加载从编译时刻延迟到运⾏时刻。

具体来说,当Webpack打包代码时,遇到动态导⼊语句时不会将其打包进⼊主⽂件,⽽是将其单独打包为⼀个新的⽂件。在运⾏时,当代码需要加载该组件时,会通过⽹络请求动态加载该⽂件。

这样做的好处是可以减⼩主⽂件的体积,从⽽加快⻚⾯的加载速度,并且也可以提⾼代码的灵活性和可维护性。同时,Webpack还可以对动态加载的⽂件进⾏代码分割和按需加载,进⼀步优化⻚⾯的性能。

在使⽤动态导⼊时,需要注意⼀些细节。例如,在⽀持动态导⼊的浏览器中,需要使⽤ import() 函数进⾏动态导⼊;⽽在不⽀持动态导⼊的浏览器中,需要使⽤Webpack提供的 require.ensure 或 require.include 等⽅法进⾏模块的异步加载。同时,还需要注意动态导⼊的兼容性和性能问题。

  1. [webpack]核心库- tapable的设计思路与实现原理是什么?

87.[webpack]构建流程是怎么样的?

88.小程序的大概原理?

  1. [Webpack] webpack热更新原理是什么?

90.如果用卢说web应用感觉很慢,该如何排查?

91.[webpack]如果解决重复引用node_modules 里面的不同版本的包

解决重复引⽤ node_modules 中不同版本的包的问题,可以通过以下⼏种⽅式:

1.使⽤npm或者yarn的⼯具进⾏依赖的版本控制,尽量避免引⽤不同版本的同⼀个依赖库。在package.json⽂件中使⽤"^"、"~"、">="等⽅式指定依赖版本,可以有效减少不同版本的包冲突问题。

2.使⽤webpack的resolve.alias配置选项,将需要共享的模块指定到⼀个⽬录下,然后在其它模块中使⽤别名引⽤该模块。例如,将需要共享的模块指定到src/shared⽬录下,然后在其它模块中使⽤别名@Shared_CD引⽤该模块,这样就可以保证在不同模块中引⽤相同的依赖库。

假设我们在项⽬中同时依赖了两个库:lodash 和 lodash-es ,并且它们分别被安装在了不同的⽬录下,如下所⽰:

图片

我们需要在项⽬中同时引⽤这两个库,但是如果我们在代码中分别使⽤ import _ from 'lodash' 和 import _ from 'lodash-es' ,那么webpack会将它们打包成两个独⽴的模块,导致代码体积变⼤。

为了解决这个问题,我们可以通过 resolve.alias 配置项将它们指向同⼀个模块。具体做法是在 webpack配置⽂件中添加以下内容:

图片

这样⼀来,当我们在代码中使⽤ import _ from 'lodash-es' 时,webpack会⾃动将它解析成对 lodash 的引⽤,从⽽避免了重复打包的问题。

3.使⽤webpack的ProvidePlugin插件,将需要共享的模块注⼊到全局作⽤域中,这样就可以在不同模块中共享相同的依赖库。例如,在webpack配置⽂件中添加以下代码:

图片

这样在不同模块中就可以使⽤$、jQuery、window.jQuery全局变量引⽤jquery依赖库,避免了重复引⽤不同版本的jquery包的问题。

4.使⽤webpack的resolve.modules配置选项,将node_modules⽬录移动到项⽬根⽬录之外,然后在resolve.modules中添加该⽬录的绝对路径,这样就可以解决不同模块中引⽤相同依赖库不同版本的问题。例如,在webpack配置⽂件中添加以下代码:

图片

这样webpack在查找依赖库的时候,会先在项⽬根⽬录下的src⽬录中查找,如果没有找到再去 node_modules⽬录中查找,避免了不同模块中引⽤相同依赖库不同版本的问题。

  1. [webpack]是如何实现treeShaking的

webpack实现treeshaking的原理是基于ES6模块化语法的静态特性。

在编译阶段,Webpack会根据模块的依赖关系,通过AST(抽象语法树)进⾏静态分析,识别出那些代码块(函数、变量、对象等)被引⽤并且使⽤了。然后将这些代码块打包输出到最终的打包⽂件中。在这个过程中,Webpack会⾃动将未被引⽤的代码块进⾏剔除,这个过程就是treeshaking。

具体来说,当Webpack在打包时遇到⼀个ES6模块导⼊语句(import),它会⾃动去加载这个模块并分析其导出对象。然后它会分析项⽬中哪些导出对象被引⽤了。如果⼀个导出对象没有被引⽤,那么Webpack会直接把它从最终的代码中剔除掉。

需要注意的是,treeshaking只对ES6模块⽣效,对于CommonJS等其他模块化规范,由于其动态加载特性,⽆法在静态分析阶段确定哪些代码块被引⽤,因此⽆法进⾏treeshaking。

另外,为了使Webpack能够正确识别和剔除未引⽤的代码块,开发者也需要做出⼀定的努⼒,例如将代码编写为纯函数的形式,避免使⽤全局变量等副作⽤等。

93.[webpack] loader和plugin有啥区别

94.[webpack] webpack是如何给web应用注入环境变量的,原理是啥

  1. babel的工作流程是如何的?

  2. [webpack]什么情况下webpack treeShaking会失效?

97.不用使用vue-cli,如何创建一个完整的vue工程?

这个⼀个较为复杂和庞⼤的话题,不能称之为问题,只能说它是⼀个话题。主要涉及到的话题如下:

  1. vue⼯程初始化

  2. 测试集成

  3. UI库绑定、基础组件使⽤

  4. 开发流程

  5. 代码规范(甚⾄包含commit规范)

  6. 多⼈协作与⼯作流

  7. 构建问题

  8. 上线流程

  9. 线上⽇志与⽤⼾反馈问题排查

  10. 性能保证

98.使用虚拟DOM一定会比直接操作真实DOM快吗?

⼤家惯有的思维模式下,我们普遍的认为,虚拟DOM⼀定会⽐原⽣DOM要快的多。但实际上并不是这样。

仅从React的⻆度来说:React的官⽹可从来都没有说过虚拟DOM会⽐原⽣操作DOM更快。

虚拟DOM和原⽣操作DOM谁更快这个问题。如果要我来回答的话,⼀定是原⽣DOM⽐虚拟DOM更快性能更好。

值得注意的是,虚拟DOM并不是⽐原⽣DOM快,更确切的来说,虚拟DOM是⽐操作不当的原⽣DOM快。实际上,如果对原⽣DOM的操作得当的话,原⽣DOM的性能⼀定优于虚拟DOM。

我们来剖析⼀下。

虚拟DOM为什么⽽存在

其最核⼼的思想是提升开发效率⽽⾮提升性能

使⽤React/Vue这些框架的时候,我们不需要去考虑对DOM的操作,只需要关⼼数据的改变。我们以前还在使⽤JQ的时候,数据改变之后我们需要调⽤ $("#id").append(node) 等操作去⼿动追加DOM。⽽在使⽤React/Vue之后,我们只需要关⼼数据的改变。⾄于对DOM的⼀系列动作,在我们的数据改变之后,React/Vue会为我们代劳。这极⼤程度的提升了我们的开发效率。也是React/Vue的核⼼思想和初衷。

⾄于很多⼈都说,虚拟DOM会⽐操作原⽣DOM更快,这个说法并不全⾯。⽐如,⾸次渲染或者所有节点都需要进⾏更新的时候。这个时候采⽤虚拟DOM会⽐直接操作原⽣DOM多⼀重构建虚拟DOM树的操作。这会更⼤的占⽤内存和延⻓渲染时间。

举个例⼦

⾸次渲染 不采⽤虚拟DOM的步骤

  1. 浏览器接受绘制指令

  2. 创建所有节点

⾸次渲染 采⽤虚拟DOM的步骤

  1. 浏览器接受绘制指令

  2. 创建虚拟DOM

  3. 创建所有节点

不难发现,在⾸次渲染的时候,采⽤虚拟DOM会⽐不采⽤虚拟DOM要多⼀个创建虚拟DOM的步骤。

注意:虚拟DOM的存在,并不是免费的,⽐对新旧虚拟DOM树的差异会带来⼀定的性能开销。

虚拟DOM的优势在于我们更新节点时候。它会检查哪些节点需要更新。尽量复⽤已有DOM,减少DOM的删除和重新创建。并且这些操作我们是可以通过⾃⼰⼿动操作javascript底层api实现的。只是我们⼿动操作会⾮常耗费我们的时间和精⼒。这个⼯作由虚拟DOM代劳,会让我们开发更快速便捷。

举个例⼦

在采⽤虚拟DOM的前提下

假设我们有节点A,下辖两个⼦节点B/C.然后我们删除了节点C

这个时候会有两棵虚拟DOM树,

⼀颗是修改前的,A->B/C。另⼀颗是修改后的A->B。

diff算法会去⽐对两颗树的差异 ,然后发现A->B没有更改,那么A->B节点保留,C节点执⾏删除动作。

那么,A->B两个节点的删除和创建渲染操作就被省略了。

如果不采⽤虚拟DOM的话。使⽤JQ那时候的模板.我们可能会把A->B/C三个节点全部删除.

再全都重新创建。⽽A->B是完全没有改动的。他们的删除和创建则完全不必要。

框架的意义

我们需要知道:不论是React还是Vue或者是Angular。这些框架本⾝,都是基于原⽣的基础上创造的。它们,底层依赖的还是javascript,并不是⼀⻔新的语⾔。在他们的底层逻辑下。我们使⽤框架所做出的⼀切⾏为,都会被框架转化为对原⽣DOM的操作。框架,只是⼀个转化语法的⼯具。

既然原⽣DOM可以创造出这些框架。当然我们使⽤原⽣DOM⾃然是可以写出⽐这些框架更好的性能。

但是:为什么对原⽣DOM进⾏操作的性能明明可以⽐使⽤框架更好。为什么⼤家都在使⽤框架,⽽没有⼈去直接对原⽣DOM进⾏操作。

这背后涉及 成本 和 普适性 。

如果我们直接去操作真实DOM,当然,我们可以做到在性能上⽐虚拟DOM更快。但问题是,技术⽔准能做到这个地步的⼈,⼜有多少⼈呢。不说⽐虚拟DOM快。即使是做到和虚拟DOM不分上下的性能,拥有这种⽔平的前端玩家,也是寥寥⽆⼏。基于这样的客观情况下,框架的出现解决了这个问题。

框架存在的意义:在为我们提供只需要关注数据的前提下。框架本⾝已经做好了底层原理上的性能优化(包括但不限于,对DOM的调⽤,算法上的优化)已经是⾼度封装。这样就可以让我们使⽤⼀些简单的较为容易理解的技术去做我们原本做不到的事情。这其实就像调⽤⽹上的第三⽅包,某⼀个功能,⾃⼰写是写不出来,写出来性能也不会很好。但是同样的功能,我们去⽹上引⼊其他⼤神已经封装完成的第三⽅包。我们就会⽤,功能就可以实现并且性能上也过得去。

如果让⼤家直接对DOM进⾏操作完成⽐框架更优秀的性能。这绝不是⼤多数⼈可以做到的。让⼤多数可以接受,框架需要做的,就是让⼤多数⼈使⽤尽量使⽤简单的技术,完成相对困难的操作。这是 普适性 。

并且,如果完成同⼀个性能效果,需要我们去精通原⽣javascript和学习框架上的⼀些简单的API和结构。明显后者的学习成本更低。如果说使⽤框架我们所能完成的某⼀阶段的性能所需要的学习成本是2个⽉的话。那么学习javascript完成同⼀阶段的性能可能需要⼀年。

框架的初衷就是让⽤⼾使⽤尽量简单的技术,完成相对复杂的⼯作并提升⼀定的性能(这其中包括但不限于:可维护性,可复⽤性,渲染效率等)。这样,即使我们的⽔平不是很⾼,使⽤框架以后。项⽬在性能上也能过得去。

总结

  1. 虚拟DOM不⼀定会⽐操作原⽣DOM更快。

  2. 虚拟DOM的优势在于节点进⾏改动的时候尽量减少开销

  3. React从来没说过虚拟DOM会⽐原⽣更快。

  4. 框架的本质是提升开发效率,让我们的注意⼒更集中于数据

99.AMD和CMD模块化有和区别?

100.前端模块化发展历程?

101.前端单页应用History路由模式,需要如何配置nginx ?

102.实现JS沙盒的方式有哪些?

  1. pnpm了解多少?

104.pnpm和npm的区别?

图片

图片

小编将以上的前端工程化面试合集做了一个整理,还有更多的JavaScript、CSS、ES6、Vue、Vue3、React、Node.js、小程序、HTTP、Typescript、.Webpack、Git、Linux、算法面试、设计模式等面试题库也一并分享出来,供大家参考,需要的可以【点击此处】 即可免费获取小编整理的全部文档!!!