loader

1 官方文档:

https://www.webpackjs.com/api/loaders/

2 基础模板

  1. module.exports = function (source) {
  2. console.log('source', source)
  3. // 这里对source进行处理
  4. // .........
  5. // 处理完成后,将结果return出去
  6. return source
  7. }

3 说明

loader的功能就是将传进来的source,按照需求进行加工处理,将处理完的source返回出去,是一个函数,作用就是让任意类型的文件都能运行在浏览器中

2 编写原则

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

    关键点

  • Loader 运行在 Node.js 中,我们可以调用任意 Node.js 自带的 API 或者安装第三方模块进行调用

  • Webpack 传给 Loader 的原内容都是 UTF-8 格式编码的字符串,当某些场景下 Loader 处理二进制文件时,需要通过 exports.raw = true 告诉 Webpack 该 Loader 是否需要二进制数据
  • 尽可能的异步化 Loader,如果计算量很小,同步也可以
  • Loader 是无状态的,我们不应该在 Loader 中保留状态
  • 使用 loader-utils 和 schema-utils 为我们提供的实用工具
  • 加载本地 Loader 方法
  • Npm link
  • ResolveLoader

plugins

1 官方文档:

https://www.webpackjs.com/api/plugins/

2 基础模板

  1. class DemoWebpackPlugin {
  2. constructor () {
  3. console.log('plugin init')
  4. }
  5. apply (compiler) {
  6. compiler.hooks.emit.tapAsync('DemoWebpackPlugin', (compilation, fn) => {
  7. console.log(compilation)
  8. })
  9. }
  10. }
  11. module.exports = DemoWebpackPlugin

3 说明

webpack在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在特定的阶段钩入想要添加的自定义功能。Webpack 的 Tapable 事件流机制保证了插件的有序性,使得整个系统扩展性良好。
plugin类里面需要实现一个apply方法,webpack打包时候,会调用plugin的aplly方法来执行plugin的逻辑,这个方法接受一个compiler作为参数,这个compiler是webpack实例,compiler提供了本次打包的各个生命周期勾子,在这些钩子里实现需求
plugin是一个class类

4 compiler 、compilation

compiler

compiler 对象包含了Webpack 环境所有的的配置信息。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。

compilation

compilation对象包含了当前的模块资源、编译生成资源、变化的文件等。当运行webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。

compiler和 compilation的区别在于

  • compiler代表了当前这一次整个webpack从启动到关闭的生命周期,而compilation 只是代表了一次新的编译过程(比如我们改了一个文件,当前已经启动的webpack并没有先停下然后重新启动,而只是读取变更的文件重新编译了一下)
  • compiler和compilation暴露出许多钩子,我们可以根据实际需求的场景进行自定义处理

    5 关键点:

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

  • compilation 暴露了与模块和依赖有关的粒度更小的事件钩子
  • 插件需要在其原型上绑定apply方法,才能访问 compiler 实例
  • 传给每个插件的 compiler 和 compilation对象都是同一个引用,若在一个插件中修改了它们身上的属性,会影响后面的插件
  • 找出合适的生命周期钩子去完成想要的功能
  • emit 事件发生时,可以读取到最终输出的资源、代码块、模块及其依赖,并进行修改(emit 事件是修改 Webpack 输出资源的最后时机),用的较多
  • watch-run 当依赖的文件发生变化时会触发
  • 异步的事件需要在插件处理完任务时调用回调函数通知 Webpack 进入下一个流程,不然会卡住


    6 plugins示例及使用(同步、异步)

  1. 新建一个webpack-demoWebpackPlugin.js

实现了一个在输出目录添加一个index.md文件的功能

  1. class demoWebpackPlugin {
  2. constructor () {
  3. console.log('plugin init')
  4. }
  5. // compiler是webpack实例
  6. apply (compiler) {
  7. // 一个新的编译(compilation)创建之后(同步)
  8. // compilation代表每一次执行打包,独立的编译
  9. compiler.hooks.compile.tap('DemoWebpackPlugin', compilation => {
  10. console.log(compilation)
  11. })
  12. // 生成资源到 output 目录之前(异步)
  13. compiler.hooks.emit.tapAsync('DemoWebpackPlugin', (compilation, fn) => {
  14. console.log(compilation)
  15. compilation.assets['index.md'] = {
  16. // 文件内容
  17. source: function () {
  18. return 'this is a demo for plugin'
  19. },
  20. // 文件尺寸
  21. size: function () {
  22. return 25
  23. }
  24. }
  25. fn()
  26. })
  27. }
  28. }
  29. module.exports = demoWebpackPlugin
  1. webpack.config.js中使用该plugin ```javascript const path = require(‘path’) const DemoWebpackPlugin = require(‘webpack-demoWebpackPlugin.js’) module.exports = { // 省略其他代码 plugins:[
    1. new demoWebpackPlugin()
    ] }

```