八股备份(不定时更新)

1.Vue中key值作用

高逼格答案: 提升vue渲染性能
  • 1.vue在渲染的时候,会 先把 新DOM 与 旧DOM 进行对比, 如果dom结构一致,则vue会复用旧的dom。 (此时可能造成数据渲染异常)
  • 2.使用key可以给dom添加一个 唯一标识符,让vue强制更新dom

2.vue组件传值

父传子

  • 1.子组件props定义变量
  • 2.父组件在使用子组件时通过行内属性给props变量传值
  • 特点:单向数据流

子传父

  • 1.子组件:$emit触发父的事件
  • 2.父在使用组件用@自定义事件名=父的方法 (子把值带出来)
  • 特点:事件监听

非父子组件

  • vuex

3.vue生命周期总共分为几个阶段?

核心: 四个阶段8个勾子

Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。

1**)beforeCreate**

在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。

2**)created**

在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer), 属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

3**)beforeMount**

在挂载开始之前被调用:相关的 render 函数首次被调用。

4**)mounted**

el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。

5**)beforeUpdate**

数据更新时调用,发生在虚拟DOM打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。

6**)updated**

由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

7**)activated**

keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。

8**)deactivated**

keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。

9**)beforeDestroy**

实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。

10**)destroyed**

Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

11**)errorCaptured(2.5.0+ 新增)**

当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

4.第一次加载页面会触发哪几个钩子函数?

  • 四个钩子
    • beforeCreate,
    • created,
    • beforeMount,
    • mounted 这几个钩子函数

5.Vue的路由实现模式:hash模式和history模式

1.路径不同
hash有#, history没有#
2.工作模式不同
hash : 修改当前页面hash,不需要服务器额外配置
history: 会给服务器发送请求,需要服务器配置
  • 1.hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用 window.location.hash 读取。特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。
  • 2.history模式:history采用HTML5的新特性;且提供了两个新方法: pushState(), replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更

6.请说出路由配置项常用的属性及作用

  • 路由配置参数:
    • path : 跳转路径
    • component : 路径相对于的组件
    • name:命名路由
    • children:子路由的配置参数(路由嵌套)
    • props:路由解耦
    • redirect:重定向路由

7.说一下你在vue中踩过的坑

  • 1操作data中的数据,发现没有响应式
    • 原因: 数组中有很多方法,有的会改变数组(例如pop push),有的不会改变数组(例如slice, filter)
    • 解决方案:通过Vue.set(对象,属性,值)这种方式就可以达到,对象新添加的属性是响应式的
  • 2.在created操作dom的时候,是报错的,获取不到dom,这个时候实例vue实例没有挂载
    • 解决方案:Vue.nextTick()回调函数进行获取
  • 3.其他的可以自由发挥,只要不是太低级就可以(比如,单词写错,代码位置写错,这种就是低级问题。其他的都可以说,千万别说这两个)

Vue 的 nextTick 的原理是什么?

  • 1为什么需要 nextTick
    • Vue 是异步修改 DOM 的并且不鼓励开发者直接接触 DOM,但有时候业务需要必须对数据更改--刷新后的 DOM 做相应的处理,这时候就可以使用 Vue.nextTick(callback)这个 api 了。
  • 2.知识储备(可以不说,但是自己要知道,以防不测)
    • 事件循环中宏任务和微任务这两个概念
    • 常见的宏任务有 script, setTimeout, setInterval, setImmediate(一种执行更加频繁的定时器)
    • 常见的微任务有 ,Promise.then(), async
  • 3.最终答案:
    • nextTick 的原理是 vue 通过异步队列控制DOM 更新
    • nextTick底层是promise,所以是微任务。这个一定要知道
    • (官方语言) : nextTick 回调函数先后执行的方式。如果大家看过这部分的源码,会发现其中做了很多 isNative()的判断,因为这里还存在兼容性优雅降级的问题。可见 Vue 开发团队的深思熟虑,对性能的良苦用心。
  • 4.小科普:其实vue在版本更新的时候。 时而将nextTick封装成宏任务,时而将nextTick封装成微任务。 不过目前vue2最新的版本,nextTick底层是微任务

v-slot插槽与作用域插槽

  • 1.插槽作用:父组件 传递 html结构 给 子组件
  • 2.具名插槽作用:父组件 传递 多个html结构 给 子组件
  • 3.作用域插槽作用:父组件 给 子组件 传递插槽 时,可以使用子组件内部的数据

Vue路由作用与原理

  • 路由作用: 实现单页面应用
  • 原理:监听location的hash值

自定义指令的方法有哪些?它有哪些钩子函数?还有哪些钩子函数参数?

  • 全局定义指令:在vue对象的directive方法里面有两个参数,一个是指令名称,另外一个是函数。组件内定义指令:directives
  • 钩子函数:bind(绑定事件触发)、inserted(节点插入的时候触发)、update(组件内相关更新)
  • 钩子函数参数:el、binding

面试内容:

1、几道基础面经题:如数组常用方法、vue父子组件传值方式、跨域原因及处理方案、BFC概念、promise相关、页面的重绘重排、MVVM概念、简单算法题 等等,准备了大约20道题,随机抽。
2、实操相关:element-ui 覆盖方式、调试方法、跨域处理、axios封装等等。
3、工程化相关:前后端分离、打包自动化、代码版本管理、发布管理、微前端。
4、进阶相关:日志管理、标准工程化、标准样式化、自动化、组件化、插件化、nodeJS、性能优化。
5、业务线技术相关:运维管理、nginx反向代理、服务器中台、数据库表结构、网关、安全、加密6、应用相关:uniapp、微信小程序、微信公众号、安卓、iOS。
7、项目相关。
8、个人经历

------------------------------------------------------------------------------------------------------------------------

1,问项目(40分)做过哪些项目,在其中怎么思考的。如果重头设计,会在设计时考虑哪些问题,如何规划好代码结构。这个问题考察候选人有没有从业务增长角度出发考虑架构设计。有没有完整的工程化实践。面对前端领域的问题,有没有丰富经验。有没有考虑性能优化等等。同时也考察候选人的责任心,主动性,沟通能力,项目管理能力,和一些技术视野和自个的编程哲学等。

2,问场景(30分)一道场景应用题。这道场景题会涉及用到框架底层原理,各种极端情况下的取舍于兜底,算法等知识。你可以随便找一道你们曾经处理过的比较复杂的需求,抽象一下并脱敏之后用作提问,看看候选人会如何思考。

