2023年最新的前端面试收集(2)

webpack熟悉吗?webpack打包流程是什么?

webpack打包流程

  1. 解析配置文件: 读取并解析配置文件,并根据配置生成一个Compiler对象。
  2. 读取入口文件:根据配置中的入口文件,读取这些文件及其依赖的模块,并将它们组成一个依赖关系图。
  3. 解析模块依赖:根据模块之间的关系,递归解析它们的依赖,直到所有依赖都被解析完
  4. 加载模块:根据路径,使用对应的loader加载对应的源代码,并将其转换成Webpack可处理的形式
  5. 转换代码:根据配置中的插件,对加载的模块金雄一系列的转换操作,比如压缩、合并、优化等
  6. 生成代码,将所有模块转换后的代码合成一个或者多个文件,并输出到相应的输出目录中。

Webpack声明周期

  1. 进入编译前:此时会初始化Compiler对象
  2. 开始编译前:此时会读取入口文件和依赖,并创建依赖关系图
  3. 开始编译:此时会开始编译入口文件和依赖的模块,并生成输出文件
  4. 生成文件前:此时可以在插件中处理生成的输出文件
  5. 完成打包:此时可以在插件中进行一些清理工作

你在公司制定前端规范的时候,都有哪些内容?

  1. 命名风格
    • CSS命名规范
      1. 选择器命名一律用小写字母,避免使用拼音命名
      2. 选择器统一采用横线很分隔,禁止使用下换线,分隔符尽量不要超过4个
    • JS命名规范
      1. 代码中命名不能使用 、 , 不能以 、_,不能以 不能以、_以及数字结尾
      2. 代码中命名禁止使用拼音、拼音+英文
      3. 尽量使用驼峰命名法
      4. 常量统一使用大写,单词之间用下换线 _ 隔开
      5. TS接口名统一用大写字母 I 作为前缀
      6. TS枚举类名称以及其属性名统一使用大写,单词之间用下换线 _ 隔开
      7. 函数名、方法名、属性名、变量名规范
        • 获取单个对象、接口数据,使用get作为前缀
        • 获取多个对象使用list作为前缀
        • 获取数组使用List作为后缀
        • 保存、添加使用save、add作为前缀
        • 编辑、更新、删除,移除使用edit、update、delete、remove作为前缀
    • 代码格式规范
      1. CSS代码格式
        • 一个样式独占一行,使用tab或者4个空格
        • 选择器单独一行,与大括号之间空格,样式属性值与冒号之间空格
        • 嵌套层级不能过多,最多不要超过4层
      2. JS代码格式
        • 尽量使用const和let声明变量
        • 大括号使用规范,注意前后空格和换行
      3. 引号使用
        • HTML代码中class、id或其他属性都采用双引号
        • JS中字符串使用单引号
        • 注意使用 === 、== !=、!== 的使用
        • 采用4个空格缩进
        • 三元表达式在一条表达式中最多出现两次
    • 对象处理
      1. 不要修改标准JS对象的原型
      2. 不要通过原型向对象添加新的属性或方法,通过封装导出的方式引用
      3. 使用对象字面量创建
      4. 使用展开运算符…复制或者合并数组或对象
      5. 使用解构获取对象的属性值
      6. 使用数组对象的方法前,如果不确定,则需要先进行类型判断
      7. 使用JSON.parse前,需要对变量做类型及JSON格式检查
      8. 使用定时器后,一定要在销毁组件是,进行销毁。
    • 注释规约
      1. 如果用只说明用途或功能,单行注释,如果要对参数进行解释,多行注释
      2. 修改代码的同时,注释也要进行相应的修改,尤其是参数或返回值

    小程序跟H5的区别是什么?

    1. 运行环境的不同
    • 小程序: 小程序的运行环境是基于浏览器内核完全重构的一个内置解析器,针对性做了优化,配合自己定义的开发语言标准,提升了小程序的性能。 脚本内无法使用浏览器中常用的window对象和document对象,从源头上避免了DOM的内存泄漏。
    • H5: 无法控制开发人员对DOM的操作,容易出现内存泄漏,在SPA单页应用还存在页面加载慢的问题。
    1. 开发成本不同
    • 小程序: 小程序规范了开发标准,则简单得多。前端常见的HTML、CSS变成了微信自定义的WXML、WXSS,这样避免了框架五花八门,加大了项目接手人员上手维护难度。支付宝小程序可能是AXML、ACSS;头条小程序可能是TTML、TTSS等。
    • H5: 涉及开发工具(vscode、Atom等)、前端框架(Angular、react等)、模块管理工具(Webpack 、Browserify 等)、任务管理工具(Grunt、Gulp等),还有UI库选择、接口调用工具(ajax、Fetch Api等)、浏览器兼容性
    1. 获取系统权限的不同
    • 小程序: 更多的系统权限,比如网络通信状态、数据缓存能力等,这些系统级权限都可以和小程序无缝衔接。
    • H5: 获取系统权限是大多H5被诟病的地方,这也是H5的大多应用场景被定位在业务逻辑简单、功能单一的原因。
    1. 运行流畅度的不同
    • 小程序: 小程序,它的代码直接在APP上运行,通过浏览器双线程UI渲染和业务逻辑分离等技术,因此,在微信中使用小程序,才会比H5流畅很多,首次打开需要几秒的加载时间外,小程序各个页面的切换、跳转等体验已经媲美原生App,有着同样的柔丝般顺滑的效果。
    • H5: 实际上是打开一个网页,而网页需要在浏览器中渲染。所以加载这一过程,会给人明显的「卡顿」感觉,面对复杂的业务逻辑或者丰富的页面交互时尤为明显。
    1. 运维方式不同
    • 小程序: 小程序支持灰度发布、AB测试,在出现异常情况下可以实时在管理界面上操作回退。
    • H5: H5如果出现异常问题,需要运维人员在生产环境重新部署回滚系统,要动到生产环境的系统部署,有较大的风险。
    1. 用户体验不同
    • 小程序: 由于微信的关系,小程序近几年大火,用户的接受度和认可度都非常高,而且小程序的体验确实要比h5好很多,小程序下载到本地可以缓存,因此用户体验也更平滑,更关键的是,用户对小程序的收藏等操作会更自然,体验更好,不用担心收藏后的东西不好找等情况。
    • H5: H5传统上给人感觉加载始终比较卡,而且H5一旦点击退出去后经常会比较难找到对应入口,特别是链接深度比较深,用户在里面一直点击后,用户一旦退出也很难找到自己关注的东西。

