webpack loader和plugin

適用webpack3。

loader

loader主要用於 預處理源文件,相似於構建工具中的 任務概念

開始一段簡單的loader編寫vue

  • 編寫一段js代碼,如
function loader (source) {
  var self = this;
  return source.replace(/<div(.*?)>/, function (str) {
    var value = convertStr(self.resource)
    return str.substring(0, str.length - 1) + ' data-source="' + value.substring(value.indexOf('src')) + '">'
  })
}

function convertStr (str) {
  return str.replace(/\\/g, function (v) {
    return '/'
  })
}

module.exports = loader;

其中source返回的是源文件內容或者上一個loader返回的內容。沒錯,loader能夠有多個,而且按照從後往前的順序執行。node

this是webpack的實例,this.resource得到當前的文件地址。webpack

  • 在webpack配置文件中,配置
resolveLoader: {
    modules: [
      path.resolve(__dirname, '../build/rules'),
      'node_modules'
    ]
  },

由於是本地自制的loader,須要聲明地址。默認會直接尋找node_modules中的loaderweb

{
        test: /\.vue$/,
        use: [
          {
            loader: 'vue-loader',
            options: vueLoaderConfig
          },
          {
            loader: 'vue-source-loader'
          }
        ]
      },

vue-loader一塊兒監聽.vue文件。vue-source-loader是第一個執行的loaderapi

plugin

plugin主要完成 loader沒法完成的事情

plugin的主要執行apply方法, 在plugin中存在不少hook鉤子,即生命週期app

閱讀webpack 全部的HOOK工具

  • 一個小栗子(完成後效果和上面的loader一致,可是十分複雜且不利於閱讀,僅供瞭解,由於是修改打包後的文件,定有不足之處)
function MixBase () {
}

MixBase.prototype.apply = function (compiler) {
  compiler.plugin('emit', function (compilation, callback) {
    var arr = new Set()
    compilation.chunks.forEach(function (chunk) {
      chunk.modules.forEach(function (module) {
        module.fileDependencies.forEach(function (filepath) {
          if (/\.vue$/.test(filepath)) {
            arr.add(filepath)
          }
        })
      })

      chunk.files.forEach(function (filename) {
        if (/\.js$/.test(filename)) {
          var source = compilation.assets[filename].source(),
            name = source.match(/name:[\'|\"](.*?)[\'|\"]/g),
            isApp = false,
            finalSource,
            componentsArr = []

          if (name) {
            for (var i = 0; i < name.length; i++) {
              var item = name[i].match(/name:[\'|\"](.*?)[\'|\"]/)[1]
              if (item === 'App') isApp = true
              componentsArr.push(item)
            }

            if (isApp) {
              finalSource = source.replace(/;return [a-z|A-Z]\([\"|\'](.*?);/, function (v) {
                return v.replace(/attrs:\{id:(.*?)\}/, function (k) {
                  return k.substring(0, k.length - 1) + ',"data-source":"src/app.vue"}'
                })
              })
            } else {
              finalSource = source.replace(/;return [a-z|A-Z]\([\"|\'](.*?),/, function (v) {
                var newStr
                for (var k of arr) {
                  if (k.indexOf(componentsArr[0]) !== -1) {
                    newStr = k.replace(/\\/g, function (str) {
                      return '/'
                    })
                    newStr = newStr.substring(newStr.indexOf('src'))
                  }
                }
                return v + '{attrs:{"data-source":"' + newStr + '"}},'
              })

              for (var j = 1; j < componentsArr.length; j++) {
                if (componentsArr[j].trim()) {
                  var reg = new RegExp(`,[a-z|A-Z]\\([\\"|\\']${componentsArr[j].toLocaleLowerCase()}(.*?)\\)`)
                  console.log(`,[a-z|A-Z]\\([\\"|\\']${componentsArr[j].toLocaleLowerCase()}(.*?)\\)`)
                  finalSource = finalSource.replace(reg, function (v) {
                    var newStr
                    for (var k of arr) {
                      if (k.indexOf(componentsArr[j]) !== -1) {
                        newStr = k.replace(/\\/g, function (str) {
                          return '/'
                        })
                        newStr = newStr.substring(newStr.indexOf('src'))
                      }
                    }
                    return v.substring(0, v.length - 1) + ',{attrs:{"data-source":"' + newStr + '"}})'
                  })
                }
              }
            }

            compilation.assets[filename] = {
              source: function () {
                return finalSource
              },
              size: function () {
                return finalSource.length
              }
            }
          }
        }
      })
    })
    callback()
  })
}

module.exports = MixBase
相關文章
相關標籤/搜索