webpack之打包原理分析

91 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

流程

接收webpack的配置进行读取;

  • 入口 从那个文件开始->那些是依赖模块的位置->内容:对内容的处理,处理成浏览器正常解析的->递归处理其他依赖模块->生成chunk代码片段->补齐函数,生成bundle文件的内容->启动函数

  • 出口 生成资源文件的名称和位置

  • 核心功能 根据入口模块开始分析依赖路径,对内容进行处理,支持es6+To es5的语法转换,返回模块路径,依赖和相应的处理

分析

  • webpack在执行npx webpack进行打包后,都干了什么事情
var installedModules = {};
function __webpack_require__(moduleId) {
if (installedModules[moduleId]) {
    return installedModules[moduleId].exports;
}
var module = (installedModules[moduleId] = {
    i: moduleId,
    l: false,
    exports: {}
});
modules[moduleId].call(
  module.exports,
    return module.exports;
  }
return __webpack_require__((__webpack_require__.s = "./index.js"));
})

大概的意思是:我们实现了一个webpack_require来实现自己的模块化,把代码都缓存在installedModules里,代码文件以对象传递进来,key是路径,value是包裹的代码字符串,并且代码内部的require,都被替换成webpack_require

  • 实现bundle.js
  1. 模块分析:读取入口文件,分析代码
const fs = require("fs");
const fenximokuai = filename => {
 const content = fs.readFileSync(filename, "utf-8");
};

拿到文件中的依赖,不推荐使用字符串截取,推荐使用@babel/parser,这个是babel7的工具,来给我们解析内部的语法比如es6、返回一个ast抽象语法树

  1. 安装@babel/parser

npm i @babel/parser --save 接下来我们就可以根据body里面的分析结果,遍历出所有的引入模块,但是比较麻烦,这里还是推荐babel推荐的一个模块@babel/traverse帮我们处理 npm i @babel/travers --save

const fs = require("fs");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const fenximokuai = filename => {
 const content = fs.readFileSync(filename, "utf-8");
 const Ast = parser.parse(content, {
 sourceType: "module"
 });
};

分析ast抽象语法树,根据需要返回对应的数据,根据结果返回对应的模块,定义一个数组,接收一下node.source.value的值

var arr = []
traverse(Ast, {
    ImportDeclaration({ node }) {
        arr.push(node.source.value);
    }
});

最后

最后我们把代码处理成浏览器可运行的代码,需要借助@babel/core,和@babel/preset-env,把ast语法树转换成合适的代码

const babel = require("@babel/core");
const { code } = babel.transformFromAst(Ast, null, {
 presets: ["@babel/preset-env"]
});

参考资料

babel/parser