微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Webpack 面试题汇总持续更新4.9

乐闻世界-webpack面试题

什么是前端模块化?AMD、CMD、Commonjs、ES6模块化之间的区别是什么?

模块化 是指将一个复杂的系统分解为多个模块以方便编码。

模块化规范 的实现是为了达成浏览器端模块化的目的。

AMD 是一种Javascript模块化规范,采用异步的方式去加载依赖的模块。不用转换代码的情况下直接运行在浏览器环境。 依赖前置,提前执行。代表库 requirejs

CMD 是一种Javascript模块化规范,依赖就近,延迟执行。代表库seajs

Commonjs 通过 require 方法同步加载依赖的其他模块,通过module.exports导出需要暴露的接口。 优点:代码可以在Nodejs环境复用。缺点:代码不能直接运行在浏览器环境,必须通过工具转换成标准的ES5。

ES6是语言层面的模块化,浏览器和Node都原生支持,逐渐取代 CommonjsAMD。目前无法直接运行在大部分 JavaScript 环境,都需要通过工具转换标准的ES5代码

webpack工作流程及原理

原理:Webpack 启动后会从 Entry 里配置的 Module 开始,递归解析 Entry 依赖的所有的 Module。没找到一个 Module ,就会根据配置的 Loader 去找出对应的转换规则,对 Module 进行转换后,再解析出当前 Module 依赖的 Module。这些模块会以 Entry 为单位进行分组,一个 Entry 及其所有依赖的 Module 被分到一个组也就是一个 Chunk。最后,webpack 会将所有的 C hunk 转换成文件输出。在整个流程中,Webpack 会在恰当的时机执行Plugin里定义的逻辑。

