前端面试题

1.深浅拷贝的区别

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存(分支)。
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支)

2.事件循环 Event Loop

js是单线程的,一个任务执行完成之后才能执行另一个任务。

首先要知道运行栈,任务队列,事件循环

同步任务放到 运行栈中

异步任务放到 异步队列里

事件循环就是检测 任务队列中是否有异步任务。有就执行,没有就继续循环
微任务

process.nextTick
promise
Object.observe
MutationObserver
宏任务

script
setTimeout
setInterval
setImmediate
I/O
UI rendering
宏任务中包括了 script ,浏览器会先执行一个宏任务,接下来有异步代码的话就先执行微任务

3.防抖、节流

防抖:用户触发事件过于频繁,只需要最后一次事件的操作

节流 :规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效

4.Async/Await 如何通过同步的方式实现异步

Async/Await就是一个自执行的generate函数。利用generate函数的特性把异步的代码写成“同步”的形式,第一个请求的返回值作为后面一个请求的参数,其中每一个参数都是一个promise对象。

5.Vue 响应式原理

整体思路是数据劫持+观察者模式

6.Vue nextTick 原理

nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法

7 谈谈你对重构的理解

也就是说是在不改变UI的情况下,对网站进行优化, 在扩展的同时保持一致的UI
对于传统的网站来说重构通常是:
表格(table)布局改为DIV+CSS
使网站前端兼容于现代浏览器(针对于不合规范的CSS、如对IE6有效的)
对于移动平台的优化
针对于SEO进行优化

8.你觉得前端工程的价值体现在哪