3,问疑难杂症(20分)先问问候选人自己印象最深的bug是什么。问问定位排查解决的思路。也可以问问浏览器在极端情况下的bug。比如合成层爆炸相关的实际问题。极端情况下让gpu抢先cpu渲染,导致点击事件错位问题。比如极端情况下chrome请求丢失问题等。不要求解决,只要求排查思路。

4,问基础(10分)。比如js执行机制,浏览器渲染机制等等。这点我一般喜欢让候选人自个选一个自己熟悉的让他自由发挥,看看他有没有体系化的理解,最深入的知识点到哪一步等等。看看他在他擅长的领域能否打败我。

5,笔试(附加分)一些简单的应用题和算法题。还是得让候选人写写伪代码,主要看看思路和候选人的编码习惯。

-------------------------------------------------------------------------------------------------------------------------------

1. webpack是干什么的

  • 是什么
  • 核心功能
  • 具体的核心功能拆分 模块化管理、编译和转换、代码分割和懒加载、资源优化、热更新与开发环境支持、自定义扩展

Webpack 前端使用最流行的前端静态资源模块打包工具,它的核心功能是将项目中的各种静态资源(如JavaScript、CSS、图片、字体等)当作模块处理,通过一系列的加载器(loaders)和插件(plugins)对这些模块进行转义、压缩、Tree Shaking等处理方式后,利用模块化管理将它们有效地打包成一个或多个bundle文件,以供Web应用在浏览器中运行。

具体来说,Webpack的主要作用包括:

  1. 模块化管理:(4 大)支持CommonJS、AMD、ES6模块规范以及其他自定义模块格式,使得前端开发可以采用模块化的方式来组织和管理代码。
  2. 编译和转换:通过加载器,Webpack可以将各种类型的文件转化为浏览器可识别的格式,例如将ES6+的语法转换为ES5,将SCSS或Less编译成CSS,将图片和字体文件进行Base64编码或Url-loader处理等。
  3. 代码分割和懒加载:Webpack能够将代码分割成多个chunk,实现按需加载和动态导入,以提高应用的初始加载速度和运行时性能。
  4. 资源优化:通过minimizer插件(如UglifyJS或TerserWebpackPlugin)进行代码压缩,去除注释和空白字符,通过Tree Shaking移除未使用的代码,还可以对CSS进行提取和压缩,图片进行压缩优化等。
  5. 热更新与开发环境支持:Webpack Dev Server提供快速的开发环境支持,包括自动重新编译、热模块替换等功能,极大地提高了开发效率。
  6. 自定义扩展:Webpack具有高度的可扩展性,开发者可以通过编写自定义插件来实现更复杂的构建流程和任务处理。

2. Webpack构建流程

  1. 初始化 
  • 读取配置文件:Webpack从webpack.config.js或者其他指定的配置文件中读取构建参数,包括入口(entry)、输出(output)、加载器(loaders)、插件(plug-ins)等配置项。
  • 合并Shell参数:如果通过命令行传递了额外的参数,Webpack会合并这些参数到配置中。

·  启动Compiler 创建加载开始run

  • 创建一个Compiler对象,这是Webpack的核心执行对象,负责整个构建流程的控制。
  • 加载所有配置的插件,这些插件将在编译过程中发挥作用。
    • 会解析其中的module.rules,根据配置加载对应的Loader
    • 会加载plugins数组中配置的插件实例
  • 调用 Compiler 对象的 run 方法来启动整个编译过程。

·  解析Entry 

  • Compiler根据配置文件中的入口(entry point)开始解析,寻找入口模块。

·  递归解析依赖 

  • Webpack从入口模块出发,通过调用模块系统的API(如Node.js的fs模块读取文件内容)来读取模块内容。
  • 递归解析每个模块的依赖,形成一个依赖树。

·  编译模块 

  • 从入口文件开始,递归地编译每个模块:
    • 使用 Loader 对模块内容进行转换处理。
    • 分析模块间的依赖关系,对于每个模块找到其所有依赖的模块。
    • 这个过程中可能涉及抽象语法树(AST)的解析,用来收集模块的导入和导出信息
  • 在所有模块及其依赖被 Loader 处理完毕后,形成已翻译和链接的模块集合。

·  生成依赖图谱(Dependency Graph) 

  • Webpack根据解析和编译的结果生成一个详细的依赖关系图谱,其中包含了所有模块之间的依赖关系。
  • 构建依赖图的过程中,Webpack会根据配置的module.rules来确定每个模块应该应用哪些Loader。当遇到一个模块需要编译时,Webpack会按照Loader链(栈方式)的顺序执行它们,也就是从右到左(最后定义的Loader最先执行)
  • 根据模块间的依赖关系,Webpack 将模块组合成 chunks(通常包括 CommonsChunk 和按需加载的 chunk)。
  • 把每个 chunk 转换为一个或多个输出文件,这些文件会被添加到输出列表。
  • 在这个阶段,还可以通过插件干预输出内容,例如压缩、优化等操作。

·  优化(Processing with Plugins) 

  • 通过Plugin系统介入构建流程的各个阶段,执行诸如资源优化、代码分割(Code Splitting)、提取公共代码(Chunking)、Tree Shaking、持久化缓存(Persistent Caching)等操作。

·  生成最终输出文件(Bundle) 

  • 根据输出(output)配置,将处理过的模块内容和资源进行合并、压缩等操作,生成最终的JavaScript bundle文件以及其他静态资源文件。

·  写入文件系统 

  • 最终将生成的bundle文件和资源写入到指定的目录中。

·  完成构建 

  • 当所有模块处理完毕,所有输出资源都已经写入磁盘后,Webpack完成构建流程,并输出相关信息。

在构建过程中,Webpack会持续广播构建事件,插件可以监听这些事件并在恰当的时机执行自定义逻辑,进一步丰富和定制构建流程。

3. Loader和Plugin的区别

在Webpack中,Loader和Plugin是两个不同的概念,它们的作用和使用方式也有所不同。

  1. Loader:意为“加载器”,由于Webpack本身只能打包JS文件,对于非JS文件(如CSS、图片等)无法直接打包,因此需要引入第三方的模块进行打包。Loader扩展了Webpack,专注于转化文件这一个领域,主要作用是进行文件转化,完成压缩/打包/语言翻译等,以实现对非JS文件的打包。Loader在module.rules中配置,也就是说它作为模块的解析规则而存在。例如,处理CSS文件需要使用css-loader,处理图片需要使用file-loader等。使用Loader可以实现代码转换、文件处理、代码压缩等功能。
  2. Plugin:意为“插件”,主要用于扩展Webpack的功能,可以访问整个编译生命周期,包括加载器已经执行完毕之后的时期。Plugin的目标在于解决Loader无法实现的其他事。它针对打包过程中的某些事件节点执行自定义操作,如生成HTML文件、压缩代码、提取公共代码等。使用Plugin可以实现Webpack无法处理的复杂任务。Plugin在plugins中单独配置,类型可以是函数或带有apply方法的类。

