zoukankan      html  css  js  c++  java
  • Webpack——webpack的编译原理

    转自:https://mp.weixin.qq.com/s/y_l49Ak3QqmTTkxVzHWgew

    webpack 的作用就是根据入口文件将 源代码编译(构建,打包)成最终代码,中间经过 webpack 打包,打包的过程就是 编译。

       整体的过程分为三个步骤:初始化编译(最重要),输出

     

    初始化

      在初始化这个阶段 webpack 会将 CLI 参数配置文件默认配置进行融合,形成一个最终的配置对象。

    CLI 参数:使用命令行工具,可能会添加一些参数进去,如:

    npx webpack --mode=development --config xxx

    配置文件:webpack.config.js 文件里面的配置

    默认配置:比如入口文件 entry , 默认为 ./src/index.js

    对配置的处理过程是依托于一个第三方的库 yargs 完成的,yargs 库就是融合配置的,初始化阶段相对比较简单,主要是为了接下来的编译阶段做准备

    目前,可以理解为:初始化阶段主要的作用是用于产生一个最终的配置。

    编译阶段:

    1. 创建chunk

      chunk webpack 内部构建过程中的一个概念,它译为 “块”,是指通过某个入口 找到的所有依赖的统称,比如说:入口模块(./src/index.js),依赖a 模块(./src/a.js),a 模块又依赖 b(./src/b.js)模块,通过一个入口模块分析依赖关系,可以找到三个模块。那么index。js,a.js,b.js这三个就统称为一个chunk.

      根据入口模块插件一个chunk,每一个chunk都是有名字的,意味着 chunk 有可能也会有多个,入口文件是可以有多个的。

     

      默认情况下只有一个chunk,每个chunk 都有至少两个属性:

      * name:默认为 mian;

      * id: 唯一编号,如果是开发环境,那么 id 和 name 相同,如果是生产环境,则是一个数字,从 0 开始。

    2.构建所有的依赖模块

     我们通过下面的代码来简单过一遍这个图:

    代码:

    //模块名:
    ./src/index.js (未加载状态)
    
    //模块内容:
    console.log("index");
    require("./a");
    require("./b");

    第一步:根据入口模块文件(./src/index.js)进行构建,模块文件是有一个路劲的,入口模块文件的路径就是./src/index.js,他会通过这个路径检查这个模块是否已经加载过,注意:它不是运行模块,而是看一眼,看看模块记录表(上面图中的蓝色部分),有没有这个模块,如果有的话就表示当前这个模块已经被加载过,如果没有的话就表示他没有被加载过。

    第二步:如果说模块记录表中有记录,说明这个模块已经加载过了,如果没有记录,就继续走下一步,说明该模块需要加载。

    第三步:读取模块里面的内容,里面的内容其实就是一个字符串

    //读取内容(字符串)
    console.log("index");
    require("./a");
    require("./b");

    第四步:对模块里面的内容进行语法分析,树形结构遍历,找到所有的 依赖,最后找到生成AST 抽象语法树。

    require("./a");
    require("./b");

    第五步:将分析出来的依赖记录到dependencies 数组中

    //记录依赖
    ["./src/a.js","./src/b.js"]

    第六步:替换依赖函数,什么意思呢?就是把有依赖的地方变一种代码格式,将require 改为 _webpack_require ,将 依赖的模块  改为 模块id。

    console.log("index");
    _webpack_require("./src/a.js");
    _webpack_require("./src/b.js");

    第七步:我们将替换后的代码称为转化后的代码,并且把他保存到模块记录中。

    第八步:index.js 模块处理完成,由于 index.js 依赖其他的模块,所以递归循环保存在 dependencies 数组中的依赖,开始分析 ./src/a.js 模块,从头再走一遍这个流程就可以了,假设 a 模块依赖./src/b.js 模块,那么它会等 a 模块处理完成后,再处理a 模块所依赖的b模块,再最后处理 index.js 依赖的b 模块,此时他发现 b 模块在处理 a 模块所依赖的b 模块已经加载过了,那么index.js 模块所依赖的 b 模块是不会进行下一次处理,直接结束。

    上面就是webpack 的编译过程,做这一切的最终目的就是为了形成一个模块记录表

    下面这个简图,就是上述编译过程之后会在chunk 中通过入口文件加载形成多个模块,每个模块记录了转换之后的代码。

    3.生成chunk assets 

      在第2步完成后,chunk中会产生一个模块列表,列表中包含了模块id 和 模块转换之后的代码,接下来,webpack 会根据配置为 chunk 生成一个资源列表,即 chunk assets,资源列表可以理解为是生成到最终文件的文件名和文件内容。

      chunk hash: 是根据所有的 chunk assets 的所有内容是生成的一个 hash 字符串

      hash :一种算法,具体有很多类,特点是将一个任意长度的字符串转化为一个固定长度的字符串,而且可以保证原始内容不变,生成的hash 字符就不变。

    简图:

     4. 合并 chunk assets 

      将多个chunk 的assets 合并到一起,并产生一个总的 hash 

     

     

    输出 emit 

      webpack 将利用 node 中的 fs 模块(文件处理模块),根据编译产生的总的 assets ,生成相应的文件,

    总过程:

      

     当敲下webpack打包命令之后,文件开始初始化,各个参数进行融合,形成一个最终的配置对象,然后把配置对象交给编译器进行编译, 通过入口模块找到互相依赖模块形成模块列表,接下来webpack会根据配置,为chunk生成一个资源列表,然后将每一个chunk生成的资源合并成一个完整的资源,并且生成一个完整的hash值,最终根据完整的资源列表输出到文件。

     

    涉及术语:

    1. module:模块,分割的代码单元,webpack中的模块可以是任何内容的文件,不仅限于JS
    2. chunk:webpack内部构建模块的块,一个chunk中包含多个模块,这些模块是从入口模块通过依赖分析得来的
    3. bundle:chunk构建好模块后会生成chunk的资源清单,清单中的每一项就是一个bundle,可以认为bundle就是最终生成的文件
    4. hash:最终的资源清单所有内容联合生成的hash值
    5. chunkhash:chunk生成的资源清单内容联合生成的hash值
    6. chunkname:chunk的名称,如果没有配置则使用main
    7. id:通常指chunk的唯一编号,如果在开发环境下构建,和chunkname相同;如果是生产环境下构建,则使用一个从0开始的数字进行编号

     

  • 相关阅读:
    C++11并发之std::thread<转>
    YUV420格式解析<转>
    在windows、linux中开启nginx的Gzip压缩大大提高页面、图片加载速度<转>
    curl 超时设置<转>
    C++中map用法详解《转》
    同一台服务器配置多个tomcat服务的方法
    找出两个排好序的数组的中位数
    mysql中设置默认字符编码为utf-8
    大步小步攻击算法_完全版
    ACL登陆认证
  • 原文地址:https://www.cnblogs.com/zhilili/p/14735077.html
Copyright © 2011-2022 走看看