vue3中做了哪些优化?

  1. 源码优化

    • 更好的代码管理方式,代码库中各功能区分得更加细致,责职分工更加明确
    • package 是可以独立于 Vue.js 使用的,例如 reactivity 响应式库能力,可以单独依赖这个响应式库而不用依赖整个 Vue.js 减少了引用包的体积大小,在 Vue.js 2.x 是做不到这一点的
    • 使用了类型语言 TypeScript 重构项目
  2. 性能优化

    • 移除了一些冷门的内置方法,引入 tree-shaking 的技术(在打包中只会引入使用了的代码,从而减少了打包后代码的体积)
  3. 数据劫持优化

    • 数据响应式处理放弃使用 Object.defineProperty,改用 new Proxy 监听整一个对象。原因是 Object.defineProperty 不管是否遇到有嵌套层级的对象,都需要无脑递归对象,逐层监听对象,对性能损耗过大。而采用 Proxy 后,只有在真正遇到有嵌套层级的对象的时候,才会在 getter 的时候逐层递归,对每一个对象进行监听处理,在很大程度上提升了性能。
  4. 编译优化

    • petch 函数优化;通过编译阶段对静态模版的分析,编译生成了 Block tree

      • Block tree 是一个将模板基于动态节点指令切割的嵌套区块,每个区块内部的节点结构是固定的,每个区块只需要以一个 Array 来追踪自身包含的动态节点
      • 借助 Block tree,Vue.js 将 vnode 更新性能由与模板整体大小相关提升为与动态内容的数量相关
    • 在编译阶段还包含了对 Slot 的编译优化、事件侦听函数的缓存优化,并且在运行时重写了 diff 算法

  5. 语法APi优化:composition api

    • Oprion API:当组件小的时候,这种分类方式一目了然;但是在大型项目中,一个组件可能有多个逻辑关注点,每一个关注点都有自己的 Options,当需要修改某一个逻辑关注点时,就需要在单个文件中不断上下切换和寻找
    • Composition API:将某个逻辑关注点相关的代码全部放在一个函数里,这样当需要修改一个功能时,就不再需要在文件中翻来覆去

vue2和vue3的响应式有什么区别?

