配置文件中的loader配置
可以根据配置文件匹配到到规则,去执行相应的loader。
// analyze.config.js// 引入loaderconst jsloader = require('./lib/jsloader')const jsonloader = require('./lib/jsonloader')const cssloader = require('./lib/cssloader')const htmlloader = require('./lib/htmlloader')const signloader = require('./lib/signloader')const config = { entry: './', output: { name: 'dist', src: './' }, module: [ { test: /\.js$/, loader: [signloader, jsloader], }, { test: /\.wxss$/, loader: [cssloader], outputpath: (outputpath) => outputpath.replace('.wxss', '.acss') }, { test: /\.wxml$/, loader: [htmlloader], outputpath: (outputpath) => outputpath.replace('.wxml', '.axml') }, { test: /\.json$/, loader: [jsonloader], }, ]}module.exports = config
具体loader实现
以jsloader为例子,接收源码作为参数,返回编译后获得的新的源码
// 前几篇中封装的js转换器const jsparser = require('./jsparser')function loader(source) { const jsparser = new jsparser() let ast = jsparser.parse(source) ast = jsparser.astconverter(ast) return jsparser.asttocode(ast)}module.exports = loader
不同文件选择对应loader
// 重写analyze函数中的analyzefiletoloard文件分析部分function analyze(filepath, outputpath){ if (fs.statsync(filepath).isdirectory()) { const files = fs.readdirsync(filepath) files.foreach(file => { const currentfilepath = filepath+'/'+file const currentoutputpath = outputpath+'/'+file if(fs.statsync(currentfilepath).isdirectory()) { fs.mkdirsync(currentoutputpath) analyze(currentfilepath, currentoutputpath) } else analyzefiletoloard(currentfilepath, currentoutputpath) }) } else analyzefiletoloard(filepath, outputpath)}
function analyzefiletoloard(inputpath, outputpath) { let source = readfile(inputpath) // 读取源码 const loaders = config.module loaders.foreach(loader => { // 遍历配置文件,看是否有匹配文件的loader规则 if (loader.test.test(inputpath)) { // 使用loader source = useloader(source, loader.loader, outputpath) // 输出路径处理函数 if (loader.outputpath) outputpath = loader.outputpath(outputpath) } }) writefile(outputapppath(outputpath), source) // 将处理过后的源码写入文件}
loader过滤和执行
loader执行是个逆序的执行,从右边向左依次执行。在这里我们先用同步的loader来做讨论。
loader执行前还有个pitch阶段,感觉pitch这个起名方式并不是特别合适,我更愿意叫它过滤筛选阶段。先去顺序执行loader上的pitch方法,要是pitch有返回值,就不再执行在该loader之前执行的loader。
function useloader(source, loaders = []) { // 执行loader存储列表 const loaderlist = [] // 递归去筛选需要执行的loader function loaderfilter(loaders) { const [firstloader, ...ortherloader] = loaders if (loaders.length === 0) return // 执行pitch,并将剩余的loader传入作为参数 if (firstloader.pitch && firstloader.pitch(ortherloader)) return ortherloader else { // 将可用loader加入待执行列表 loaderlist.push(firstloader) // 剩余loader作为参数 递归调用 loaderfilter(ortherloader) } } // 大概,暂时用不到。。。 const remainloader = loaderfilter(loaders) // 同步loader逆序执行 function runloader(source, loaderlist) { const loader = loaderlist.pop() let newsource = loader(source) if (loaderlist.length > 0) return runloader(newsource, loaderlist) else return newsource } source = runloader(source, loaderlist) return source}
实验
写个signloader,看看loader能不能像我们想的那样逆序执行
function loader(source) {let sign = `/*** @author: ly*/` source = sign + source return source}module.exports = loader
结果:
这样简易的loader部分算是完成了,但这么写只能执行一些同步的loader,异步的loader无法等待执行完成后再写入。
相关学习推荐:小程序开发教程
以上就是微信小程序转换器之 loader设计实现的详细内容。
