内容简介:loader是导出为一个函数的node模块。该函数在loader转换资源的时候调用。给定的函数将调用loader API,并通过this上下文访问。pre => normal => inline => postloader执行首先会加载pitch-loader(书写loader的顺序),然后加载资源resource,最后执行normal-loader(正常加载loader的顺序) 如果pitch-loader有返回值,则会跳过后面的加载,直接走到上一层的normal-loader里面。
loader是导出为一个函数的node模块。该函数在loader转换资源的时候调用。给定的函数将调用loader API,并通过this上下文访问。
function loader(source){ return source } loader.pitch = function(){ console.log('pitch') } module.exports = loader 复制代码
加载自定义loader的几种方式
- 匹配单个loader(使用绝对路径)
{ test:/\.js$/, use:[ loader:path.resolve('path/loaderjs'), options ] } 复制代码
- alias
resolveLoader:{ alias:{ 'loader1':path.resolve('path/loader1') } }, module:{ rules:[ { test:/\.js$/, use:[ loader:loader1, options ] } ] } 复制代码
- 配置多个loader
resolveLoader:{ modules:[ path.resolve('node_modules'), path.resolve(__dirname, 'src', 'loaders') ] } 复制代码
loader的分类
- 在前面 pre
- 正常 normal
- 在后面 post
loader的顺序
pre => normal => inline => post
// index.js 加载顺序为 pre + normal + inline + post let str = require('inline-loader!./a.js') // index.js 加载顺序为 inline + post // -! 不会让文件 再去通过pre+normal loader 来处理了 // ! 没有normal // !! 什么都没有 只有自身 let str = require('-!inline-loader!./a.js') 复制代码
loader的组成
loader执行首先会加载pitch-loader(书写loader的顺序),然后加载资源resource,最后执行normal-loader(正常加载loader的顺序) 如果pitch-loader有返回值,则会跳过后面的加载,直接走到上一层的normal-loader里面。
- pitch-loader
- normal-loader
loader的特点
- 最后加载的loader必须返回一个js脚本
- 每一个loader都是一个模块
- 每一个loader都是无状态的,确保loader在不同模块转换之间不保存状态。
各种loader的实现
babel-loader
需要安装@babel/core、@babel/preset-env
let babel = require('@babel/core'); <!--loader 的 工具 库--> let loaderUtils = require('loader-utils') function loader(source){ <!--处理异步--> let cb = this.async(); <!--this loaderContext--> let options = loaderUtils.getOptions(this); <!--babel 转化源码--> babel.transform(source,{ ...options, sourceMap:true, filename:this.resourcePath.split('/').pop() // 文件名 },function(err,result){ cb(null,result.code,result.map) }) } module.exports = loader 复制代码
banner-loader
use:{ loader:'banner-loader', options:{ text:'xx', filename:path.resolve(__dirname,'banner.js') } } 复制代码
let loaderUtils = require('loader-utils') let fs = require('fs') <!--验证传递参数--> let validateOptions = require('schema-utils') function loader(source){ <!--添加缓存--> this.cacheable && this.cacheable() let options = loaderUtils.getOptions(this) let cb = this.async(); let schema = { type:'object', properties:{ text:{ type:'string' }, filename:{ type:'string' } } } validateOptions(schema,options,'banner-loader') if(options.filename){ <!--添加监听 当文件内容变化 自动打包--> this.addDependency(options.filename) fs.readFile(options.filename,'utf8',function(err,data){ cb(err,`/**${data}**/${source}`) }) }else{ cb(null,`/**${options.text}**/${source}`) } } module.exports = loader 复制代码
file-loader && url-loader
import p from './public.jpg' let img = document.createElement('img'); img.src = p; document.body.appendChild(img) 复制代码
file-loader
- 现将图片生成一个md5 发射到dist目录下
- 然后返回当前图片的路径
// file-loader let loaderUtils = require('loader-utils') function loader(source){ <!--生成md5文件--> let filename = loaderUtils.interpolateName(this,'[hash].[ext]',{content:source}) this.emitFile(filename,source) return `module.exports = "${filename}"` } // 将source 转化为二进制buffer loader.raw = true module.exports = loader // url-loader let loaderUtils = require('loader-utils') let mime = require('mime') function loader(source){ let {limit} = loaderUtils.getOptions(this); if(limit && limit > source.length){ return `module.exports = "data:${mime.getType(this.resourcePath)};base64,${source.toString('base64')}"` }else{ return require('./file-loader').call(this,source) } } loader.raw = true; module.exports = loader; 复制代码
less-loader && style-loader && css-loader
// less-loader let less = require('less') function loader(source){ let css; less.render(source,function(err,r){ css = r.css }) // 交给css-loader处理 return css; } module.exports = loader // style-loader function loader(source){ } loader.pitch = function(request){ // 这个request的就是当前路径 没有包含当前 // css-loader less-loader console.log(request); let script = ` let style = document.createElement('style'); <!--返回相对路径 只执行行内loader--> style.innerHTML = require(${loaderUtils.stringifyRequest(this, '!!' + request)}); document.head.appendChild(style); ` // 返回的结果 会在浏览器中运行 return script; } module.exports = loader // css-loader // css-loader的作用就是把所有url的内容 都变成require('文件名的形式') function loader(source) { let reg = /url\((.*?)\)/g; let current; let pos = 0; let arr = [`let lists = []`]; while (current = reg.exec(source)) { //lastIndex // 数组类型 [匹配的字符串,分组中的内容] let [matchUrl, p] = current; let index = reg.lastIndex - matchUrl.length // lastIndex就是匹配结束的位置 arr.push(`lists.push(${JSON.stringify(source.slice(pos, index))})`); arr.push(`lists.push("url("+require(${p})+")")`) pos = reg.lastIndex; } arr.push(`lists.push(${JSON.stringify(source.slice(pos))})`); arr.push(`module.exports = lists.join('')`); console.log(arr.join('\r\n')); return arr.join('\r\n'); } module.exports = loader; 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
产品经理的20堂必修课
徐建极 / 人民邮电出版社 / 2013-9-1 / 59.00元
《产品经理的20堂必修课》以作者八年的产品经理工作实践为基础,通过系统的理论结合丰富的实例的方法,全面地总结了作为一名互联网产品经理所应掌握的知识。 《产品经理的20堂必修课》分为三大部分。 讲产品:深入剖析互联网产品成功的要素,分别从需求导向、简单原则、产品运营、战略布局等维度,分析如何让产品在残酷的互联网竞争中脱颖而出。 讲方法:着重分析优秀的产品团队运作的工作方法和程序,详......一起来看看 《产品经理的20堂必修课》 这本书的介绍吧!