Kazaf's blog Kazaf's blog
首页
  • javascript
  • typescript
  • vue
  • react
  • babel
  • nginx
GitHub (opens new window)

Kazaf

前端打字员
首页
  • javascript
  • typescript
  • vue
  • react
  • babel
  • nginx
GitHub (opens new window)
  • Babel

  • 面试题

    • webpack相关面试题
      • webpack 如何对 js/css 代码进行压缩?
      • webpack 中 hash、chunkhash、contenthash 区别
      • Webpack 配置中用过哪些 Loader ?都有什么作用?
      • Webpack 配置中用过哪些 Plugin ?都有什么作用?
      • Loader 和 Plugin 有什么区别?
      • 是否写过 Loader?简单描述一下编写 loader 的思路?
      • 是否写过 Plugin?简单描述一下编写 Plugin 的思路?
  • 前端工程化
  • 面试题
Kazaf
2022-03-17

webpack相关面试题

# webpack 相关面试题

# webpack 如何对 js/css 代码进行压缩?

在 webpack 配置中设置 optimization 的 minimizer 属性,压缩 js 可以使用 terser-webpack-plugin 插件,插件内部使用的就是 terser 来实现对 js 代码的压缩,对 css 代码可以使用 css-minimizer-webpack-plugin 来对 css 代码进行压缩,插件内部使用 cssnano 优化和压缩 CSS。

# webpack 中 hash、chunkhash、contenthash 区别

  • hash: 是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的 hash 值都会更改,并且全部文件都共用相同的 hash 值
  • chunkhash: 是针对 entry 的每一个入口文件,独立的 hash。如果 entry 里面的其中一个文件内容改变,只会改变这个入口文件 build 之后的文件名,而不会影响到其他文件。
  • contenthash: 是针对文件内容级别的,文件自身的内容改变 hash 值才会发生变化。

# Webpack 配置中用过哪些 Loader ?都有什么作用?

  • file-loader: 把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
  • url-loader: 与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)
  • style-loader: 把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS,对于生产版本,建议 mini-css-extract-plugin 提供的 loader 从 bundle 中提取 CSS
  • css-loader: 加载 CSS,支持模块化、压缩、文件导入等特性
  • sass-loader: sass-loader 的作用就是将该 css 文件翻译成纯 css 语法文件,以便后续打包处理。
  • less-loader: 与 sass-loader 作用相同用于处理 less 文件。
  • postcss-loader: 通过 postcss css 后处理器对 css 进行处理,如配合 autoprefixer 插件自动补齐 CSS3 前缀
  • vue-loader: 加载 Vue.js 单文件组件
  • source-map-loader: 加载额外的 Source Map 文件,以方便断点调试

# Webpack 配置中用过哪些 Plugin ?都有什么作用?

  • define-plugin: 定义环境变量 如 process.env
  • html-webpack-plugin: 简化 HTML 文件创建 (依赖于 html-loader)
  • uglifyjs-webpack-plugin: 压缩 js 代码(不支持 ES6 压缩 )
  • terser-webpack-plugin: 压缩 js 代码(支持压缩 ES6 )
  • css-minimizer-webpack-plugin: 这个插件使用 cssnano 优化和压缩 CSS。
  • mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载 (替代 extract-text-webpack-plugin)
  • eslint-webpack-plugin: 该插件使用 eslint 来查找和修复 JavaScript 代码中的问题。
  • clean-webpack-plugin: 目录清理

# Loader 和 Plugin 有什么区别?

Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。

Plugin 就是插件,基于事件流框架 Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

# 是否写过 Loader?简单描述一下编写 loader 的思路?

  • loader 是使用在 node 环境的可以使用 node 的 api 或者引入自己安装的依赖
  • webpack 会根据配置的 test 属性将匹配到的文件转换成字符串或者 buffer 传递给 loader,当前 loader 处理完之后的结果会传递给下一个 loader。
  • webpack 提供了 loader-utils 和 schema-utils 工具库可以供使用
  • 可以通过 exports.raw = true 告诉 Webpack 该 Loader 是否需要二进制数据
  • loader 提供了 this 访问 loader context(上下文)使用 loader 内部的方法,
  • 如:this.callback() 一个可以同步或者异步调用的可以返回多个结果的函数。预期的参数是:
this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
);
1
2
3
4
5
6
  • 如:this.async() 告诉 loader-runner 这个 loader 将会异步地回调。返回 this.callback。
this.async(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
);
1
2
3
4
5
6

编写一个简单的 loader

// bar-loader.js
module.exports = function (content, map, meta) {
  content = content.replace('world', 'lin')
  this.callback(null, content, map, meta)
}
1
2
3
4
5
// index.js
const str = 'hello world'
console.log(str)
1
2
3

使用 loader

// webpack.config.js
const path = require('path')

module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bound.js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        use: ['./src/bar-loader.js']
      }
    ]
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

生成的 bound.js

/******/ ;(() => {
  // webpackBootstrap
  var __webpack_exports__ = {}
  const str = 'hello world'
  console.log(str)

  /******/
})()
1
2
3
4
5
6
7
8

# 是否写过 Plugin?简单描述一下编写 Plugin 的思路?

  • compiler 暴露了和 Webpack 整个生命周期相关的钩子

  • compilation 暴露了与模块和依赖有关的粒度更小的事件钩子

  • 插件需要在其原型上绑定 apply 方法,才能访问 compiler 实例

  • 传给每个插件的 compiler 和 compilation 对象都是同一个引用,若在一个插件中修改了它们身上的属性,会影响后面的插件

  • 找出合适的事件点去完成想要的功能

    • emit 事件发生时,可以读取到最终输出的资源、代码块、模块及其依赖,并进行修改(emit 事件是修改 Webpack 输出资源的最后时机)
    • watch-run 当依赖的文件发生变化时会触发
  • 异步的事件需要在插件处理完任务时调用回调函数通知 Webpack 进入下一个流程,不然会卡住

编写一个简单的 loader

// testPlugin.js
// webpack 插件其实是一个具有 apply 属性的 JavaScript 对象。
// apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问。
const pluginName = 'ConsoleLogOnBuildWebpackPlugin'

class ConsoleLogOnBuildWebpackPlugin {
  apply(compiler) {
    compiler.hooks.run.tap(pluginName, compilation => {
      console.log('webpack 构建过程开始!')
    })
  }
}

module.exports = ConsoleLogOnBuildWebpackPlugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14

使用 plugin

const path = require('path')
const testPlugin = require('./src/testPlugin.js')

module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bound.js'
  },
  plugins: [new testPlugin()]
}
1
2
3
4
5
6
7
8
9
10
11
12

运行 npx webpack 结果

linzhenbin@linzhenbindeAir test % npx webpack
webpack 构建过程开始!
asset bound.js 127 bytes [compared for emit] (name: main)
./src/index.js 43 bytes [built] [code generated]
webpack 5.70.0 compiled successfully in 35 ms
1
2
3
4
5
编辑 (opens new window)
#webpack#前端工程化
上次更新: 2022/03/22, 18:03:49
Babel基础知识

← Babel基础知识

最近更新
01
React中的受控和非受控组件
09-22
02
nginx基本配置
06-01
03
vue添加水印
05-26
更多文章>
Theme by Vdoing | Copyright © 2021-2022
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式