总的来说,Loader主要用于文件的加载和转化,将非JS文件转化为Webpack可处理的模块;而Plugin则用于扩展Webpack的功能,对打包过程进行增强和优化。

Loader为专门解决某个子问题(eslint、scss)的加载器

Plugin 服务于整个webpack的生命周期

  • define-plugin:定义环境变量 (Webpack4 之后指定 mode 会自动配置)
  • ignore-plugin:忽略部分文件
  • Loader:Webpack将一切文件视为模块,但是Webpack原生只能解析JS/JSON文件。Loader的作用是让Webpack拥有了加载和解析非JavaScript文件的能力。Loader可以将文件从不同的语言或格式转换为Webpack可以处理的模块,例如将TypeScript转换为JavaScript,或将内联图像转换为data URL。Loader是一个转换器,专注于文件的编译和转换。
    • 核心是将 webpack 不能识别的模块转换成能识别的模块
    • 附加功能 :添加版权注释、图片太大转 base64
  • Plugin:Plugin可以扩展Webpack的功能,让Webpack具有更多的灵活性。Plugin在Webpack的编译和打包过程中起着关键作用,可以访问整个编译生命周期,包括加载器已经执行完毕之后的时期。Plugin可以执行范围更广的任务,如打包优化、资源管理和环境变量注入等。Plugin是一个扩展器,它丰富了Webpack本身,针对的是加载器结束后,Webpack打包的整个过程。
  • Loader:在Webpack的配置文件(通常是webpack.config.js)中,Loader在module.rules中配置。它们作为模块的解析规则而存在,以数组的形式定义,每个数组项是一个对象,描述了对于什么类型的文件(test属性)使用什么加载器(loader属性)以及使用的参数(options属性)。
  • Plugin:Plugin也在Webpack的配置文件中配置,但在plugins字段中单独配置。它们以数组的形式存在,每个数组项是一个Plugin的实例,参数都通过构造函数传入。Plugin并不直接操作文件,而是基于事件机制工作,会监听Webpack打包过程中的某些节点,然后执行特定的任务。

https://juejin.cn/post/7079765458416566303

Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。

将接收内容转译预处理为 webpack能够识别的js

从右向左开始编译:出于设计上的考虑,这一决策遵循了函数式编程中的思想

Plugin 就是插件,基于事件流框架 Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

  • Loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。
  • Plugin 在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。
  • loader 是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中
  • plugin 赋予了 webpack 各种灵活的功能,例如打包优化、资源管理、环境变量注入等,目的是解决 loader 无法实现的其他事
  • loader 运行在打包文件之前
  • plugins 在整个编译周期都起作用

  • 在Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过Webpack提供的 API改变输出结果
  • 对于loader,实质是一个转换器,将A文件进行编译形成B文件,操作的是文件,比如将A.scss或A.less转变为B.css,单纯的文件转换过程

4. Plugin 可以在loader 执行前执行吗

loader的执行发生在构建过程的开始阶段,当Webpack解析到需要加载的模块时,会根据配置文件中定义的loader来处理这些模块。加载器的执行顺序是从右到左,或者从下到上,这取决于配置文件中的定义。

Plugin的执行时机则更加灵活,它们可以监听Webpack编译器发出的事件,并在这些事件发生时执行自定义逻辑。这意味着Plugin可以在加载器执行之前、之后或甚至与loader并行执行,具体取决于插件所监听的事件和Webpack的生命周期阶段。

通常情况下,loader会在Plugin之前执行,因为loader负责将源文件转换为Webpack能够处理的模块,而插件则在这些模块已经处理完毕后的某个阶段执行自定义任务。尽管如此,有些插件可能会在加载器执行之前的某些阶段进行工作比如修改Webpack的配置或处理环境变量等。

以下的 Plugin 都是在 loader 之前就开始执行 :

  1. IgnorePlugin
    在打包过程中排除某些特定的模块,防止它们被打包进去。这个插件在解析模块之前就运行了,因此可以在加载器处理文件之前阻止某些模块的加载。
  2. ProvidePlugin
    自动加载模块,而不必到处import或require它们。这在加载器处理文件之前就已经设置好了,使得在源代码中可以直接使用某些模块而无需显式导入。
  3. EnvironmentPlugin
    这个插件可以从环境变量中创建全局变量。它在加载器处理文件之前就已经执行,并将环境变量暴露给Webpack配置和源代码。

在 loader 中执行工作

DefinePlugin
允许在编译时创建配置的全局常量。这可以对开发模式和发布模式下的构建进行区分,并允许在编译时对环境进行更细致的控制。这个插件在加载器转换文件之前就已经运行了。

在 loader 结束后执行的 plugin

  • CleanWebpackPlugin
  • MiniCssExtractPlugin 合并 css 文件
  • HtmlWebpackPlugin

5. ts-loader 做了哪些事

  1. 识别与加载: 当Webpack配置中设置了对.ts或.tsx文件的处理规则,并指定了使用ts-loader时,Webpack在编译过程中遇到这些文件时,会调用ts-loader。
  2. 类型检查: ts-loader首先会对TypeScript文件进行类型检查(type checking)。它会读取项目的tsconfig.json配置文件,按照其中的规则对TypeScript源代码进行编译前的类型检查。如果有类型错误,编译过程会终止,并报告错误信息。
  3. 编译转换: 通过调用TypeScript编译器(tsc),ts-loader将TypeScript源代码转换为JavaScript ES5或ES6(取决于tsconfig.json中的编译目标和模块选项)。这个过程中,高级的TypeScript特性(如泛型、装饰器、枚举、接口等)会被编译成JavaScript基础结构。
  4. 生成.d.ts声明文件*(可选): 如果配置允许,ts-loader还会生成相应的.d.ts声明文件,为编译后的JavaScript提供类型信息。
  5. 输出JavaScript文件: 编译后的JavaScript代码会被ts-loader传递回Webpack的编译流程中,Webpack接着会根据配置将这些代码和其他资源一同打包到bundle文件中。
  6. 与其他Webpack插件协同工作: ts-loader与Webpack生态中的其他插件可以很好地协同工作,例如与source-map-loader一起生成Source Map,以便于调试;或与eslint-loader结合,对TypeScript代码进行ESLint的风格检查。