工作流程:(加载 -> 编译 -> 输出

  1. 读取配置文件,按命令初始化配置参数,创建 Compiler 对象
  2. 调用插件的 apply 方法挂载插件监听,然后从入口文件开始执行编译
  3. 文件类型,调用相应的 Loader 对模块进行编译,并在合适的时机点出发对应的事件,调用 plugin 执行,最后再根据模块依赖查找到所依赖的模块,递归执行直到整个项目解析完毕。
  4. 将编译后的所有的代码包装成一个代码块(chunk),并按依赖和配置确定输出内容。这个步骤仍然可以通过 plugin 进行文件修改
  5. 最后根据output配置把最终编译文件输出到指定的文件夹。

webpack核心配置

entry

string 入口模块的文件路径,只生成一个chunk

array 入口模块的文件路径,只有数组里的最后一个入口文件的模块会被导出

object 配置多个入口,每个入口生成一个chunk

output

filename 产物chunk文件名称

path 输出产物文件存在位置

publicPath CDN配置路径

libary 导出库的名称

libaryTarget 配置以何种方式到处库

module

rules loader, 配置模块的读取和解析规则。{test:/.js/,use:[‘babel-loader’],include:’’,exclude:’’}

noparse 不用解析和处理的模块

plugin 各种各样的 plugin 几乎可以让 web pack 做任何与构建相关的事情

resolve webapck在启动的时候会从配置的入口模块出发找到所有依赖的模块,resolve配置webapck如何寻找模块对应的文件

alias 别名

extensions 导入没有带文件后缀时,extensions用于配置在尝试过程中用到的后缀列表。

modules 配置 webpack 去哪些目录下寻找第三方模块,认只会去node_modules

resolveLoader 告诉 webpack 如何寻找 loader,用于加载本地的loader

target 配置webpack构建出针对不同运行环境的代码,比如web,node,async-node,webworker,electron-main,electron-renderer

devtool webpack 如何生成 sourceMap

watch webpack 监听模式,文件发生变化时重新编译

watchOptions 监听模式配置信息

externals webpack 要构建的代码中使用了哪些不用被打包的模块,也就是这些模块是外部环境。

Webpack 热更新原理

在我们开发时使用 Webpack Dev Server 提供热更新功能,webpack dev server 中存在两个server: Bundle Server , HMR Server。

初始化: webpack compiler 将源文件编译层 bundle.js,浏览器请求到bundle.js并与 webpack dev server 通过 websocket 建立连接。

热更新: webpack会对源文件进行监听,当修改了源文件,webpack compiler 重新编译,并通过 HMR server进行更新;

HMR 运行时替换更新中的模块,如果确定这些模块无法更新,则触发整个页面刷新。

Webpack Loader

因为 webpack 认情况下只能识别 js 模块,如果我们需要处理不同格式文件,就需要配置对应的文件转换器,Loader 就是文件转换器。

Loader的职责应该保持单一性,我们只需要关心输入和输出,即Loader函数的参数是处理前的文件内容,返回处理后的内容

通常需要将代码进行分析,构建AST,遍历进行定向修改重新生成新的代码字符串。

  • 链式传递,按照配置的相反顺序链式执行

  • 基于 Node 环境,拥有较高权限

  • 可以同步也可以异步

Webpack Plugin

插件系统是 webpack 核心能力之一,在整个编译生命周期中,webpack 会触发许多事件钩子,plugin 可以监听这些事件,根据需求在相应的时间点对打包内容进行定向修改

事件流机制:webpack 就像工厂中的一条产品流水线。原材料经过 Loader 与 Plugin 的一道道处理,最后输出目标产物。

Webpck事件流编程规范核心是基于 Tapable, 是一种 观察者模式 的实现事件的订阅与广播。

Webpack 中两个最重要的类 CompilerCompilation 继承与 Tapable

Compiler: webpack 实例,全局唯一,从启动生成到结束。包含了当前webpack中所有的配置信息,比如 options, loaders,plugins等信息。启动时进行初始化创建,随着生命周期传递。

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

loader 和 plugin 有什么区别?

Webpack 认只能打包 JS 和 JSON 文件,要打包其他模块,需要借助loader, loader就可以让模块中的内容转化成webpack或者其他loader可以识别的内容

loader 用于模块内容转换,plugin参与整个webpack 打包流程,在合适的时机,可以处理不同的事件。

Webpack 编译优化途径

  1. 打包速度优化:

    1. 减少文件搜索范围(loader的test正则匹配,include,exclude)
    2. noparse:避免对非模块化文件的加载
    3. 别名alias(减少导入模块路径推导过程)缓存目录,避免重复寻址
    4. Happypack并行调用打包
    5. babel可以缓存编译结果,避免多次重复编译,配置cacheDirectory
    6. 第三方库模块缓存:DllPlugin 可以提前进行打包并缓存,避免每次都重新编译
    7. 使用分析工具 webpack Analyse/ webpack-bundle-analyzer 对打包的文件进行分析,寻找耗时长可优化的地方
  2. 代码优化

    1. 无用代码消除,减少最终产物体积(tree-shaking)

    2. code-spliting 代码分割技术,将代码分割成多份进行懒加载或者异步加载,避免打包成一份后导致体积过大而影响页面的首屏加载速度。

Tree Shaking 原理

打包的时候会去除一些无用的代码

原理: ES6的模块引入是静态分析的,所以在编译时能够正确判断到底加载了哪些模块。编译时分析程序流,判断哪些变量未被使用、引用,进而删除代码

ES6的import语法可以使用tree shaking,Commonjs的动态特性模块意味着tree shaking 不合适。

Webpack 动态导入原理

动态导入可以实现按需加载我们的代码,并使用 promise式的回调,获取加载的包。在代码中所有被import()的模块,都将打包成一个单独的包,放在chunk存储的目录下。在浏览器运行到这行代码时,就会自动请求资源,从而实现了异步加载的效果

为什么需要把源文件进行合并

将源文件合并到一个单独的bundle.js的原因是,浏览器不能像Node.js能够快速加载本地的一个个模块,而需要通过网络请求去加载还没有得到的文件。如果文件数量很多,会加载很长时间,所以合并到一个文件后,只需要加载一次就能达到目的。

bundle.js 能够直接在浏览器运行的原因是,在输出文件中通过 _webpack_require_ 函数,定义了一个可以在浏览器中执行的加载函数模拟nodejs中的require语句。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