当前位置:   article > 正文

【webpack自定义插件】实现一个webpack自定义插件_webpack里面的插件是怎么实现的

webpack里面的插件是怎么实现的

webpack插件相信很多前端开发都使用过,但是实际开发中需要自定义一个webpack插件的情况也有很多,试想着这样一个开发场景: 我们想知道在一个项目中都有哪些文件或者模块引用了某一个组件,难道要通过搜索一个一个文件去代码里找吗?有没有更简便的方法实现它?

        本文通过实现一个webpack自定义插件,来输出在一个项目中所有引用某一个模块的功能。(基于webpack v5.75.0/webpack-cli 5.0.1,本文的主要目的是梳理自定义插件的思路和方法,建立webpack插件开发使用体系,建议在开发中不要直接copy该组件使用,而是根据实际的业务和对应版本webpack的api自行开发)

如图在项目中,src底下有3个js文件

index.js

  1. import { age } from './tapable';
  2. import foo from './test';
  3. foo(); // foo如果执行了将会在test.txt中打印两个index的路径,即被引用了两次
  4. console.log(age)

tapable.js

  1. export const age = '5656';
  2. import foo from './test';

test.js

  1. export default function foo() {
  2. console.log('test组件')
  3. }

可以看到,其中test.js文件被index.js和tapable.js组件引用。

webpack.config.js的plugins配置如下:

这里jsFilePath就是我需要查询index.js被哪些模块引用;

addText:表示是否需要生成一个文件来记录这些输出地址

outPath:表示文件的输出地址和文件名

  1. plugins: [
  2. new FindDepsPlugin({
  3. jsFilePath: path.resolve(__dirname, 'src/test.js'), // 需要查询的文件路径
  4. addText: true, // 是否生成.txt文件
  5. outPath: './dist_my/public/test.txt' // 生产的文件地址和路径
  6. })
  7. ],

其中FindDepsPlugin就是我们要自定义的插件,jsFilePath,addText,outPath参数定义已经在上述代码中标明。

接下来定义FindDepsPlugin插件,设计思路如下:

        1.在插件的 apply 方法中,通过 compilation.hooks.optimizeChunkAssets 钩子获取到所有已优化过的 chunk 对象。

         2.遍历每个 chunk 的模块依赖关系(可以使用 chunk.getModules() 方法),找到所有的模块对象。

        3.找出这些模块的引用部分dependencies,通过compilation.moduleGraph.getModule(dep).resource获取以来的源路径,判断模块所有的依赖列表中是否含有jsFilePath,如果有就把该模块收集起来

        4.记录下这些模块的源文件路径(可以使用 module.resource 属性获取)。

        5.在 compiler.hooks.done 钩子中输出这些记录下来的源文件路径。

find-deps-Plugin.js

  1. const fs = require('fs')
  2. const path = require('path')
  3. class FindDepsPlugin {
  4. constructor(options = {}) {
  5. this.jsFilePath = options.jsFilePath || ''
  6. this.outPath = options.outPath || './test.txt';
  7. this.addText = options.addText || false;
  8. this.deps = []
  9. }
  10. apply(compiler) {
  11. compiler.hooks.compilation.tap('FindDepsPlugin', compilation => {
  12. compilation.hooks.optimizeChunkAssets.tapAsync(
  13. 'FindDepsPlugin',
  14. (chunks, callback) => {
  15. chunks.forEach(chunk => {
  16. const modules = chunk.getModules();
  17. const isHasPath = modules.find(item => item.resource && item.resource === path.resolve(this.jsFilePath));
  18. // 如果输入的jsFilePath参数是有效的
  19. if (isHasPath) {
  20. // 用来收集依赖模块中含有jsFilePath的module
  21. const list = [];
  22. modules.forEach(module => {
  23. (module.dependencies || []).forEach(dep => {
  24. const depResource = compilation.moduleGraph.getModule(dep) && compilation.moduleGraph.getModule(dep).resource;
  25. if (depResource === path.resolve(this.jsFilePath)) {
  26. // 判断模块所有的依赖列表中是否含有jsFilePath,如果有就把该模块收集起来
  27. list.push(module);
  28. }
  29. });
  30. });
  31. const depModules = list.map(module => module.resource);
  32. this.deps.push(...depModules)
  33. }
  34. })
  35. callback()
  36. }
  37. )
  38. })
  39. compiler.hooks.done.tap('FindDepsPlugin', () => {
  40. console.log(`"${this.jsFilePath}" 组件被以下文件所引用:`)
  41. // 为了解决循环引用的问题,需要对this.deps进行去重处理
  42. this.deps = [...new Set(this.deps)];
  43. this.deps.forEach(dep => {
  44. console.log(dep)
  45. });
  46. if (this.addText) {
  47. fs.writeFile(this.outPath, this.deps.join('\n'), 'utf8', err => {
  48. if (err) {
  49. console.log('err', err);
  50. return
  51. }
  52. console.log('写入文件成功')
  53. });
  54. }
  55. })
  56. }
  57. }
  58. module.exports = FindDepsPlugin;

验证下输出:

 可以看到在终端中输出了index和tapable的路径

而 outPath参数对应的./dist_my/public文件夹中多了一个test.txt文件,输出的也是index和tapable的路径

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/793650
推荐阅读
相关标签
  

闽ICP备14008679号