webpack-Bundler源码编写(Dependencies Grapg)依赖图谱

之前我们分析出了分析文件(filename)的依赖和源代码,我们是对入口文件进行了分析,接下来我们要对整个工程进行分析:

bundler.js:

const fs=require('fs');
const path=require('path');
const parser=require('@babel/parser');
const traverse=require('@babel/traverse').default;
const babel=require('@babel/core');

const moduleAnalyser=(filename)=>{
    const content=fs.readFileSync(filename,'utf-8');
    const ast=parser.parse(content,{
        sourceType:'module'
    });
    let dependencies={};
    traverse(ast,{
        ImportDeclaration({node}){
            const dirname=path.dirname(filename);
            const newFile=path.join(dirname,node.source.value);
            dependencies[node.source.value]=newFile;
        }
    });
    const {code}=babel.transformFromAst(ast,null,{  // code--浏览器可以运行的代码
        presets:['@babel/preset-env']
    });
    return {
        filename,dependencies,code
    }
}

const makeDependenciesGraph=entry=>{    // entry--入口文件
    const entryModule=moduleAnalyser(entry);    // 入口
    let graphArray=[entryModule];
    // 递归分析依赖
    for(let i=0;i<graphArray.length;i++){
        const item=graphArray[i];
        const {dependencies}=item;
        if(dependencies){
            for(let j in dependencies){
                graphArray.push(moduleAnalyser(dependencies[j]));
            }
        }
    }
    console.log(graphArray);
}

输出:

[ { filename: './src/index.js',
    dependencies: { './message.js': 'src/message.js' },
    code:
     '"use strict";\n\nvar _message = _interopRequireDefault(require("./message.js"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }\n\nconsole.log(_message["default"]);' },
  { filename: 'src/message.js',
    dependencies: { './word.js': 'src/word.js' },
    code:
     '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n  value: true\n});\nexports["default"] = void 0;\n\nvar _word = require("./word.js");\n\nvar message = "say ".concat(_word.word);\nvar _default = message;\nexports["default"] = _default;' },
  { filename: 'src/word.js',
    dependencies: {},
    code:
     '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n  value: true\n});\nexports.word = void 0;\nvar word = \'hello\';\nexports.word = word;' } ]

以上可以看出index.js依赖message.js,message.js依赖word.js,这样我们就得到了正规项目的依赖及源代码,这就是依赖图谱。

现在依赖图谱是一个数组,后面打包的话不是特别容易,所以我们需要进行格式转换:

const makeDependenciesGraph=entry=>{    // entry--入口文件
    const entryModule=moduleAnalyser(entry);    // 入口
    let graphArray=[entryModule];
    // 递归分析依赖
    for(let i=0;i<graphArray.length;i++){
        const item=graphArray[i];
        const {dependencies}=item;
        if(dependencies){
            for(let j in dependencies){
                graphArray.push(moduleAnalyser(dependencies[j]));
            }
        }
    }
    let graph={};
    graphArray.forEach(item=>{
        graph[item.filename]={
            dependencies:item.dependencies,
            code:item.code
        }
    });
    console.log(graph);
}

输出:

{ './src/index.js':
   { dependencies: { './message.js': 'src/message.js' },
     code:
      '"use strict";\n\nvar _message = _interopRequireDefault(require("./message.js"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }\n\nconsole.log(_message["default"]);' },
  'src/message.js':
   { dependencies: { './word.js': 'src/word.js' },
     code:
      '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n  value: true\n});\nexports["default"] = void 0;\n\nvar _word = require("./word.js");\n\nvar message = "say ".concat(_word.word);\nvar _default = message;\nexports["default"] = _default;' },
  'src/word.js':
   { dependencies: {},
     code:
      '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n  value: true\n});\nexports.word = void 0;\nvar word = \'hello\';\nexports.word = word;' } }

这样我们就得到了对象形式的依赖图谱

posted @ 2020-02-20 16:45  金钩梨  阅读(283)  评论(0)    收藏  举报