Vue3和 Vue2 对比,Vue2 的响应式存在很多的问题

  • 初始化时需要遍历对象所有 key,如果对象层次较深,性能不好
  • 通知更新过程需要维护大量 dep 实例和 watcher 实例,额外占用内存较多
  • 无法监听到数组元素的变化,只能通过劫持重写了几个数组方法
  • 动态新增,删除对象属性无法拦截,只能用特定 set/delete API 代替
  • 不支持 Map、Set 等数据结构

Vue2 的响应式原理是怎么样的?

  • Vue2 的对象数据是通过 Object.defineProperty 对每个属性进行监听,当对属性进行读取的时候,就会触发 getter,对属性进行设置的时候,就会触发 setter
```javascript
	/**
	* 这里的函数 defineReactive 用来对 Object.defineProperty 进行封装。
	**/
	function defineReactive(data, key, val) {
	   // 依赖存储的地方
	   const dep = new Dep()
	   Object.defineProperty(data, key, {
	       enumerable: true,
	       configurable: true,
	       get: function () {
	           // 读取数据的时触发,在 getter 中收集依赖
	           dep.depend()
	           // 返回结果
	           return val
	       },
	       set: function(newVal) {
	       	   // 修改数据时触发,更新数据,并通知dep,更新储存,触发watcher更新
	           val = newVal
	           // 在 setter 中触发依赖
	           dep.notify()
	       }
	   }) 
	}
```
1. 在Watcher里面进行属性读取,读取的时候会把自己设置到一个全局变量中
2. 在Watcher中读取属性会触发getter,在getter里面进行依赖收集,依赖储存的地方叫Dep,在Dep里面就可以把全局变量中的依赖进行收集,,收集完毕就会把全局依赖变量置空,将来数据发生变化的时候,就去Dep中把相关的Watcher拿出来执行一遍
	// Watcher就是所谓的依赖
	class Watcher {
	    constructor(vm, exp, cb) {
	        this.vm = vm
	        this.getter = exp
	        this.cb = cb
	        this.value = this.get()
	    }
	
	    get() {
	    	// 读取时,依赖收集,并储存在Dep中
	        Dep.target = this
	        let value = this.getter.call(this.vm, this.vm)
	        // 收集完毕,置空全局依赖变量
	        Dep.target = undefined
	        // 将最新的结果返回
	        return value
	    }
	
	    update() {
	    	// 数据变化,重走一遍watcher,触发get
	        const oldValue = this.value
	        this.value = this.get()
	        this.cb.call(this.vm, this.value, oldValue)
	    }
	}
    1. 总结:
    • Object.defineProperty监听对象的每一个属性,当读取数据时会触发getter,修改数据时会触发setter,
    • 在改变数据setter时,调用dep中的notify方法,notify会遍历依赖后调用watcher依赖器中update方法更新,update中会调用get方法重新收集依赖,将结果在dep中储存,并将结果返回。
    • Dep是依赖的储存器,负责添加、删除相关的依赖和通知相关依赖进行相关的操作
    • Watcher是依赖器,只有watcher中的get触发才会收集,然后调用Dep进行添加、删除依赖操作
    • 由于Object.defineProperty无法监听对象的变化,所以Vue2中设置了一个Observer类来管理对象的响应式依赖,同时会递归检测对象中子数据的变化

为什么 Vue2 新增响应式属性要通过额外的 API,$set?

  • 这是因为Object.defineProperty只会对属性进行监测,而不能对对象镜像监测,为了可以监测对象Vue2创建了一个Observer类。

  • Observer类的作用就是把一个对象全部转换成响应式对象,包括子属性,当对象新增或者删除属性的是否负责同时对应的Watcher进行更新操作

    // $set操作
    function set(target, key, val) {
        const ob = target.__ob__
        // 响应式赋值
        defineReactive(ob.value, key, val)
        // 通知dep,等同于修改数据,触发setter操作
        ob.dep.notify()
        return val
    }
    