为简化用户使用提供技术支持(交互部分)
为多个浏览器兼容性提供支持
为提高用户浏览速度(浏览器性能)提供支持
为跨平台或者其他基于webkit或其他渲染引擎的应用提供支持
为展示数据提供支持(数据接口

9.平时如何管理你的项目

先期团队必须确定好全局样式(globe.css),编码模式(utf-8) 等;
编写习惯必须一致(例如都是采用继承式的写法,单样式都写成一行);
标注样式编写人,各模块都及时标注(标注关键样式调用的地方);
页面进行标注(例如 页面 模块 开始和结束);
CSS跟HTML 分文件夹并行存放,命名都得统一(例如style.css);
JS 分文件夹存放 命名以该JS功能为准的英文翻译。
图片采用整合的 images.png png8 格式文件使用 - 尽量整合在一起使用方便将来的管理
规定全局样式、公共脚本
严格要求代码注释(html/js/css)
严格要求静态资源存放路径
Git 提交必须填写说明

10.组件封装

目的:为了重用,提高开发效率和代码质量 注意:低耦合,单一职责,可复用性,可维护性 常用操作

分析布局
初步开发
化繁为简
组件抽象

11.typeof 于 instanceof 区别

typeof 对于基本类型,除了 null都可以显示正确的类型
typeof 对于对象,除了函数都会显示 object
instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 iprototype

12.介绍一下 webpack 的构建流程

解析入口文件:Webpack 从入口文件开始分析,根据入口文件中的依赖关系来确定需要打包的模块。入口文件可以是一个或多个,Webpack 会自动处理它们之间的依赖关系。

加载模块:Webpack 根据模块的路径和类型,使用合适的 loader 来加载模块。例如,如果模块是一个 CSS 文件,Webpack 会使用 CSS loader 来加载它。

转换模块:一旦模块被加载进来,Webpack 会根据配置中的规则(rules)来对模块进行转换。这些规则可以将模块转换成 JavaScript 可以识别的代码,也可以对模块进行其他处理。

解析依赖:Webpack 在加载每个模块时,会递归地查找该模块依赖的其他模块,并且重复以上步骤,直到所有依赖的模块都被加载进来。

打包输出:最后,Webpack 将所有的模块打包成一个或多个包,并将它们输出到指定的目录中。在这个过程中,Webpack 还会进行代码压缩、模块合并等优化操作,以便减小文件大小、提高加载速度等。

13.解释几个 webpack 中的术语

module:指在模块化编程中我们把应用程序分割成的独立功能的代码模块。
chunk:"指的是一个由模块组成的代码块,可以是一个单独的文件或一组文件,它们被Webpack根据特定的逻辑划分出来。
Webpack中的chunk可以分为两种类型:entry chunk和async chunk
Entry chunk是Webpack中的入口点,即webpack.config.js文件中的entry配置项所定义的入口文件。当Webpack开始打包时,它会先生成一个entry chunk,其中包含入口文件及其依赖的所有模块。
Async chunk是在应用程序运行过程中,根据需要动态加载的代码块,可以通过import()语句或webpack的require.ensure()方法来实现。这些代码块会被Webpack自动划分到不同的chunk中,以实现按需加载。
chunk group:Chunk Group(代码块组)是一种将相关的chunk组合在一起的机制,通常用于优化代码块的加载顺序,以便最大限度地减少浏览器需要下载的资源。通过Webpack的配置文件中的optimization.splitChunks.chunks选项来配置哪些代码块被包含在同一个Chunk Group中。一个常见的使用场景是将第三方库(如React、Vue等)和应用程序的代码分别打包到不同的Chunk Group中。这样可以将第三方库的代码缓存到浏览器中,以便在多个页面中重复使用,并在应用程序更新时,只下载应用程序的代码,而不必重新下载第三方库的代码。
asset和bundle:
asset(资源):指的是Web应用程序中除了JavaScript代码以外的静态文件,如CSS、图片、字体等。这些文件通常被称为静态资源,因为它们不会动态生成或者发生改变。
bundle(捆绑包):指的是Webpack打包后生成的JavaScript文件,其中包含了应用程序的所有代码,包括依赖项和业务逻辑。Webpack通过将多个JavaScript模块(包括依赖项和业务逻辑)合并为一个或多个bundle来实现代码的管理和优化。

14.将webpack 的打包思想可以简化为 3 点:

  • 一切源代码文件均可通过各种 Loader 转换为 JS 模块 (module),模块之间可以互相引用。
  • webpack 通过入口点(entry point)递归处理各模块引用关系,最后输出为一个或多个产物包 js(bundle) 文件。
  • 每一个入口点都是一个块组(chunk group),在不考虑分包的情况下,一个 chunk group 中只有一个 chunk,该 chunk 包含递归分析后的所有模块。每一个 chunk 都有对应的一个打包后的输出文件(asset/bundle

15.webpack打包流程

1.初始化参数:将Webpack的配置对象合并到用户提供的配置对象中,得出最终的配置参数。
2.开始编译:从上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译。
在 Webpack 打包流程中,Webpack 会根据命令行参数初始化一个 Compiler 对象。这个 Compiler 对象是整个打包过程的核心,负责管理所有的打包流程,从文件的解析到生成最终的打包文件。参数会被传递到 Compiler 对象的构造函数中,因此在构造 Compiler 对象时,Webpack 会使用这些参数来初始化各种属性,如 entry、output、module、resolve 等。
在构造完 Compiler 对象之后,Webpack 会加载所有配置的插件,这些插件可以通过在 webpack.config.js 文件中配置的方式进行加载。Webpack 中的插件可以在整个打包过程中的不同阶段执行各种任务,例如文件解析、代码转换、文件输出等。这些插件可以对打包过程进行扩展和定制,以满足不同的需求。
最后,Webpack 会调用 Compiler 对象的 run 方法,开始执行编译。在执行编译过程中,Webpack 会遍历所有的入口文件,通过 Loader 将其转换成模块,再将模块打包成最终的输出文件。整个打包过程中会依次执行各个插件的任务,并根据插件的结果来决定下一步的操作。一旦所有的模块都被打包完成,Webpack 就会生成最终的输出文件,并将其保存到指定的输出路径中,完成整个打包过程。
3.确定入口:根据配置中的 entry 找出所有的入口文件。
4.编译模块:从入口文件出发,调用所有配置的 loader 对模块进行翻译,再找出该模块依赖的模块,这个步骤是递归执行的,直至所有入口依赖的模块文件都经过本步骤的处理。
5.完成模块编译:经过第 4 步使用 loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系。
6.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 chunk,再把每个 chunk 转换成一个单独的文件加入到输出列表,这一步是可以修改输出内容的最后机会。
7.输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
简版
Webpack CLI 启动打包流程;
载入 Webpack 核心模块,创建 Compiler 对象;
使用 Compiler 对象开始编译整个项目;
从入口文件开始,解析模块依赖,形成依赖关系树;
递归依赖树,将每个模块交给对应的 Loader 处理;
合并 Loader 处理完的结果,将打包结果输出到 dist 目录。

16.webpack构建流程核心概念

Tapable:一个基于发布订阅的事件流工具类,Compiler 和 Compilation 对象都继承于 Tapable。
发布订阅模式是一种常见的事件处理模式,它将事件的发布者和订阅者分离开来,通过事件中心(或者叫做事件总线)来协调它们之间的通信。在发布订阅模式中,发布者(或者叫做事件源)会在事件中心上发布事件,订阅者会在事件中心上订阅事件,并在事件发生时被通知到。这种模式具有高度的灵活性和可扩展性,可以方便地实现各种插件和扩展。

继承于 Tapable 的 Compiler 和 Compilation 对象分别表示 Webpack 的编译器和编译过程,它们都有自己的钩子和事件流。Compiler 对象负责读取配置文件、解析入口文件、生成依赖关系图等等,而 Compilation 对象则负责具体的模块编译、文件生成、代码压缩等等。
Compiler:compiler对象是一个全局单例,他负责把控整个webpack打包的构建流程。在编译初始化阶段被创建的全局单例,包含完整配置信息、loaders、plugins以及各种工具方法。
Compilation:代表一次 webpack 构建和生成编译资源的的过程,在watch模式下每一次文件变更触发的重新编译都会生成新的 Compilation 对象,包含了当前编译的模块 module, 编译生成的资源,变化的文件, 依赖的状态等。
而每个模块间的依赖关系,则依赖于AST语法树。每个模块文件在通过Loader解析完成之后,会通过acorn库生成模块代码的AST语法树,通过语法树就可以分析这个模块是否还有依赖的模块,进而继续循环执行下一个模块的编译解析。
抽象语法树(Abstract Syntax Tree,AST)是指程序源代码在编译器或解释器中被解析时生成的一种树状结构。AST 中的每个节点都代表着源代码中的一个语法结构,例如表达式、语句、声明等等。AST 可以用来帮助编译器或解释器进行代码分析和优化,也可以用来进行程序分析和转换。

Webpack 打包生成的 bundle 文件是一个立即执行函数(Immediately Invoked Function Expression,IIFE),也可以称之为自执行匿名函数。
具体来说,Webpack 会将打包后的模块代码包裹在一个函数内部,并在函数定义后立即执行该函数。这个函数一般是一个匿名函数,因为它的名字并不重要,而且不会与其他代码中的函数名产生冲突。为了避免在函数内部使用全局变量产生的命名冲突,Webpack 会将模块代码中的变量名进行重命名,并在函数内部使用新的变量名。

通过使用 IIFE,Webpack 实现了模块代码的封装和作用域的隔离。这样可以避免模块之间的变量污染和命名冲突,同时也可以防止模块内部的变量被意外地暴露在全局作用域中,增强了代码的可维护性和可靠性。

在浏览器中加载 bundle 文件时,会立即执行这个 IIFE 函数,并将模块代码和依赖关系注入到函数中。这样就可以实现模块的加载和执行,同时也可以避免在全局作用域中污染变量和命名空间。

17.Webpack 是一个现代化的打包工具,它的核心概念包括

Entry:入口
Webpack 构建应用程序的起点是从一个或多个入口开始的。入口可以是 JavaScript 文件、CSS 文件、HTML 文件或任何其他文件类型。Webpack 将从入口开始递归地解析和处理所有依赖关系,并生成最终的输出结果。

Output:输出
Webpack 会将打包后的结果输出到指定的目录下。输出的结果可以是一个或多个文件,具体取决于打包配置中的设置。例如,可以将输出文件压缩、混淆、合并等操作以减小文件体积并提高加载速度。

Loader:模块转换器
Webpack 本身只能处理 JavaScript 模块,如果需要处理其他类型的文件,需要使用 Loader 进行转换。Loader 可以将非 JavaScript 模块转换成 JavaScript 模块,例如将 CSS 文件转换成 JavaScript 代码,并将其添加到打包后的输出文件中。

Plugin:扩展插件
Plugin 可以扩展 Webpack 的功能,例如通过 UglifyJSPlugin 对输出的文件进行压缩,通过 HtmlWebpackPlugin 自动生成 HTML 文件等等。Plugin 的作用范围往往比 Loader 更广泛,可以在 Webpack 的各个阶段中进行操作。

Mode:打包模式
Webpack 提供了三种打包模式,分别是 development、production 和 none。通过设置不同的打包模式,可以启用不同的内置优化策略,例如 development 模式会启用更加详细的输出信息和开发者工具,而 production 模式会启用更加激进的优化策略以减小文件体积。

18. 介绍 Loader

file-loader: 加载文件资源,如 字体 / 图片 等,具有移动/复制/命名等功能;
url-loader: 通常用于加载图片,可以将小图片直接转换为 Date Url,减少请求;
babel-loader: 加载 js / jsx 文件, 将 ES6 / ES7 代码转换成 ES5,抹平兼容性问题;
ts-loader: 加载 ts / tsx 文件,编译 TypeScript;
style-loader: 将 css 代码以<style>标签的形式插入到 html 中;
css-loader: 分析@import和url(),引用 css 文件与对应的资源;
postcss-loader: 用于 css 的兼容性处理,具有众多功能,例如 添加前缀,单位转换 等;
less-loader / sass-loader: css预处理器,在 css 中新增了许多语法,提高了开发效率;
编写原则:

单一原则: 每个 Loader 只做一件事;
链式调用: Webpack 会按顺序链式调用每个 Loader;
统一原则: 遵循 Webpack制定的设计规则和结构,输入与输出均为字符串,各个 Loader 完全独立,即插即用;
#

19. 介绍 plugin

在 Webpack 中,plugin 是一种用于扩展 Webpack 功能的机制,它可以在 Webpack 运行过程中监听特定的事件,执行自己的逻辑,并且可以修改 Webpack 内部的数据或控制 Webpack 的流程。Plugin 可以用于处理文件、生成统计数据、优化输出结果等等,也可以用于实现各种自定义需求。

Webpack 就像工厂中的一条产品流水线。原材料经过 Loader 与 Plugin 的一道道处理,最后输出结果。

通过链式调用,按顺序串起一个个 Loader;
通过事件流机制,让 Plugin 可以插入到整个生产过程中的每个步骤中;

一个 Plugin 实际上是一个 JavaScript 对象,它通常包含如下属性和方法:

apply 方法:是一个必须的方法,它接受一个 compiler 参数,代表 Webpack 编译器对象。在这个方法中可以访问到 Webpack 编译器的各种信息和事件流,可以定义自己的钩子函数来监听 Webpack 的特定事件。
compiler 钩子:表示 Webpack 编译器对象上的事件,例如 beforeCompile、afterCompile 等等。Plugin 可以定义自己的方法来监听这些钩子,并在事件发生时执行自己的逻辑。
compilation 钩子:表示 Webpack 编译过程中的一个阶段,例如 optimize、seal、optimizeChunkAssets 等等。Plugin 可以定义自己的方法来监听这些钩子,并在事件发生时执行自己的逻辑。

在 Webpack 中,使用 Plugin 机制非常灵活,可以通过自定义 Plugin 实现各种需求。例如可以实现自定义的文件名生成、自动化注入脚本、按需加载、生成 manifest 等等。当然,也可以使用现有的 Plugin,例如 HtmlWebpackPlugin、CleanWebpackPlugin、HotModuleReplacementPlugin 等等。这些 Plugin 都可以在 Webpack 的配置文件中进行配置和使用。

20.Webpack 中两个最重要的类 Compiler 与 Compilation 便是继承于 Tapable,也拥有这样的事件流机制。

Compiler: 可以简单的理解为 Webpack 实例,它包含了当前 Webpack 中的所有配置信息,如 options, loaders, plugins 等信息,全局唯一,只在启动时完成初始化创建,随着生命周期逐一传递;

Compilation: 可以称为 编译实例。当监听到文件发生改变时,Webpack 会创建一个新的 Compilation 对象,开始一次新的编译。它包含了当前的输入资源,输出资源,变化的文件等,同时通过它提供的 api,可以监听每次编译过程中触发的事件钩子;

区别:

Compiler 全局唯一,且从启动生存到结束;
Compilation对应每次编译,每轮编译循环均会重新创建;

21.常用 Plugin:

UglifyJsPlugin: 压缩、混淆代码;
CommonsChunkPlugin: 代码分割;
ProvidePlugin: 自动加载模块;
html-webpack-plugin: 加载 html 文件,并引入 css / js 文件;
extract-text-webpack-plugin / mini-css-extract-plugin: 抽离样式,生成 css 文件; DefinePlugin: 定义全局变量;
optimize-css-assets-webpack-plugin: CSS 代码去重;
webpack-bundle-analyzer: 代码分析;
compression-webpack-plugin: 使用 gzip 压缩 js 和 css;
happypack: 使用多进程,加速代码构建;
EnvironmentPlugin: 定义环境变量;

22.loader和plugin有什么区别?

webapck默认只能打包JS和JOSN模块,要打包其它模块,需要借助loader,loader就可以让模块中的内容转化成webpack或其它laoder可以识别的内容。

loader就是模块转换化,或叫加载器。不同的文件,需要不同的loader来处理。
plugin是插件,可以参与到整个webpack打包的流程中,不同的插件,在合适的时机,可以做不同的事件

23.webpack中都有哪些插件,这些插件有什么作用?

html-webpack-plugin 自动创建一个HTML文件,并把打包好的JS插入到HTML文件中
clean-webpack-plugin 在每一次打包之前,删除整个输出文件夹下所有的内容
mini-css-extrcat-plugin 抽离CSS代码,放到一个单独的文件中
optimize-css-assets-plugin 压缩css

24 webpack 热更新实现原理

Webpack热更新(Hot Module Replacement,HMR)是一种能够在应用程序运行时替换、添加或删除模块而不需要完全重新加载页面的技术。
其基本原理如下:

Webpack 开启一个websocket长连接,在应用程序运行时,webpack 会在客户端和服务器之间建立一个websocket长连接。

修改代码后,Webpack监测到代码变化,并通过websocket将变化的代码信息发送给客户端。

客户端根据收到的代码变化信息,在不刷新整个页面的情况下,对局部进行更新。

具体来说,当一个模块发生变化时,Webpack会通知相应的插件,插件将决定如何处理这个变化。通常情况下,插件会使用Hot Module Replacement Runtime(HMR Runtime)来处理模块更新。

HMR Runtime是客户端代码的一部分,它会接收到Webpack发来的更新消息,并根据消息内容来更新模块。如果模块可以被热替换,HMR Runtime会直接将新的模块代码注入到页面中,否则会触发页面刷新以加载新的模块代码。

总的来说,Webpack热更新的实现原理就是通过websocket建立一个客户端与服务器之间的连接,然后通过消息的方式来实现模块的热替换。

25.webpack 层面如何做性能优化

减少 entry 数量:尽量减少 entry 数量,可以降低打包时间和内存使用量。如果项目需要多个入口,可以使用 webpack-merge 将多个配置文件合并成一个。

使用缓存:使用 webpack 的缓存机制可以减少重新构建的时间。可以通过配置 cache-loader 或者使用 hard-source-webpack-plugin 插件来实现。

使用 DLL:使用动态链接库(DLL)可以大大缩短打包时间。通过配置 dll-plugin 可以将一些不经常变动的库提前打包成 DLL 文件,再在开发过程中直接使用,避免每次都打包。

优化 loader:在使用 loader 时,尽量使用最小化的正则表达式,并且配置好 include 和 exclude,减少不必要的编译。

优化插件:Webpack 插件可以实现很多高级功能,但是一些插件可能会影响性能。尽量只使用必要的插件,删除不需要的插件。

拆分代码:将代码拆分成多个块可以提高代码的并行加载能力,从而提高页面加载速度。可以使用 Webpack 的 code splitting 功能来实现。

压缩代码:使用 UglifyJSPlugin 或者 TerserPlugin 等插件来压缩代码,减小文件大小,提高加载速度。

开启 Tree shaking:在 webpack 中开启 Tree shaking 可以剔除未使用的代码,减小打包后的文件大小,提高加载速度。

开启 Scope Hoisting:Scope Hoisting 可以将模块中的函数作用域提升到父作用域,减少函数声明代码,从而减少代码量。

优化前的准备工作

准备基于时间的分析工具:我们需要一类插件,来帮助我们统计项目构建过程中在编译阶段的耗时情况。speed-measure-webpack-plugin 分析插件加载的时间
使用 webpack-bundle-analyzer 分析产物内容
代码优化::
无用代码消除,是许多编程语言都具有的优化手段,这个过程称为 DCE (dead code elimination),即 删除不可能执行的代码;
摇树优化 (Tree-shaking)
摇树优化 (Tree-shaking),这是一种形象比喻。我们把打包后的代码比喻成一棵树,这里其实表示的就是,通过工具 “摇” 我们打包后的 js 代码,将没有使用到的无用代码 “摇” 下来 (删除)。即 消除那些被 引用了但未被使用 的模块代码。
原理: 由于是在编译时优化,因此最基本的前提就是语法的静态分析,ES6的模块机制 提供了这种可能性。不需要运行时,便可进行代码字面上的静态分析,确定相应的依赖关系。
问题: 具有 副作用 的函数无法被 tree-shaking
在引用一些第三方库,需要去观察其引入的代码量是不是符合预期;
尽量写纯函数,减少函数的副作用;
可使用 webpack-deep-scope-plugin,可以进行作用域分析,减少此类情况的发生,但仍需要注意;
code-spliting: 代码分割技术,将代码分割成多份进行 懒加载 或 异步加载,避免打包成一份后导致体积过大,影响页面的首屏加载;
Webpack 中使用 SplitChunksPlugin 进行拆分;
按 页面 拆分: 不同页面打包成不同的文件;
按 功能 拆分:
将类似于播放器,计算库等大模块进行拆分后再懒加载引入;
提取复用的业务代码,减少冗余代码;
按 文件修改频率 拆分: 将第三方库等不常修改的代码单独打包,而且不改变其文件 hash 值,能最大化运用浏览器的缓存;
scope hoisting: 作用域提升,将分散的模块划分到同一个作用域中,避免了代码的重复引入,有效减少打包后的代码体积和运行时的内存损耗;
编译性能优化:
升级至 最新 版本的 webpack,能有效提升编译性能;
使用 dev-server / 模块热替换 (HMR) 提升开发体验;
监听文件变动 忽略 node_modules 目录能有效提高监听时的编译效率;
缩小编译范围
modules: 指定模块路径,减少递归搜索;
mainFields: 指定入口文件描述字段,减少搜索;
noParse: 避免对非模块化文件的加载;
includes/exclude: 指定搜索范围/排除不必要的搜索范围;
alias: 缓存目录,避免重复寻址;
babel-loader
忽略node_moudles,避免编译第三方库中已经被编译过的代码
使用cacheDirectory,可以缓存编译结果,避免多次重复编译

多进程并发
webpack-parallel-uglify-plugin: 可多进程并发压缩 js 文件,提高压缩速度;
HappyPack: 多进程并发文件的 Loader 解析;

第三方库模块缓存:
DLLPlugin 和 DLLReferencePlugin 可以提前进行打包并缓存,避免每次都重新编译

使用分析
Webpack Analyse / webpack-bundle-analyzer 对打包后的文件进行分析,寻找可优化的地方
配置profile:true,对各个编译阶段耗时进行监控,寻找耗时最多的地方
source-map:
开发: cheap-module-eval-source-map
生产: hidden-source-map;
优化webpack打包速度
减少文件搜索范围
比如通过别名
loader 的 test,include & exclude
Webpack4 默认压缩并行
Happypack 并发调用
babel 也可以缓存编译
Resolve 在构建时指定查找模块文件的规则
使用DllPlugin,不用每次都重新构建
externals 和 DllPlugin 解决的是同一类问题:将依赖的框架等模块从构建过程中移除。它们的区别在于
在 Webpack 的配置方面,externals 更简单,而 DllPlugin 需要独立的配置文件。
DllPlugin 包含了依赖包的独立构建流程,而 externals 配置中不包含依赖框架的生成方式,通常使用已传入 CDN 的依赖包
externals 配置的依赖包需要单独指定依赖模块的加载方式:全局对象、CommonJS、AMD 等
在引用依赖包的子模块时,DllPlugin 无须更改,而 externals 则会将子模块打入项目包中
优化打包体积
提取第三方库或通过引用外部文件的方式引入第三方库
代码压缩插件UglifyJsPlugin
服务器启用gzip压缩
按需加载资源文件 require.ensure
优化devtool中的source-map
剥离css文件,单独打包
去除不必要插件,通常就是开发环境与生产环境用同一套配置文件导致
Tree Shaking 在构建打包过程中,移除那些引入但未被使用的无效代码
开启 scope hosting
体积更小
创建函数作用域更小
代码可读性更好

26. 介绍一下 Tree Shaking

作用:

它表示在打包的时候会去除一些无用的代码
原理:
ES6的模块引入是静态分析的,所以在编译时能正确判断到底加载了哪些模块
分析程序流,判断哪些变量未被使用、引用,进而删除此代码
特点:
在生产模式下它是默认开启的,但是由于经过babel编译全部模块被封装成IIFE,它存在副作用无法被tree-shaking掉
可以在package.json中配置sideEffects来指定哪些文件是有副作用的。它有两种值,一个是布尔类型,如果是false则表示所有文件都没有副作用;如果是一个数组的话,数组里的文件路径表示改文件有副作用
rollup和webpack中对tree-shaking的层度不同,例如对babel转译后的class,如果babel的转译是宽松模式下的话(也就是loose为true),webpack依旧会认为它有副作用不会tree-shaking掉,而rollup会。这是因为rollup有程序流分析的功能,可以更好的判断代码是否真正会产生副作用。

27.介绍一下 webpack scope hosting

作用域提升,将分散的模块划分到同一个作用域中,避免了代码的重复引入,有效减少打包后的代码体积和运行时的内存损耗;

28 Webpack Proxy工作原理?为什么能解决跨域

1. 是什么

webpack proxy,即webpack提供的代理服务

基本行为就是接收客户端发送的请求后转发给其他服务器

其目的是为了便于开发者在开发模式下解决跨域问题(浏览器安全策略限制)

想要实现代理首先需要一个中间服务器,webpack中提供服务器的工具为webpack-dev-server
2. webpack-dev-server

webpack-dev-server是 webpack 官方推出的一款开发工具,将自动编译和自动刷新浏览器等一系列对开发友好的功能全部集成在了一起

目的是为了提高开发者日常的开发效率,「只适用在开发阶段」

关于配置方面,在webpack配置对象属性中通过devServer属性提供,如下:

module.exports = {
    // ...
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        compress: true,
        port: 9000,
        proxy: {
            '/api': {
                target: 'https://api.github.com'
            }
        }
        // ...
    }
}
target:表示的是代理到的目标地址
pathRewrite:默认情况下,我们的 /api-hy 也会被写入到URL中,如果希望删除,可以使用pathRewrite
secure:默认情况下不接收转发到https的服务器上,如果希望支持,可以设置为false
changeOrigin:它表示是否更新代理后请求的 headers 中host地址

2. 工作原理
proxy工作原理实质上是利用http-proxy-middleware 这个http代理中间件,实现请求转发给其他服务器
3.跨域

在开发阶段, webpack-dev-server 会启动一个本地开发服务器,所以我们的应用在开发阶段是独立运行在 localhost的一个端口上,
而后端服务又是运行在另外一个地址上

所以在开发阶段中,由于浏览器同源策略的原因,当本地访问后端就会出现跨域请求的问题
通过设置webpack proxy实现代理请求后,相当于浏览器与服务端中添加一个代理者

当本地发送请求的时候,代理服务器响应该请求,并将请求转发到目标服务器,目标服务器响应数据后再将数据返回给代理服务器,最终再由代理服务器将数据响应给本地。
在代理服务器传递数据给本地浏览器的过程中,两者同源,并不存在跨域行为,这时候浏览器就能正常接收数据

注意:「服务器与服务器之间请求数据并不会存在跨域行为,跨域行为是浏览器安全策略限制」

29.介绍一下 babel原理

Babel 的原理是将新版本的 JavaScript 代码转换为向后兼容的代码。Babel 将 JavaScript 代码解析为 AST(抽象语法树),对 AST 进行分析和转换,最终生成转换后的代码。
Babel 的核心功能是通过插件对 AST 进行转换。Babel 的插件系统是一个强大的机制,可以将代码转换为任何你想要的形式。Babel 的插件可以实现很多功能,例如将 ES6 的箭头函数转换为 ES5 的普通函数,将 JSX 转换为 JavaScript 等等。
babel 的编译过程分为三个阶段:parsing、transforming、generating,以 ES6 编译为 ES5 作为例子:
Parsing(解析)阶段:Babel 会将输入的 JavaScript 代码解析为抽象语法树(AST)。AST 是一种表示程序语法结构的树形数据结构,它可以帮助 Babel 理解代码的语法结构和含义。
Transforming(转换)阶段:Babel 会对 AST 进行遍历,并根据需要进行修改。在这个阶段,Babel 可以使用各种插件对 AST 进行修改、添加、删除等操作,从而实现对 JavaScript 代码的转换。
Generating(生成)阶段:Babel 会将转换后的 AST 重新生成 JavaScript 代码。这个阶段会把 AST 转换回普通的 JavaScript 代码,并且可以根据需要生成不同版本的 JavaScript 代码(例如 ES5、ES6 等)。
Babel 首先对输入的 JavaScript 代码进行解析,生成对应的 AST;然后对 AST 进行遍历和修改,生成转换后的 AST;最后将转换后的 AST 转换为 JavaScript 代码。整个过程中,Babel 的插件系统起到了至关重要的作用,它可以对 AST 进行各种修改和操作,从而实现对 JavaScript 代码的自定义转换和扩展。

ES6 代码输入;
babylon 进行解析得到 AST;
plugin 用 babel-traverse 对 AST树进行遍历编译,得到新的 AST树;
用 babel-generator 通过 AST树生成 ES5 代码。

30 介绍一下Rollup

它也可以将项目中散落的细小模块打包为整块代码,从而使得这些划分的模块可以更好地运行在浏览器环境或者 Node.js 环境。
Rollup优势:

输出结果更加扁平,执行效率更高;
自动移除未引用代码;
打包结果依然完全可读。

缺点

加载非 ESM 的第三方模块比较复杂;
因为模块最终都被打包到全局中,所以无法实现 HMR;
浏览器环境中,代码拆分功能必须使用 Require.js 这样的 AMD 库
总结一下:Webpack 大而全,Rollup 小而美。

在对它们的选择上,我的基本原则是:应用开发使用 Webpack,类库或者框架开发使用 Rollup。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值