6. 常用的plugins

  • CleanWebpackPlugin是在项目打包时先将上一次所打包的文件夹进行一次清除后再去打包的一种插件
  • HtmlWebpackPlugin插件能够在打包后帮助我们生成html文件,因为webpack打包是没有帮我们生成html文件的,所以我们需要这个插件帮助我们生成html文件,同时也可以对html文件进行一些另外的配置
  • define-plugin:定义环境变量 (Webpack4 之后指定 mode 会自动配置)
  • ignore-plugin:忽略部分文件
  • html-webpack-plugin:简化 HTML 文件创建 (依赖于 html-loader)
  • web-webpack-plugin:可方便地为单页应用输出 HTML,比 html-webpack-plugin 好用
  • uglifyjs-webpack-plugin:不支持 ES6 压缩 (Webpack4 以前)
  • terser-webpack-plugin: 支持压缩 ES6 (Webpack4)
  • webpack-parallel-uglify-plugin: 多进程执行代码压缩,提升构建速度
  • mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载 (替代extract-text-webpack-plugin)
  • serviceworker-webpack-plugin:为网页应用增加离线缓存功能
  • clean-webpack-plugin: 目录清理
  • ModuleConcatenationPlugin: 开启 Scope Hoisting
  • speed-measure-webpack-plugin: 可以看到每个 Loader 和 Plugin 执行耗时 (整个打包耗时、每个 Plugin 和 Loader 耗时)
  • webpack-bundle-analyzer: 可视化 Webpack 输出文件的体积 (业务组件、依赖第三方模块)

有没有手写过

https://juejin.cn/post/6992738808517099528

7. 常用的Loader

  1. 源代码转换 Loader
  • TypeScript Loader (ts-loader 或 awesome-typescript-loader):将 TypeScript 文件转译为 JavaScript。
  • Babel Loader (babel-loader):将 ES6+ 代码转换为向下兼容的 ES5 代码,或者其他目标环境的兼容代码。
  • JSX Loader (babel-loader with React preset):将 JSX(React 语法)转换为标准 JavaScript。
  • CoffeeScript Loader (coffee-loader):将 CoffeeScript 文件转换为 JavaScript。

·  样式文件处理 Loader

  • CSS Loader (css-loader):处理 CSS 文件,解决 CSS 中的 @import 和 url() 引用。
  • PostCSS Loader (postcss-loader):利用 PostCSS 插件处理 CSS,如自动添加浏览器前缀、变量替换等功能。
  • Sass/SCSS Loader (sass-loader 或 node-sass-loader):将 Sass 或 SCSS 样式表编译为 CSS。
  • Less Loader (less-loader):将 Less 样式表编译为 CSS。

·  图像和媒体资源处理 Loader

  • File Loader (file-loader):将二进制文件(如图片、字体等)复制到输出目录,并返回相对于输出路径的 URL。
  • URL Loader (url-loader):类似于 File Loader,但可以设置一个阈值,当文件小于指定大小时,将其转换为 Base64 编码内联到 JavaScript 或 CSS 中。

·  模板语言 Loader

  • HTML Loader (html-loader):处理 HTML 文件,提取其中的外部资源(如图片)并转换为模块引用。
  • Pug/Jade Loader (pug-loader):将 Pug 或 Jade 模板文件编译为 HTML。

·  静态资源管理 Loader

  • JSON Loader (json-loader):加载 JSON 文件并将其转换为 JavaScript 对象。
  • CSV Loader (csv-loader)、XML Loader (xml-loader) 等:加载并解析相应的数据格式文件。

·  高级功能 Loader

  • Webpack Banner Plugin (banner-loader):向文件顶部添加版权信息或其他注释。
  • Vue Loader (vue-loader):处理单文件 Vue 组件(.vue 文件)
  • coverjs-loader:计算测试的覆盖率
  • i18n-loader: 国际化
  • cache-loader: 可以在一些性能开销较大的 Loader 之前添加,目的是将结果缓存到磁盘里

8. 编写loader、plugin的思路

编写 loader

  • 确定需求:确定你要解决的问题或改进现有的功能。Loader 主要用于转换某种类型的文件,例如将 TypeScript 转换为 JavaScript、将 SASS 转换为 CSS 等。
  • 创建 Loader 模块:创建一个新的 Node.js 模块文件,例如 my-custom-loader.js。
  • 导出一个函数:在 Loader 文件中,你需要导出一个函数,该函数接收源代码(source code)和 Loader Context 作为参数:

export default function(source, map, meta) {

  // ...

};

  • 处理源代码:在函数内部,对源代码进行必要的转换操作。这可能涉及字符串操作、正则表达式匹配替换、第三方库的调用等。
    • 通常情况下,Loader 会返回一个新的转换后的源代码字符串:
  • 处理 Source Map(可选):如果你的 Loader 需要处理 Source Map(用于调试时映射原始代码到转换后代码的位置),则需要对传入的 map 参数进行相应处理,并在返回结果时一并提供新的 Source Map 数据。
  • 访问 Loader Context:Loader context 提供了一些有用的方法和属性,如 this.callback 用于返回处理后的结果,this.query 获取 Loader 配置参数等。利用这些上下文信息可以让你的 Loader 更加灵活。
  • 错误处理:如果在转换过程中出现错误,Loader 应通过 this.emitError(error) 报告错误。
  • 测试 Loader 是否适用:在 Loader 的 package.json 文件中声明 test 字段,或者在 webpack 配置文件中通过 test 属性明确指出此 Loader 应用于哪种类型的文件。
  • 发布和使用:编写完 Loader 后,将其发布到 npm 或私有仓库,然后在目标项目中通过 npm install 安装并在 Webpack 配置中引用。

编写 plugin

  • 定义插件类: Node.js 环境中创建一个新的 JavaScript 文件,例如 my-custom-plugin.js。
    • 创建一个继承自 webpack.Plugin 类的自定义插件类:
  • 构造函数:在插件类中定义构造函数,用于初始化插件实例所需的任何参数或配置:
  • 挂载钩子方法:Webpack 插件的工作原理是通过监听和响应 Webpack 生命周期中的钩子函数。根据你的需求,在插件类中定义适当的钩子方法:
    • 例如,如果你想在编译开始前执行一些操作,可以监听 compiler.hooks.compile;若要在生成资源文件后进行操作,可以监听 compiler.hooks.emit 等。
  • 编写处理逻辑
    • 在挂载的钩子方法内部,编写具体的业务逻辑。可以操作 webpack compiler 或 compilation 对象,以实现你的功能需求,如修改输出文件、注入额外代码、删除无效资源等
  • 错误处理:如果在插件运行过程中发生错误,可以使用 this.emitError(error) 报告错误。
  • 导出插件类:module.exports = MyCustomPlugin;
  • 配置和使用:在 Webpack 配置文件中,引入你自定义的插件,并将其添加到 plugins 数组中
    • 可以发布到公共 npm 仓库或私有仓库

9. Tree Shaking原理

在JavaScript编译器和打包工具(如Webpack)的上下文中,“树摇”(Tree Shaking)是一种优化技术,主要用于消除代码中未被引用的无用模块,从而减少最终生成的bundle文件大小。它的底层原理基于静态分析和模块系统的特性。

基本原理

  1. 静态分析
  • 摇依赖于ES6模块系统,因为ES6模块具有静态结构即在编译时就可以确定模块的导入和导出内容。Webpack和其他工具通过分析模块的import/export语法来判断哪些模块成员被真正使用到了。

·  模块依赖图: 

  • 构建工具首先构建出整个项目的模块依赖关系图,其中包括每个模块导出和导入的内容。

·  死代码剔除

  • 在编译阶段,工具会对模块进行分析,寻找那些未被任何模块导入的导出成员。由于这些成员没有被引用,因此它们被认为是死代码(Dead Code)。

·  优化输出

  • 在生成最终bundle的过程中,工具会剔除这些未使用的导出成员,确保最终输出的bundle中不包含未使用的代码。

简单来说,"树摇"这个名字形象地比喻了如同摇晃一棵大树,将枯叶(未引用的代码)摇落的过程。在Webpack中,Tree Shaking通常配合诸如UglifyJS或Terser等压缩工具一起工作,后者也具备类似的能力来移除未引用的变量和函数。而在现代Webpack配置中,通过开启mode为production以及使用合适的优化插件,Webpack本身就能够较好地实现Tree Shaking。

10. webpack提高效率的插件

  • webpack-dashboard:可以更友好的展示相关打包信息
  • webpack-merge:提取公共配置,减少重复配置代码
  • speed-measure-webpack-plugin:简称 SMP,分析出 Webpack 打包过程中 Loader 和 Plugin 的耗时,有助于找到构建过程中的性能瓶颈
  • size-plugin监控资源体积变化,尽早发现问题
  • HotModuleReplacementPlugin:模块热替换

11. source map是什么?生产环境怎么用

source map 是将编译、打包、压缩后的代码映射回源代码的过程。打包压缩后的代码不具备良好的可读性,想要调试源码就需要 soucre map。

map文件只要不打开开发者工具,浏览器是不会加载的。

线上环境一般有三种处理方案:

  • hidden-source-map:借助第三方错误监控平台 Sentry 使用
  • nosources-source-map:只会显示具体行数以及查看源代码的错误栈。安全性比 sourcemap 高
  • sourcemap:通过 nginx 设置将 .map 文件只对白名单开放(公司内网)

注意:避免在生产中使用 inline- 和 eval-,因为它们会增加 bundle 体积大小,并降低整体性能。

12. 文件监听原理

原理:轮询判断文件的最后编辑时间是否变化,如果某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等 aggregateTimeout 后再执行。

发现源码发生变化时,自动重新构建出新的输出文件。

Webpack开启监听模式,有两种方式:

  • 启动 webpack 命令时,带上 --watch 参数
  • 在配置 webpack.config.js 中设置 watch:true

缺点:每次需要手动刷新浏览器

13. P0热更新原理

Webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。 这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。

HMR的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上 WDS 与浏览器之间维护了一个 Websocket,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发起 Ajax 请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp 请求获取该chunk的增量更新。

后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由 HotModulePlugin 来完成,提供了相关 API 以供开发者针对自身场景进行处理,像react-hot-loader 和 vue-loader 都是借助这些 API 实现 HMR。

14. 如何对bundle体积进行监控和分析?

前端代码编辑器 ide 插件 Import Cost 可以帮助我们对引入模块的大小进行实时监测,

还可以使用 webpack-bundle-analyzer 生成 bundle 的模块组成图,显示所占体积。

bundlesize 工具包可以进行自动化资源体积监控。

15. webpack 打包是hash码是如何生成的

.webpack生态中存在多种计算hash的方式

  1. hash:这是根据每次编译会话(compilation)来生成的 hash,每次编译都会生成一个新的 hash,即使文件内容没有发生任何变化。因此,这种 hash 不能用于长期缓存。
  2. chunkhash:这是根据每个 chunk 的内容生成的 hash,当 chunk 的内容发生变化时,chunkhash 才会发生变化。这种 hash 可以用于长期缓存,但是需要注意的是,如果入口文件发生了变化,其依赖的所有 chunk 的 chunkhash 都会发生变化。
  3. contenthash:这是根据文件内容生成的 hash,只有当文件内容发生变化时,contenthash 才会发生变化。这种 hash 是最精确的,也是最适合用于长期缓存的。在 Webpack 中,可以通过配置 output.filename 中的占位符来使用 contenthash,例如:[name].[contenthash].js。

2.避免相同随机值

  • webpack在计算hash后分割chunk。产生相同随机值可能是因为这些文件属于同一个chunk,可以将某个文件提到独立的chunk(如放入entry)

16. 文件指纹是什么?怎么用?

文件指纹是打包后输出的文件名的后缀。

  • Hash:和整个项目的构建相关,只要项目文件有修改,整个项目构建的 hash 值就会更改
  • Chunkhash:和 Webpack 打包的 chunk 有关,不同的 entry 会生出不同的 chunkhash
  • Contenthash:根据文件内容来定义 hash,文件内容不变,则 contenthash 不变

JS的文件指纹设置

设置 output 的 filename,用 chunkhash。

CSS的文件指纹设置

设置 MiniCssExtractPlugin 的 filename,使用 contenthash。

module.exports = {

    entry: {

        app: './scr/app.js',

        search: './src/search.js'

    },

    output: {

        filename: '[name][chunkhash:8].js',

        path:__dirname + '/dist'

    },

    plugins:[

        new MiniCssExtractPlugin({

            filename: `[name][contenthash:8].css`

        })

    ]

}

图片的文件指纹设置

设置file-loader的name,使用hash。

占位符名称及含义

  • ext 资源后缀名
  • name 文件名称
  • path 文件的相对路径
  • folder 文件所在的文件夹
  • contenthash 文件的内容hash,默认是md5生成
  • hash 文件内容的hash,默认是md5生成
  • emoji 一个随机的指代文件内容的emoj

const path = require('path');

module.exports = {

    entry: './src/index.js',

    output: {

        filename:'bundle.js',

        path:path.resolve(__dirname, 'dist')

    },

    module:{

        rules:[{

            test:/\.(png|svg|jpg|gif)$/,

            use:[{

                loader:'file-loader',

                options:{

                    name:'img/[name][hash:8].[ext]'

                }

            }]

        }]

    }

}

17. 如何保证各个loader按照预想方式工作?

可以使用 enforce 强制执行 loader 的作用顺序,pre 代表在所有正常 loader 之前执行,post 是所有 loader 之后执行。(inline 官方不推荐使用)

Webpack 中的 loader 在执行时是串行关系,也就是说,当一个文件需要经过多个 loader 处理时,这些 loader 会按照配置的顺序依次执行。这种顺序通常是从右到左,即从配置数组的最后一项开始,向前执行,直至第一项。每个 loader 会接收前一个 loader 的处理结果作为输入,然后输出自己的处理结果给下一个 loader,直到所有 loader 执行完毕,最后将最左侧 loader 的输出作为最终结果

18. 代码分割的本质?意义

代码分割的本质其实就是在源代码直接上线和打包成唯一脚本main.bundle.js这两种极端方案之间的一种更适合实际场景的中间状态。

阿卡丽:荣耀剑下取,均衡乱中求

「用可接受的服务器性能压力增加来换取更好的用户体验。」

源代码直接上线:虽然过程可控,但是http请求多,性能开销大。

打包成唯一脚本:一把梭完自己爽,服务器压力小,但是页面空白期长,用户体验不好。

(Easy peezy right)

19. 钩子函数

Webpack 中的钩子函数是由其内部使用的 Tapable 库提供的,用于插件系统中扩展和定制构建过程。Tapable 提供了一系列同步和异步的钩子,使得插件可以在合适的时机介入编译过程,执行自定义逻辑。虽然具体的钩子函数数量随着 Webpack 版本的升级可能会有所增减和变化,但下面是一些常见的 Webpack 钩子函数示例:

Compiler Hooks (编译器级别的钩子)

  • compile: 在新的编译开始时调用。
  • make:在开始编译所有模块之前调用。
  • watchRun:在 watch 模式下每次重新编译之前调用。
  • normalModuleFactory:创建 NormalModuleFactory 时调用,可用于修改模块工厂的行为。
  • afterCompile:在完成编译之后调用。
  • done:整个编译完成后调用,包括所有额外的处理步骤(如生成资产等)。
  • invalid:当依赖项发生变化导致重新编译时调用。

Compilation Hooks (编译阶段的钩子)

  • optimizeAssets / optimizeChunkAssets:在压缩或处理输出的资产(如 JavaScript 和 CSS 文件)之前调用。
  • optimizeModules / optimizeChunks:在模块和chunk优化阶段调用。
  • seal:在编译准备封存并输出资源之前调用。
  • additionalAssets:在所有其他资产生成完毕后,如果插件还需要生成额外的资产,则可以在此钩子中添加。
  • emit:在所有资源准备就绪即将写出到硬盘时调用。

Module Hooks (模块级别的钩子)

  • moduleFactory:在模块工厂创建模块时调用。
  • parser:在模块解析阶段可以用来修改模块的 AST(抽象语法树)。
  • buildModule:在模块开始构建时调用。

实际使用中会有更多的细节钩子。每个钩子都允许插件在特定时刻改变或增强 Webpack 的行为,例如添加额外的转换步骤、修改输出内容、甚至完全接管某个编译阶段。对于具体的使用场景,需要查阅 Webpack 官方文档或查看相关插件的源码来获取更准确和详尽的信息。

20. 针对构建速度的优化

  1. 升级 Webpack 版本: 确保使用最新版本的 Webpack,新版本通常包含了性能优化和更快的构建算法。
  2. 使用缓存机制
  • 开启 Webpack 内置的持久化缓存(在 Webpack 5 中默认开启部分缓存功能)。
  • 使用 cache-loader 在 loaders 中增加缓存层。
  • 应用 hard-source-webpack-plugin 这样的第三方插件,它提供了更强大的缓存机制。

·  多进程/多实例构建

  • 利用 Webpack 5 的并行构建特性(通过设置 parallel 选项)。
  • 使用 thread-loader 或已过时的 happypack 将工作负载分配到多个核心,加快编译速度。

·  DLLPlugin 和 DLLReferencePlugin: 预先打包第三方库,使主构建流程避开这部分代码,只重新编译项目自身的变动代码。

·  优化 Loader 和 Plugin 配置

  • 减少不必要的 Loader 应用范围,精简 Loader 链。
  • 选择高效的 Loader 和 Plugin,如使用 tree-shaking 功能的 UglifyJS 或 TerserPlugin 进行压缩。

·  优化 Resolve 配置

  • 设置 resolve.modules 和 resolve.extensions 来减少寻找模块路径所需的时间。
  • 使用 resolve.alias 创建别名,简化模块引用路径。

·  Tree Shaking 和 Scope Hoisting

  • 启用 Tree Shaking(摇树优化),移除未使用的代码。
  • 使用 Webpack 的 module concatenation 或 optimization.concatenateModules 选项来减少模块间的开销。

·  懒加载和代码分割

  • 按需加载代码块,避免一次性加载所有资源。

·  开发环境热更新(HMR)优化

  • 调整 HMR 设置,使得只有更改过的模块重新编译和刷新浏览器。

·  缩小构建范围

  • 通过 watch 模式下设置 watchOptions 来监视指定的文件变化,而非整个项目。

