💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# loader、plugin实现 https://juejin.cn/post/6995758595648258078 loader的特性 loader本质上是一个ESM模块,它导出一个函数,在函数中对打包资源进行转换 loader必须返回一段js代码,这样eval才能执行,否则会报错,多个loader,保证最后面一个返回js代码就行。 当配置多个loader时,loader的执行顺序时从右往左,右边的执行结果作为参数传到左边 ```js // less-loader把less转化成css,传给css-loader,css-loader把结果给style-loader,style-loader返回javascript代码字符串。 { test:/\.less$/, use:[ 'style-loader','css-loader','less-loader' ] } ``` - 如何保证各个loader按照预想方式工作? 使用 enforce 强制执行 loader 的作用顺序 ## **自定义loader** - webpack将loader加载后会将代码放到打包文件boundle.js中,一个loader对应一个(function(){}) 模块;所以在loader中需要导出 - webpack的打包文件boundle.js中,支持CommonJS的方式、ES Modules的方式导出 ```js // 比如:申明一个读取markdown文件内容的loader。 cosnt { getOptions } = require('loader-utils') // 获取loader的配置项option const marked = require('marked') module.exports = function(source){ const options = getOptions(this) //获取loader配置选项 const html = marked(source) //对输入内容进行处理 // 1、CommonJS的方式:输出的模块转换为字符串的形式return // return `module.exports = ${JSON.stringify(html)}` // 2、ES Modules:webpack内部会自动转换export default导出的代码 // return `export default ${JSON.stringify(html)}` return html //返回给下一个loader处理,如果不用给下一个loader处理需要保证返回js代码 } ``` # plugin原理 webpack插件是一个具有apply方法的JS对象,apply方法会被webpack compiler调用,并且在整个编译生命周期都可以访问compiler对象。 原理:通过在生命周期的钩子中挂载函数,来实现功能扩展。 >environment 环境准备好 compile编译开始 compilation编译结束 emit打包资源到output之前S afterEmit打包资源到output之后 原理 - plugin 必须是一个函数,或者包含apply方法的对象;compiler.hooks可以访问钩子 - apply 方法有一个参数 compiler; - 通过 compiler 可以给 webpack 编译打包过程中添加钩子; - 通过钩子的回调函数 callback 拿到打包结果对象 compilation(通过compilation.assets 获取资源文件信息); - 然后对打包结果对象 compilation 进行修改; ```js // 自定义plugin:功能:将js文件中的注释删除 class MyPlugin { apply (compiler){ // emit钩子的执行时机是:输出打包好的资源文件 asset 到 output 目录之前执行。 compiler.hooks.emit.tap('MyPlugin', compilation => { // compilation => 可以理解为此次打包的结果 // compilation.assets => 获取dist目录的所有生成的资源文件信息,例如:bundle.js for (const name in compilation.assets) { // 判断文件是否为js文件 -- 获取到资源的内容,例bundle.js if (name.endsWith('.js')) { const contents = compilation.assets[name].source() // const withoutComments = contents.replace(/\/\*\*+\*\//g, '') // 替换掉注释 compilation.assets[name] = { // 覆盖原有内容 --- 新的内容 以及新内容的大小 source: () => withoutComments, size:() => withoutComments.length } } } }) } } module.exports = MyPlugin ```