loader是一个作为函数导出的node模块。当加载程序转换资源时调用此函数。给定的函数将调用加载器API,通过this上下文访问。Webpack的配置离不开loader。官方文档也介绍了如何写一个loader。本文将通过手写一些常用的loader来加深对loader的理解,提高工作中的开发效率。ExportloaderLoader是一个函数,接受匹配的文件资源字符串和SourceMap。我们可以修改文件内容的字符串,返回给下一个loader处理:module.exports=function(source,map){returnsource;}准备工作为了方便我们写loader,我们先准备webpack环境:生成一个package.json:npminit-yinstallwebpack:npminstallwebpackwebpack-D创建一个webpack.config.js文件,输入如下内容://webpack.config.jsconstpath=require('path')module.exports={模式:'开发',条目:'./src/index.js',输出:{文件名:'bundle.js',路径:路径。resolve(__dirname,'dist')}}package.jsonaddscriptscommand:"scripts":{"build":"webpack","dev":"webpack--watch"},我们知道的配置别名,webpack会默认在node_modules中找到对应的loader,不方便我们调试。我们可以通过将resolveLoader属性添加到webpack.config.js来将加载器指向我们创建的加载器文件夹.../loaders"),],}...创建一个loaders文件夹,里面会存放我们自己的loader:mkdirloaders另外,还可以通过resolveLoader.alias配置loadersAlias:resolveLoader:{alias:{loader1:resolve(__dirname,"./loaders/loader1.js"),loader2:resolve(__dirname,"./loaders/loader2.js"),loader3:resolve(__dirname,"./loaders/loader3.js"),},},模块:{rules:[{test:/\.(js)$/,use:["loader1.js","loader2.js","loader3.js]}]}第一个loader是写一个简单的loader练习自己动手,前面说了loader可以替换目标资源文件的内容,这里我想把项目里面的console.log全部干掉,毕竟项目上线的时候console里的调试内容是不合适的.在loaders文件夹下创建一个cleanlog-loader.js,输入如下:module.exports=function(source){returnsource.replace(/console\.log\(.*\);?\n/g,'');}在webpack.config.js中加入配置:module:{rules:[{test:/\.(js)$/,use:"cleanlog-loader"}]}在src下新建index.js文件夹并写入一些控制台内容,然后在控制台执行npmrunbuild,可以发现编译后的文件dist/bundle.js没有控制台信息。banner-loaderbanner-loader可以在脚本文件中添加评论信息,配置方法如下:module:{rules:[{test:/\.(js)$/,use:{loader:"banner-loader",options:{text:"/****buildfromchenwl****/",}}}]}这里有两个地方需要考虑:获取配置信息loader-utils检查配置参数是否正确schema-utils在loaders文件夹下创建banner-loader.js,输入以下内容:constfs=require("fs");const{resolve}=require("path");constloaderUtils=require("loader-utils");const{validate}=require("schema-utils");module.exports=function(source){//获取配置参数letoptions=loaderUtils.getOptions(this);letschema={type:"object",properties:{text:{type:"string"}}}//验证参数是否正确validate(schema,options,"banner-loader")return`${options.text}${source}`;}当然也可以写成读取文件内容Input,新增配置参数filename读取模板文件:if(options.filename){//依赖a某些文件更改实现实时更新;this.addDependency(path.resolve(__dirname,`../${options.filename}`))再转fs.readFileSync(options.filename,"utf-8")+source;}使用addDependency,如果目标文件发生变化,可以在watch模式下重新编译,使用npmrundev启动并修改对应的文件名试试babel-loaderbabel-loaderdependson@babel-coreand@babel/preset-env,first通过npm安装:npminstall@babel-core@babel/preset-env-Dwebpack-config.jsaddrules:{test:/\.(js)$/,use:[{loader:"babel-loader",options:{presets:["@babel/preset-env"],},},]}可以在this.async方法中使用在loader中写异步代码://babel-loader.jsconstloaderUtils=require("loader-utils");constbabel=require("@babel/core");module.exports=function(source){constoptions=loaderUtils.getOptions(this);constcb=this.async();//异步函数babel.transform(source,{...options,sourceMaps:true},function(err,result){cb(err,result.code)})}style-loader和less-loader//less-loaderletless=require("less");module.exports=function(source){letcssStr="";//使用less转换为cssless.render(source,function(error,result){if(!error){cssStr=result.css}});returncssStr}//style-loadermodule.exports=styleLoader(source){//js字符串,生成一个style标签插入到模板文件中letcode=`letstyleEl=document.createElement("style");styleEl.innerHTML=${JSON.stringify(source)};document.head.appendChild(styleEl);`;returncode.replace(/\/n/,"");}file-loader我们知道webpack无法识别js以外的其他文件,所以file-loader需要设置loader.raw=true,让loader知道它正在处理二进制内容:constloaderUtils=require("loader-utils");functionfileLoader(source){//interpolate插值letfileUrl=loaderUtils.interpolateName(this,"[hash].[ext]",{content:来源,});this.emitFile(fileUrl,source);//转换后的Buffer最终会被插入到页面中,返回类型只能是buffer或者string//fileUrl记得加引号,否则会报错return`module.exports='${fileUrl}'`}//loader处理二进制内容fileLoader.raw=true;module.exports=fileLoader;url-loaderurl-loader最重要的是把小图转成base64编码,否则会用file-loader处理://url-loader.jsconstloaderUtils=require("loader-utils");constmime=require("mime");functionurlLoader(source){让{limit}=loaderUtils.getOptions(this);if(limit>source.length){letcode=`data:${mime.getType(this.resourcePath)};base64,${source.toString('base64')}`return`module.exports="${code}"`}else{returnrequire("./file-loader").call(this,source)}}urlLoader.raw=true;module.exports=urlLoader;