Object.defineProperty 真的不能监听数组的变化吗?

  • Object.defineProperty是可以监听数组的变化,但是它是通过下标,实际开发基本很少这样处理数据,更多的是通过内置方法,push、pop、shift、unshift等,这些方法是监听不到的,所以放弃了Object.defineProperty对数组进行监听,采用通过对数组原型上的方法进行重写监听,本质还是使用原生Array原型上的方法去操作数组,只不过是做了一些逻辑处理数据。

    // 拦截器其实就是一个和 Array.prototype 一样的对象。
    const arrayProto = Array.prototype
    const arrayMethods = Object.create(arrayProto)
    ;[
        'push',
        'pop',
        'shift',
        'unshift',
        'splice',
        'sort',
        'reverse'
    ].forEach(function (method) {
        // 缓存原始方法
        const original = arrayProto[method]
        Object.defineProperty(arrayMethods, method, {
            value: function mutator(...args) {
                // 最终还是使用原生的 Array 原型方法去操作数组
                return original.apply(this, args)
            },
            eumerable: false,
            writable: false,
            configurable: true
        })
    })
    
    • 由于Vue2放弃了Object.defineProperty对数组进行监听的方法,所以通过下标操作数组是无法实现响应式操作,如:this.list.length = 0

Vue3 的响应式原理是怎么样的?

  1. Vue3是通过Proxy对数据事项getter/setter代理,从而实现响应式数据.

  2. 在副作用函数中读取响应式数据的时候,就会触发Proxy的getter

  3. 在getter里面把当前副作用函数保存起来,将来对应响应式数据发生变化时,把之前保存起来的副作用函数取出来执行。

    // 使用一个全局变量存储被注册的副作用函数
    let activeEffect
    // 注册副作用函数
    function effect(fn) {
        activeEffect = fn
        fn()
    }
    const obj = new Proxy(data, {
        // getter 拦截读取操作
        get(target, key) {
            // 将副作用函数 activeEffect 添加到存储副作用函数的全局变量 targetMap 中
            track(target, key)
            // 返回读取的属性值
            return Reflect.get(target, key)
        },
        // setter 拦截设置操作
        set(target, key, val) {
            // 设置属性值
            const result = Reflect.set(target, key, val)
            // 把之前存储的副作用函数取出来并执行
            trigger(target, key)
            return result
        }
    })
    // 存储副作用函数的全局变量
    const targetMap = new WeakMap()
    // 在 getter 拦截器内追踪依赖的变化
    function track(target, key) {
        // 没有 activeEffect,直接返回
        if(!activeEffect) return
        // 根据 target 从全局变量 targetMap 中获取 depsMap
        let depsMap = targetMap.get(target)
        if(!depsMap) {
           // 如果 depsMap 不存,那么需要新建一个 Map 并且与 target 关联
           depsMap = new Map()
           targetMap.set(target, depsMap)
        }
        // 再根据 key 从 depsMap 中取得 deps, deps 里面存储的是所有与当前 key 相关联的副作用函数
        let deps = depsMap.get(key)
        if(!deps) {
           // 如果 deps 不存在,那么需要新建一个 Set 并且与 key 关联
           deps = new Set()
           depsMap.set(key, deps)
        }
        // 将当前的活动的副作用函数保存起来
        deps.add(activeEffect)
    }
    // 在 setter 拦截器中触发相关依赖
    function trgger(target, key) {
        // 根据 target 从全局变量 targetMap 中取出 depsMap
        const depsMap = targetMap.get(target)
        if(!depsMap) return
        // 根据 key 取出相关联的所有副作用函数
        const effects = depsMap.get(key)
        // 执行所有的副作用函数
        effects && effects.forEach(fn => fn())
    }
    
    
  • Vue3 中依赖收集的规则,首先把响应式对象作为 key,一个 Map 的实例做为值方式存储在一个 WeakMap 的实例中,其中这个 Map 的实例又是以响应式对象的 key 作为 key, 值为一个 Set 的实例为值。而且这个 Set 的实例中存储的则是跟那个响应式对象 key 相关的副作用函数。
  • 副作用函数使用Set类型,是因为Set类型能自动去除重复内容
  • 对简单类型数据,Vue3通过对其做了一层包裹的方式来实现对原始值变成响应式数据的,因为简单类型数据是按值传递,如函数中形参是简单类型数据,但两者没有引用关系,改变形参无法影响到实参,无法实现响应式。
  • 因此 ref 本质是一个实例化的包裹对象,来处理对简单类型数据的代理,使用一层对象为包裹,将简单类型数据放对象里面作为value,监听对象,即可间接响应式对简单类型数据的响应式方案。

Vue3 中是怎么监测数组的变化?

  • vue2是不可以通过下标对响应式数组进行设置和读取,但Vue3是可以的
  • vue3中也需要对数组原型上方法进行重写,数组响应式对象使用includes、indexOf、lastIndexOf方法重写,因为它们内部的 this 指向的是代理对象,并且在获取数组元素时得到的值要也是代理对象,所以当使用原始值去数组响应式对象中查找的时候,如果不进行特别的处理,是查找不到的,所以我们需要对上述的数组方法进行重写才能解决这个问题。

Vue2和Vue3的总结

  • Vue2
    • 是通过 Object.defineProperty 将对象的属性转换成 getter/setter 的形式来进行监听它们的变化,当读取属性值的时候会触发 getter 进行依赖收集,当设置对象属性值的时候会触发 setter 进行向相关依赖发送通知,从而进行相关操作
    • 由于 Object.defineProperty 只对属性 key 进行监听,无法对引用对象进行监听,所以在 Vue2 中创建一个了 Observer 类对整个对象的依赖进行管理,当对响应式对象进行新增或者删除则由响应式对象中的 dep 通知相关依赖进行更新操作。
    • Object.defineProperty 也可以实现对数组的监听的,但因为性能的原因 Vue2 放弃了这种方案,改由重写数组原型对象上的 7 个能操作数组内容的变更的方法,从而实现对数组的响应式监听。
  • Vue3
    • Vue3 则是通过 Proxy 对数据实现 getter/setter 代理,从而实现响应式数据,然后在副作用函数中读取响应式数据的时候,就会触发 Proxy 的 getter,在 getter 里面把对当前的副作用函数保存起来,将来对应响应式数据发生更改的话,则把之前保存起来的副作用函数取出来执行。
    • Vue3 对数组实现代理时,用于代理普通对象的大部分代码可以继续使用,但由于对数组的操作与对普通对象的操作存在很多的不同,那么也需要对这些不同的操作实现正确的响应式联系或触发响应。这就需要对数组原型上的一些方法进行重写。
      • 比如通过索引为数组设置新的元素,可能会隐式地修改数组的 length 属性的值。同时如果修改数组的 length 属性的值,也可能会间接影响数组中的已有元素。另外用户通过 includes、indexOf 以及 lastIndexOf 等对数组元素进行查找时,可能是使用代理对象进行查找,也有可能使用原始值进行查找,所以我们就需要重写这些数组的查找方法,从而实现用户的需求。原理很简单,当用户使用这些方法查找元素时,先去响应式对象中查找,如果没找到,则再去原始值中查找。
      • 另外如果使用 push、pop、shift、unshift、splice 这些方法操作响应式数组对象时会间接读取和设置数组的 length 属性,所以我们也需要对这些数组的原型方法进行重新,让当使用这些方法间接读取 length 属性时禁止进行依赖追踪,这样就可以断开 length 属性与副作用函数之间的响应式联系了。

vue3中的watchEffect和watch

在Vue的Composition API中,watch和watchEffect都是用于监听响应式数据变化的函数

  • watch 用于监听一个或者多个响应式数据或计算属性,并在它们改变时执行一个函数
    • immediate 是否立即执行
    • deep 是否深度监听,针对对象和数组
    • flush 控制回调何时执行(pre、post、 sync)
  • watchEffect 用于立即执行函数,并监听该函数内部所有引用的响应数据或计算属性

主要区别

  • 自动监听依赖 与 显示声明
    • watchEffect是自动监听函数内所有引用的响应式,而watch需要指明监听的引用数据
  • 立即执行
    • watchEffect是立即执行一次,而watch需要设置immediate选项
  • 旧值与新值
    • watch回调提供旧值和新值,而watchEffect不提供回调参数
  • 多目标监听
  • watch 可以观察多个目标,但watchEffect 监听函数内的所有响应式引用

使用场景

  • watch
    • 需要使用旧值和新值
    • 需要基于条件监听处理逻辑
    • 需要可控配置
  • watchEffect
    • 需要多个依赖响应式来触发影响同一个目标的逻辑
    • 只关心最新的值

interface和type的区别是什么?

类型别名 type

type不仅可以用来表示基本类型,还可以用来表示对象类型、联合类型、元组和交集

type userName = string;
// 联合类型
type userId = string | number;
// 元组
type Data = [number, string];
type Person = {
	name: string;
	age: number
}

接口 interface

