愚墨的博客
  • 首页
  • 前端技术
  • 面试
只争朝夕不负韶华
  1. 首页
  2. 前端技术
  3. 正文

20下半年面试题-webpack

2020年12月04日 3706点热度 0人点赞 0条评论

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

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

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的使用需要自己写一丢丢代码,也很简单,具体看官方文档。

总结

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

标签: webpack 面试
最后更新:2020年12月04日

愚墨

保持饥渴的专注,追求最佳的品质

点赞
< 上一篇
下一篇 >

文章评论

取消回复

搜搜看看
历史遗迹
  • 2023年5月
  • 2022年9月
  • 2022年3月
  • 2022年2月
  • 2021年12月
  • 2021年8月
  • 2021年7月
  • 2021年5月
  • 2021年4月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年9月
  • 2020年7月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年1月
  • 2019年5月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年9月
  • 2018年3月
  • 2018年2月
  • 2018年1月
  • 2017年11月
  • 2017年7月
  • 2017年6月
  • 2017年3月
  • 2017年2月
  • 2017年1月
  • 2016年12月
  • 2016年11月
  • 2016年9月
  • 2016年8月
  • 2016年7月
  • 2016年6月
  • 2016年5月
  • 2016年4月
  • 2016年3月
  • 2016年2月
  • 2016年1月
  • 2015年12月
  • 2015年10月
  • 2015年9月
  • 2015年7月
  • 2015年6月
  • 2015年4月

COPYRIGHT © 2020 愚墨的博客. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS