20下半年高频题目之webpack

908 阅读5分钟

image

按照之前的专科前端生存之路 中所写的知识点。此篇是我近2个月遇到的webpack的题目。

系列文章

20下半年高频题目-React

看其他的人写webpack的面试题写的就差不多是把文档抄了一遍。作为学习资料还行,真正面试中面试官不会问出API如何使用等类似问题。此类问题最没有价值。

在面的这六七家公司中,关于webpack方面问的最多的问题就以下这个几个。

webpack loader和plugin的区别

【美团、头条】

该问题问的最多,只要你了解webpack基本都能说上来

  • webback中js作为一等公民,loader 赋予了webpack处理其他类型文件的能力,比如css、图片等。
  • plugin是用来增强文webpack的能力,让webpack有更多的活性。

如何编写一个plugin

【头条、美团、阿里】

这个问题看官方文档最明了。自己总结一下就是:

  • 使用类来编写,必须实现一个apply方法;如果是方法实现,需要在其prototype 上定义一个 apply 方法。
class webpackPlugin {
  constructor(){
    console.log('插件被使用了')
  }
  apply(compiler) {
  // compiler 很重要,是webpack的一个实例,这个实例存储了webpack各种信息,所有打包信息
  }
}
module.exports = webpackPlugin;
  • 我们的逻辑是在apply中实现

目前是用两种实现api,一种是 compiler.plugin('done'…);一种是 compiler.hooks.done。后者是新的api,目前使用较多。

相关的钩子使用看这里

给大家一个小的demo吧,实现一个生成versionMapping文件的plugin,就是每次生成的version 和 源文件写到一个文件中。

/**
 *
 * options={
 *    outputName 输出的文件名
 * }
 */
class CreateVersionsMapping {
  constructor(options) {
    this.options = options;
  }
  apply(compiler) {
    const outputName = this.options.outputName || 'versions.mapping';
    compiler.hooks.emit.tap('createVm', (compilation) => {
      // 创建一个头部字符串:
      let fileList = '';
      for (let filename in compilation.assets) {
        const reg = /(.+)@([0-9a-z]+)\.((?:js|css)$)/;
        const matchList = filename.match(reg);
        if (matchList) {
          filename = `${matchList[1]}.${matchList[3]}#${matchList[2]}`;
          fileList += `${filename}\n`;
        }
      }
      // 把它作为一个新的文件资源插入到 webpack 构建中:
      compilation.assets[outputName] = {
        source() {
          return fileList;
        },
        size() {
          return fileList.length;
        },
      };
      // callback();
    });
  }
}

module.exports = CreateVersionsMapping;

demo 使用方法,在webpack的配置中

...
const Cvm = require('./CreateVersionsMapping');
...
...
...
plugins:[
    new Cvm({ outputName: 'version.mapping' }),
]
...

执行后我们的输入目录中会增加一个 version.mapping 文件,内容就是version和文件的对应关系。

common~views/Main.js#3382d0a4a3ce
index.js#acaee480b87e
vendors~views/Main.js#1b7e16be8c04
views/Main.js#38ceb72893a4

好多初次接触webpack的朋友会觉得写一个plugin很难,其实很简单。敢下手写就行,不要怂,就是怼。

webpack的执行逻辑是什么

【头条、阿里、猿辅导、美团】

说句实在的,我面试的这几家公司,包括美团、阿里、头条等大厂,我觉得他们的面试官都不是特别的熟悉这套流程。

  • 解析shell和config

  • config合并和插件加载,生成一个options对象

  • 开始编译和构建流程

  • new 一个 compiler,调用compiler.run() 构建一个 Compilation对象,拥有超多的fun。两个作用:

    1、负责组织整个打包过程,包含了每个构建环节和输出环节所对应的方法,如 addEntry() , _addModuleChain() , buildModule() , seal() , createChunkAssets() (在每一个节点都会触发 webpack 事件去调用各插件)。

    2、二是该对象内部存放着所有 module ,chunk,生成的 asset 以及用来生成最后打包文件的 template 的信息。

  • 调用addEntry开始构建

    1、调用各loader处理模块之间的依赖,对每一个 require() 用对应的 loader 进行加工,最后生成一个 js module

    2、调用AST解析器将loader处理后的源文件生成抽象语法树

    3、遍历AST,构建改模块所依赖的模块。依赖模块会按照上述方法递归处理

  • 所有的模块及其依赖项build之后,调用各插件对构建的结果进行封装,对每一个module和chunk进行整理。生成编译后的源码。 这是我们在开发时进行代码优化和功能添加的关键环节。

  • 生成最终assets

    1、模块封装在这一步,判断是入口js还是异步加载的js,调用不同的模板对象进行封装(入口js renderChunkModules)(异步加载的 js 会调用 chunkTemplate 中的 render 方法)。

    2、模块封装,module.source()

    3、生成assets

  • 输出 按照 output 中的配置项将文件输出到了对应的 path 中,从而 webpack 整个打包过程结束。

如何使用webpack项目优化

【美团、头条、快手】

这个完全是实战经验,并且每个公司或者项目根据使用场景不同,优化的手段也是不同的。但是大致就是几个方向。

  • css的优化,

    1. 使用 mini-css-extract-plugin 来做文件合并
    2. 使用postcss-loader、autoprefixer来帮我们自动补齐浏览器前缀等
    3. css压缩
  • js的优化:

    1. 抽取公共代码 SplitChunksPlugin,这个在webpack4以后可以直接在 optimization 中配置。
    2. 懒加载,这个可以自己实现一个,或者是使用现有的库。
  • noParse 在使用类似于jq库的时候,我们不需要webpack再去构建其内部依赖关系,这时候我们可以手动干预。在module中 noParse: /jquery/

  • DLLPlugin dll是一个很好的优化手段,可以极大的提升我们的编译速度。让我们每次只编译业务代码,类似于React、Redux等我们不更改的包,只打包一次就可以。 DLL的使用需要自己写一丢丢代码,也很简单,具体看官方文档。

  • CDN 使用cdn可以免去我们打包到文件中,减少文件体积。但是在使用中要注意使用方式。

总结

上述四个问题是我最近的面试中问的webpack题目中最频繁的,也是我们应该掌握的基本题目。当然如果你了解webpack的核心 tapable 不妨在面试中拿出来讲讲。webpack整个流程都依赖于这套插件系统。

欢迎交流 互怼😂。