# webpack配置 TODO

# loader

loader (opens new window)webpack的核心概念之一,它的基本工作流是将一个文件以字符串的形式读入,对其进行语法分析及转换(或者直接在loader中引入现成的编译工具,例如sass-loader中就引入了node-sassSCSS代码转换为CSS代码,再交由css-loader处理),然后交由下一环节进行处理。

所有载入的模块最终都会经过moduleFactory处理,转成js可以识别和运行的代码,从而完成模块的集成。

也就是说,其实webpack只能处理js,但有了loader,它可以预处理文件,就可以打包除js外的所有静态资源了。

在写法上,它使用nodejs开发,只是一个导出为函数的js模块,loader runner会调用这个函数,然后把上一个loader产生的结果或者资源文件(resource file)传入进去。函数的this上下文将由webpack填充,并且loader runner具有一些有用方法,可以使loader改变为异步调用方式,或者获取query参数。

平时我们使用loader是这样的:

use: [
  'a-loader',
  'b-loader',
  'c-loader'
]

它的执行顺序其实是这样的:

|- a-loader `pitch`
  |- b-loader `pitch`
    |- c-loader `pitch`
      |- requested module is picked up as a dependency
    |- c-loader normal execution
  |- b-loader normal execution
|- a-loader normal execution

如果某一个loaderpitch函数返回了某个结果,则会跳过下面的loader

例如,假设b-loaderpitch这样返回了:

module.exports = function(content) {
  return someSyncOperation(content);
};

module.exports.pitch = function(remainingRequest, precedingRequest, data) {
  if (someCondition()) {
    return "module.exports = require(" + JSON.stringify("-!" + remainingRequest) + ");";
  }
};

上面的步骤将被缩短为:

|- a-loader `pitch`
  |- b-loader `pitch` returns a module
|- a-loader normal execution

cache-loader就是这个原理,会把编译结果进行缓存。

对于不考虑pitchloader而言,可以简单理解为是从后往前执行的。

单一职责

loader支持链式调用,所以开发上需要严格遵循单一职责原则,即每个loader只负责自己需要负责的事情:

将输入信息进行处理,并输出为下一个loader可识别的格式。

# plugin

plugin也就是插件,插件的能力与loader解析转换文件不一样,它可以各种方式自定义webpack的构建过程。 其实就是不同的生命周期提供了大批量的钩子函数,可以有同步、异步不同的处理,方便我们在构建过程中进行额外操作。

目前webpack已经提供了丰富的插件 (opens new window),已经可以满足大部分需求。

像最常用的是html-webpack-plugin,如果要用页面访问服务的话,几乎都会使用到它,它会从入口文件开始,把所有引用到的jscss都注入到模板页面上。

其它处理js压缩、css压缩、代码分割、dll预编译、md5-hash、资源复制、清除等,应有尽有。如果满足不了你的需求,就自己实现一个。

在插件开发中,常用的有2个对象:CompilerCompilation,名字有些像,有什么区别呢?

Compiler对象包含了webpack环境所有的配置信息,包含optionsloadersplugins,在webpack启动时候被实例化,是全局唯一的。我们可以把它理解为webpack的实列。开发时,我们可以从中拿到所有和webpack主环境相关的内容。

Compilation对象包含了当前的模块资源、编译生成资源、文件的变化等。当webpack在开发模式下运行时,每当检测到一个文件发生改变的时候,那么一次新的Compilation将会被创建,从而生成一组新的编译资源。最显著的特征是涉及变化的文件会触发对应的loader运行。

二者的区别是:Compiler代表了是整个webpack从启动到关闭的生命周期; Compilation只代表了一次新的编译。

以下常见的事件钩子:

钩子 作用 参数 类型
after-plugins 设置完一组初始化插件之后 compiler sync
after-resolvers 设置完 resolvers 之后 compiler sync
run 在读取记录之前 compiler async
compile 在创建新 compilation之前 compilationParams sync
compilation compilation 创建完成 compilation sync
emit 在生成资源并输出到目录之前 compilation async
after-emit 在生成资源并输出到目录之后 compilation async
done 完成编译 stats sync

plugin与loader的区别

loader是一个转换器,将A文件进行编译成B文件,属于单纯的文件转换过程。 plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后、webpack 打包的整个过程。它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务。

# 热更新 TODO

热更新是webpack的一项非常有效的能力,大大提高了我们的开发效率。 从名字上看也能理解,修改代码后,不需要刷新浏览器,就可以直接在页面上看到更改后的内容。