interface 仅限描述对象类型

	interface Person {
		name: string;
		age: number;
	}
  1. 都可以描述对象和函数,但语法不同
	// type
	type Ipoint = {
		x: number;
		y: number;
	}
	type SetPoint = (x: number, y: number) => void;
	
	// interface
	interface IPoint {
		x: number;
		y: number;
	}
	interface SetPoint {
		(x: number, y: number): void;
	}
  1. 两者都可以被继承,混合继承
	interface Person {
		name: string;
	}
	interface Student extends Person { id: number; };
	
	type Animal = {
		name: string;
	}
	type Cart = Animal & { behavior: leg; };
	
	// 混合继承
	type Student1 = Person & { id: number; };
	interface Cart1 extends Animal {
		say: string;
	}
  1. 声明合并
  • interface 同名声明合并叠加
  • type 不可能同名,会报错

vite、webpack、roolup的区别是什么

Webpack介绍

  1. 热更新方面:Webpack支持HMR,当Webpack需要全部冲洗编译并更新,效率较低。
  2. tree-shaking:webpack2开始支持,webpack5支持的更好
  3. 分包方面:Webpack支持代码切割
  4. ESM打包:现在webpack支持es6module输出

Vite介绍

  1. 两部分组成
    • 一个开发服务器,它基于原生ES模块提供了丰富的内建功能
    • 一套构建指令,它是用Rollup打包,支持预配置,可以输出用于生产环境的优化过的静态资源
  2. 主要特点
    • 快速的冷启动:直接开启开发服务器,不需要进行打包操作,不需要分类模块依赖和编译,因此启动速度非常快
    • 即时的模块热更新
    • 真正的按需编译:利用现代浏览器支持ES Module的特性,当浏览器请求某个模块的时候,根据需要对模块的内容进行编译,加载请求,这种方式大大缩短了编译时间。
  3. 优点
    1. vite热更新,实现按需加载,按模块加载,速度快
      • vite利用HTTP头来加速整个页面的重新加载,源代码模块的请求会根据304进行协商缓存,依赖模块请求这是通过Cache-Control进行强缓存,因此一旦被缓存它们将不需要再次请求
      • 热更新原理:在热模块HMR方面,当修改一个模块的时候,仅让浏览器重新请求该模块即可,无须像webpack那样需要把该模块的相关依赖模块全部编译一次,效率更高。
    2. vite在生产环境通过Rollup进行打包(特点:打包体积小),生成esm模块包(特点:快)
      • vite在开发环境时,基于浏览器支持esm,让浏览器解析模块,然后服务器按需编译返回。同时基于esbuild(go)进行预构建打包不常变动的第三包,并用进行缓存。(缓存+快)
      • Vite 使用 esbuild 预构建依赖。Esbuild 使用 Go 编写,所以比以 Node.js 编写的打包器预构建依赖快 10-100 倍。
  4. 缺点
    • 生态:生态不如webpack,wepback在于loader和plugin非常丰富
    • prod环境的构建:目前用的Rollup,原因在于esbuild对于css和代码分割不是很友好
    • 还没有被大规模使用,很多问题或者诉求没有真正暴露出来

Rollup介绍

  • 优点:

    1. Rollup 是一款 ES Modules 打包器,从作用上来看,Rollup 与 Webpack 非常类似。不过相比于 Webpack,Rollup要小巧的多,打包生成的文件更小。(识别commonJs需要插件)
    2. 热更新:Rollup不支持HMR,在对js以外的模块的支持上不如webpack,但是如果是打包纯js库例如react,前期的vue的话,使用rollup是很合适的,打包的产物比较干净,没有webpack那么多工具函数
    3. Rollup 的插件机制设计得相对更干净简洁,单个模块的 resolve / load / transform 跟打包环节完全解耦,所以 Vite 才能在开发时模拟 Rollup 的插件机制,并且兼容大部分 Rollup 插件
    4. rollup原生支持tree-shaking
  • 缺点:

    1. 加载其他类型的资源文件或者支持导入 CommonJS 模块,又或是编译 ES 新特性,这些额外的需求 Rollup需要使用插件去完成
    2. rollup并不适合开发应用使用,因为需要使用第三方模块,而目前第三方模块大多数使用CommonJs方式导出成员,并且rollup不支持HMR,使开发效率降低

结论:

Rollup更适合打包库,webpack更适合打包项目应用,vite基于rollup实现了热更新也适合打包项目。

待续

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值