適用webpack3。
loader主要用於預處理
源文件,相似於構建工具中的任務
概念
開始一段簡單的loader
編寫vue
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
resolveLoader: { modules: [ path.resolve(__dirname, '../build/rules'), 'node_modules' ] },
由於是本地自制的loader,須要聲明地址。默認會直接尋找node_modules
中的loader
。web
{ test: /\.vue$/, use: [ { loader: 'vue-loader', options: vueLoaderConfig }, { loader: 'vue-source-loader' } ] },
和vue-loader
一塊兒監聽.vue
文件。vue-source-loader
是第一個執行的loader
api
plugin主要完成
loader
沒法完成的事情
plugin的主要執行apply
方法, 在plugin中存在不少hook
鉤子,即生命週期app
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