·  Scope hoisting

  • Scope hoisting(作用域提升)技术能够间接地提高构建速度,尤其是在客户端加载和执行代码时。
  • 在 Webpack 中,Scope hoisting 是一种用于优化输出代码的编译策略。在不启用 Scope hoisting 的情况下,每个模块会被包裹在一个闭包函数里,这会导致在运行时有大量的函数调用和作用域上下文切换。启用 Scope hoisting 后,Webpack 会尝试分析模块间的依赖关系,尽可能地将模块内的变量和函数提升到同一作用域内,从而减少函数调用和闭包的数量,使得最终生成的代码体积更小,减少了代码的执行开销。
  • 虽然 Scope hoisting 主要是针对代码体积和运行性能进行优化,但理论上较小的代码体积也会带来更快的网络传输速度,从而间接改善用户体验和加载速度。此外,由于 Scope hoisting 降低了运行时的函数调用开销,页面的初始加载速度和执行速度有可能得以提高,特别是对于依赖众多的小模块而言。
  • 然而,在构建过程中,Scope hoisting 的实现和分析过程可能会增加编译时的计算负担,因此在构建速度方面,它并不一定总是显著提升编译速度,反而在某些情况下可能略微增加构建时间。但从总体效果来看,考虑到它带来的运行时性能提升和代码体积减小的优势,Scope hoisting 仍然是一个值得开启的优化选项。

·  动态Polyfill

  • 建议采用 polyfill-service 只给用户返回需要的polyfill,社区维护。 (部分国内奇葩浏览器UA可能无法识别,但可以降级返回所需全部polyfill)

21. webpack 怎么配置前端的优化

  1. 代码分割与动态加载(Code Splitting)
    Webpack可以通过import()动态导入模块或者配置SplitChunksPlugin来实现代码分割,将大型应用拆分成多个较小的块,这样在初始加载时只需加载必需的模块,其余模块按需加载。这可以显著减少首次加载时间,提高页面的加载速度。
  2. Tree Shaking(死代码消除)
    Webpack配合ES6模块语法和摇树优化插件(如TerserWebpackPlugin),可以分析出哪些模块成员未被引用,并在打包过程中将其去除,从而减小最终输出文件的大小。
  3. 资源压缩与混淆(Minification)
    使用诸如UglifyJSPlugin(已被TerserWebpackPlugin替代)、cssnano等工具对JavaScript和CSS进行压缩和混淆,去掉空白字符、注释、缩短变量名等,减少文件大小。
  4. 模块热更新(Hot Module Replacement, HMR)
    在开发环境下,Webpack的HMR功能可以实现模块的热替换,避免因代码修改而全页刷新,从而提升开发体验和效率。
  5. 懒加载(Lazy Loading)
    Webpack配合路由懒加载技术,可以延迟非首屏所需的组件和资源的加载,提升页面首屏显示速度。
  6. 资源指纹与缓存策略
    Webpack通过output.filename和output.chunkFilename的哈希命名策略,确保每次构建后资源文件的名称包含哈希值,利于客户端缓存,同时确保资源更新时浏览器能正确请求最新版本。
  7. 公共模块抽离(CommonsChunkPlugin / optimization.splitChunks)
    抽取多个入口chunk中重复使用的公共模块,将其单独打包到一个或多个文件中,避免重复加载。
  8. 资源预加载(Prefetching/Prefetch)
    预测用户下一步可能需要的资源,并在空闲时间提前下载,减少后续页面跳转或交互时的等待时间。
  9. CDN托管与缓存策略
    结合Webpack的publicPath配置,将静态资源上传至CDN,利用CDN加速资源加载,同时通过HTTP缓存头设置,合理利用浏览器缓存。
  10. 图片优化
    使用url-loader、file-loader等加载器对图片进行压缩,并根据需要转换为更紧凑的格式(如将PNG转为WebP),减小图片资源大小。
  11. Gzip压缩
    配合服务器开启Gzip压缩,Webpack在打包时可以生成Gzip压缩后的资源,传输时减小带宽消耗。

通过以上优化措施,Webpack帮助前端项目在开发和部署阶段都能实现更好的性能表现。

22. gulp和webpack的异同

Webpack 和 Gulp 之间本质区别在于它们的设计目标和核心功能的不同:

  1. Webpack
  • 是一个模块打包器,其主要关注点在于解决前端模块化的方案,以及资源的管理和打包。Webpack 可以理解项目的内部依赖结构,并通过 loader 转换不同的资源类型(如 JavaScript、CSS、图片等),再通过 plugin 进一步处理这些资源,如捆绑、压缩、分割代码块等。
  • Webpack 支持“一切皆模块”的概念,允许开发者以模块化的方式组织项目,并能处理模块间的动态引用和按需加载。
  • Webpack 在构建过程中直接提供了模块打包、转换、优化的能力,具备高度集成的特性。

·  Gulp

  • 是一个流式构建工具,它更加强调的是前端开发流程的自动化,通过定义任务(task)来执行一系列构建步骤,比如文件压缩、合并、预处理、测试、部署等。
  • Gulp 的核心优势在于其基于流(stream)的高效文件处理机制,能够有效减少内存占用并提高构建速度。
  • Gulp 并不直接处理模块打包,而是通过集成各种插件来实现各种构建任务,它更适合于解决构建过程中的工作流程问题,而不涉及模块间的依赖分析和管理。

总结来说,Webpack 更专注于前端资源的模块化打包和优化,是一种底层构建解决方案;而 Gulp 则是一个灵活的自动化构建工具,用于创建和自动化前端工作流程,通常用来配合其他插件或工具共同完成构建任务。在现代前端工程实践中,由于 Webpack 的强大功能和模块化能力,很多原本由 Gulp 完成的任务现在可以直接通过 Webpack 的配置来实现,使得单一工具即可满足大部分构建需求。然而,两者并不互斥,可以根据项目的实际情况结合使用。

23. webpck 和 gulp 场景Gulp

和 Webpack 都是前端开发工具,但它们在使用场景上的侧重点不同:

Gulp:

  1. 任务自动化
    Gulp 专注于构建任务的自动化,它可以用于多种任务,如文件拷贝、压缩、合并、预处理、图片优化、代码质量检查、单元测试等。Gulp 的强项在于其基于流(Stream)的文件处理机制,可以高效地处理和转换文件内容。
  2. 工作流构建
    Gulp 适合用于构建复杂的前端工作流程,比如先对 SCSS 文件进行编译,然后压缩 CSS,接着压缩 JS 文件,最后将它们合并并部署到服务器。你可以通过编写自定义的任务和管道(pipeline)来构建适合自己项目的完整构建流程。
  3. 模块化程度较低
    Gulp 不直接处理模块化问题,它更适合于处理已有模块化结构(如 CommonJS、AMD 等)的前端项目,或者不那么注重模块化的项目。

