loader的作用

因为webpack是跑在node环境中,打包他只认识 .js 文件和 .json 文件,所以有一些其他的文件资源、比如图片、css等等这些文件就导致webpack无法识别、所以这个时候 loader 就出来了、准确的说他是文件处理器、针对webpack不认识的文件做转换、转换成webpack能够识别的内容!

loader的基础

在开始写自定义loader的时候我们需要了解下loader和loader加载机制、loader本质是导出一个函数,函数接收三个参数、同步模式直接通过return返回出去给下一个loader使用、而异步的话需要通过调用this.async()方法通知结束

  1. /**
  2. *
  3. * @param {string|Buffer} content 源文件的内容
  4. * @param {object} [map] 可以被 https://github.com/mozilla/source-map 使用的 SourceMap 数据
  5. * @param {any} [meta] meta 数据,可以是任何内容
  6. */
  7. function webpackLoader(content, map, meta) {
  8. // 同步模式直接return
  9. content += 'gf111'
  10. return content;
  11. // 异步调用this.async
  12. let callback = this.async()
  13. setTimeout( () =>{
  14. content += 'gf111';
  15. callback(null,content)
  16. },2000)
  17. }

loader的执行过程类似一个管道、A => B => C (有点像责任链模式哈)loader 一共有四种类型:同步loader 、异步loader、Raw-loader、Pitching-loader、然后讲下loader的执行顺序 loader总是从右往左执行,也就是说会最先执行最后的loader然后往上、在实际(右到左)执行过程中会先 从左到右调用loader上的pitch

loader类型

  • pre (前置)
  • normal(普通)
  • inline(内联)
  • post(后置)

    loader的类型可以通过 enforce 去配置、正常默认loader类型是普通(normal ) 四种loader执行优先级为 pre > normal > inline > post

image.png

loader执行流程

  • 总是右往左执行( 没有配置enforce )情况下
  • 右往左执行前,会先调用所有loader上的pitch方法、这个顺序是左往右

    创建loders文件夹下面三个a-loader.js、b-loader.js、c-loader.js

image.png

配置loader和loader加载路径

  1. module.exports = {
  2. entry: {
  3. 'main':'./src/main.js'
  4. },
  5. devtool: 'inline-source-map',
  6. devServer: {
  7. static: 'dist',
  8. compress: true,
  9. port: 9000
  10. },
  11. mode: 'development',
  12. resolveLoader: {
  13. modules: ['node_modules','build/laoders'], // build/loaders 配置自定义loader路径
  14. extensions: ['.js', '.json'],
  15. mainFields: ['loader', 'main']
  16. },
  17. module:{
  18. rules:[
  19. {
  20. test: /\.js$/,
  21. use:['a-loader']
  22. },
  23. {
  24. test: /\.js$/,
  25. use:['b-loader']
  26. },
  27. {
  28. test: /\.js$/,
  29. use:['c-loader']
  30. },
  31. ]
  32. }
  33. }

执行的顺序

image.png
image.png

我们发现我们按rules正常写loader的执行顺序是右往左、那我们试试在每个loader里面添加 pitch 方法

  1. // Aloader
  2. function Aloader(content, map, meta){
  3. return content;
  4. }
  5. Aloader.pitch = function(a,b,c){
  6. console.log('a-loader---pitch')
  7. }
  8. // Bloader
  9. function Bloader(content, map, meta){
  10. return content;
  11. }
  12. Bloader.pitch = function(){
  13. console.log('b-loader---pitch')
  14. }
  15. // Cloader
  16. function Cloader(content, map, meta){
  17. return content;
  18. }
  19. Cloader.pitch = function(a,b,c){
  20. console.log('c-loader---pitch')
  21. }

image.png
image.png

串行loader和pitch阶段

image.png

获取loader参数(this.getOptions)

  1. // webpack.config.js
  2. {
  3. test: /\.js$/,
  4. use:{
  5. loader:"a-loader",
  6. options:{
  7. name:'1111'
  8. }
  9. }
  10. }
  11. // loader
  12. function Aloader(content, map, meta){
  13. console.log("getOptions",this.getOptions()) //获取参数
  14. return content;
  15. }
  16. module.exports = Aloader

异步(this.async)内容返回和同步

同步就很简单、直接在方法里面return出去、而异步得话是需要通过this.async 告诉 loader-runner当前loader是一个异步

  1. function Bloader(content, map, meta){
  2. const cb = this.async()
  3. setTimeout( () =>{
  4. cb(null, content + ';const asyncs = 1111;') // 最后会等待异步结束后执行打包
  5. },2000)
  6. }