Webpack:

  1. 模块打包
    Webpack 的核心功能是模块打包,它能够处理 JavaScript 模块间的依赖关系,并将其转换、打包为可在浏览器中运行的代码。Webpack 支持多种模块规范(如 ES6 modules),并可以通过 loader 处理各种类型的资源(如 CSS、图片、字体等)。
  2. 代码分割与懒加载
    Webpack 提供了强大的代码分割和动态加载功能,可以根据模块间的依赖关系生成多个分块(chunk),利于网页性能优化和按需加载。
  3. 资源处理和优化
    Webpack 内置了资源处理功能,可以压缩 JavaScript、CSS,甚至可以将图片转换为 base64 数据内联到代码中。通过配置 plugins,Webpack 可以实现更深度的优化,比如 Tree Shaking(去除未使用的代码)和 Scope Hoisting(提升代码执行效率)。

总结来说,Gulp 更像是一个通用的构建工具,擅长整合多种构建任务,而 Webpack 则是一个高度集成的模块打包工具,尤其适合现代化的前端模块化项目,它可以更好地处理模块间的依赖关系并进行优化。在实际开发中,两者经常结合使用,Gulp 可以负责项目中 Webpack 之外的其他构建任务,而 Webpack 负责核心的模块打包和资源处理工作。随着 Webpack 功能的不断完善和生态的壮大,许多原本由 Gulp 处理的任务现在也可以直接通过 Webpack 配置来完成。

24. webpack 的项目改用 gulp 会遇到哪些问题

如果一个原本使用 webpack 的前端项目改为使用 Gulp,可能会遇到以下几类问题:

  1. 任务自动化差异
  • Webpack 是一个强大的模块打包工具,它可以处理模块导入、代码分割、转译、压缩、热更新等功能,而 Gulp 更侧重于构建流程自动化,不直接提供模块打包的功能。
  • 如果项目原先依赖了 webpack 的模块打包机制,那么在迁移到 Gulp 时,你需要找到相应的 Gulp 插件或者自行编写脚本来实现这些功能,比如 Babel 编译、LESS/SASS 转 CSS、图片压缩、文件合并等。

·  配置复杂性

  • Webpack 配置集中在一个或多个配置文件中,它能精细地控制模块加载规则、输出路径、公共路径、插件应用等。
  • 而 Gulp 是基于任务的构建工具,它的配置相对分散在各个 task 中,因此可能需要更多手动配置去处理相似的构建细节

·  静态资源处理

  • Webpack 通过 loader 可以方便地处理各种类型的静态资源,并且能够自动添加 hash 或者版本号到文件名以实现缓存 busting。
  • 在 Gulp 中,虽然也有类似的插件可以完成类似的任务,但可能需要更细致的配置来整合不同的流处理操作。

·  动态导入与按需加载

  • Webpack 支持动态导入(import())及代码分割特性,这有助于优化首屏加载速度。
  • 在 Gulp 中实现同样的效果,可能需要借助 Rollup、Browserify 等其它打包工具,或者配合 Gulp 通过更复杂的逻辑实现按需加载

·  热更新与开发者体验

  • Webpack Dev Server 提供了实时编译、热模块替换等提升开发效率的功能。
  • 使用 Gulp 进行开发时,虽然也可以通过监听文件变化重新构建,但实现同等程度的热更新体验通常需要集成 BrowserSync 等额外工具,并且可能没有 Webpack 的热模块替换那么高效

·  项目结构适应

  • 如果项目的组织结构和构建流程是围绕着 Webpack 的特点设计的,那么转换到 Gulp 可能需要重构部分项目结构以适应 Gulp 的工作流。

25. webpack 和 vite 的优缺点对比

Webpack 和 Vite 的优缺点对比:

Webpack 优点:

  1. 成熟度与生态:Webpack 已经是非常成熟且广泛应用的构建工具,拥有极其丰富的插件和 loader 生态系统,几乎可以处理任何类型的前端资源,适用于各种复杂的项目需求。
  2. 高度自定义:Webpack 提供高度灵活的配置选项,允许开发者精细控制打包流程,包括代码分割、模块加载、资源优化等方面。
  3. 跨平台支持:Webpack 支持多种模块格式(CommonJS、AMD、ES modules 等),并且可以很好地处理旧版浏览器的兼容问题。
  4. 资源管理和优化:Webpack 可以自动处理静态资源的引用,并通过 Tree-shaking、Scope Hoisting 等技术进行代码优化。

Webpack 缺点:

  1. 启动速度相比于 Vite,Webpack 的启动速度较慢,尤其在大型项目中,全量编译和热更新等待时间较长。
  2. 开发体验:开发环境下的热更新可能不够即时,因为它往往涉及到全量或部分重新编译。
  3. 配置复杂度:由于功能强大,Webpack 的配置可能较为复杂,对新手不太友好。

Vite 优点:

  1. 快速启动与热更新:Vite 在开发环境中利用 ES module 的原生支持,无需预先编译全部代码,按需编译,大大提升了启动和热更新的速度。
  2. 轻量级开发体验:Vite 基于 esbuild 预构建依赖,极大地加快了开发阶段的构建速度
  3. 内置 Vue.js 支持:由 Vue.js 团队开发,对 Vue.js 应用提供了很好的开箱即用支持。
  4. 现代化架构:Vite 更加契合现代浏览器对 ES modules 的支持,提供了更好的开发体验。

Vite 缺点:

  1. 生态相对较小:相较于 Webpack,Vite 的生态系统还在发展中,插件和 loader 的种类和成熟度有待提升。
  2. 生产环境构建虽然开发阶段快速,但在生产环境构建时,Vite 依赖 Rollup 进行打包,可能在某些场景下(如 CSS 代码分割、CommonJS 模块处理等)不如 Webpack 灵活和全面
  3. 浏览器兼容性Vite 需要浏览器支持 ES modules,对于老旧浏览器可能需要额外的polyfill或服务端支持。
  4. 稳定性和成熟度:作为一个相对较新的工具,Vite 在一些边缘情况下的表现和稳定性可能不如 Webpack 成熟。

Webpack 是目前最主流和全能的前端构建工具,特别适合大型、复杂的项目和需要深度定制的情况。而 Vite 更关注提升开发者的生产力和现代前端项目的快速迭代,尤其在 Vue.js 项目中表现出色。选择哪一个取决于项目的具体情况、团队对工具的熟悉程度以及对构建速度、灵活性和生态完整性的权衡。

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值