• 解析webpack——模块化历史与webpack的诞生


    前言

    本文将通过前端模块化发展历史引入webpack出现的原因,解决的问题,以及目前的困境。

    至今,前端模块化已经发展了有十余年了,总结起来,它们解决的问题主要有三个

    • 外部模块的管理
    • 内部模块的组织
    • 模块源码到目标代码的编译和转换

    如果对模块化历史感兴趣,推荐阅读前端模块化的十年征程

    一些标志性工具诞生时间线:

    生态诞生时间(年)
    Node.js2009
    NPM2010
    requireJS(AMD)2010
    seaJS(CMD)2011
    broswerify2011
    webpack2012
    rollup2018
    vite2020
    snowpack2020

    前端模块化历史

    在刀耕火种的年代,如果我们需要在项目里使用某个外部模块,我们可能会去官网直接把文件下载下来放到项目中,同时在入口html中通过script标签引用它。
    后来NPM出现了,它是一个Node自带的模块管理工具。万千前端开发者们可以通过npm publish的方式将自己的模块发布到NPM上去。当需要引用外部模块时,通过运行npm install [模块名],可以将别人的模块下载到自己项目根目录中一个叫node_modules的子目录下。
    我们可以通过配置化的文件指定引入的依赖版本,也就是package.json文件。这就解决了外部模块管理的问题。

    这个时期,我们使用script标签引入模块,一些模块需要通过一个“立即调用的函数表达式”(IIFE)去组织。

    <script>
      var module1 = (function(){
        var x = 1  
        return { a: x };
      })();
    </script>
    <script>
      var module2 = (function(){
       var a = module1.a;   
       return { b: a };
     })();
    </script>       
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    随着项目扩大,html文件中会包含大量script标签。这样会出现两个主要的问题:

    1. 模块中存在一些依赖的关系,这些关系并不是线性的,相对复杂的依赖关系难以用script标签的先后顺序组织
    2. 因为对script标签顺序的要求而使用同步加载,但这却容易导致加载时页面卡死

    为了解决以上问题,社区逐渐发展出一些规范来约束模块的加载。第一阶段,占据主流的是AMD && CMD。

    AMD & CMD

    首先开始在前端流行的模块化规范是AMD/CMD, 以及实践这两种规范的require.js和Sea.js, AMD和CMD可看作是"在线处理"模块的方案,也就是等到用户浏览web页面下载了对应的require.js和sea.js文件之后,才开始进行模块依赖分析,确定加载顺序和执行顺序。模块组织过程在线上进行。
    AMD是Asynchronous Module Definition,意思就是"异步模块定义"。AMD推崇依赖前置,即通过依赖数组的方式提前声明当前模块的依赖。

    CMD即Common Module Definition,意为“通用模块定义”。CMD推崇依赖就近,在编程需要用到的时候通过调用require方法动态引入

    后来,伴随着babel等编译工具和webpack等自动化工具的出现,AMD/CMD逐渐湮没在历史的浪潮当中,然后大家都习惯于用CommonJS和ES6的模块化方式编写代码了。

    CommonJS && ES6

    CommonJS是Node.js使用的模块化方式,而import/export则是ES6提出的模块化规范。它们的语法规则如下。

    // ES6
    import { a } from './Module';
    export const b = 1;
    
    // CommonJS
    const a = require(./Module);
    module.exports = {
    	b: 1
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    最开始的时候,浏览器并不能理解这种语法。
    但是编译工具babel的出现,使我们在开发环境使用它们变成了可能。
    在babel出现之前的AMD/CMD时代,开发和生产的代码并没有明显的区分性。
    而babel则将开发和生产这两个流程分开了,让我们在开发时可以更专注于逻辑的实现、代码的便捷性和可阅读性。

    至此,ES6编程的时代到来。

    预编译时代

    受限于早期浏览器并发限制、海量HTTP性能等因素,像之前的AMD/CMD这种“在线编译”方案,会产生一些性能问题。
    为了优化模块在线编译导致的耗时,更好的管理依赖的加载和执行顺序,合并部分请求避免并发请求限制导致的阻塞,开发者们创造了一个工具来做这些工作。
    webpack就是在这样的背景下应运而生的。
    它一开始的定位是通过预先打包的方式,把前端项目里面的多个文件打包成单个文件或少数几个文件,这样的话就可以压缩首次页面访问时的http请求数量,从而提高性能。

    当然,代码打包不是一本万利的,它们也面临着一些副作用带来的问题。其中最大的问题就是多个文件合成打包后,打包产物的体积会过大,下载耗时长,如此一来,首屏加载的时间还是会被延长。

    webpack于是引入了代码拆分的功能(Code Splitting)来解决这个问题, 从全部打包后退一步:可以打包成多个包。数量还是少于之前无预编译的模块的。
    Code Splitting主要有两方面的作用:
    一是实现依赖分离,将第三方库和业务代码的分离,比起业务代码,变动较少的第三方库可以更好地利用浏览器缓存机制。
    二是实现按需加载,减少首页加载的文件体积,通过路由跳转时再加载对应页面的模块。

    自动化构建阶段

    随着技术的进步,全方位的自动化构建工具慢慢发展,开发者已经不满足于简单的代码拆分打包,希望有更全方位的自动化代码处理和优化工具,我们希望做到:

    • 开发时使用丰富且方便的JS新特性
    • 使用Sass,less编写阅读性和扩展性良好的样式代码
    • 提供开发时SourceMap功能,也即提供生产代码(如ES5)到源代码(typescript)的映射,方便开发调试
    • 提供生产时代码压缩功能,压缩js和css,删除注释,替换变量名(长变短),减少代码加载体积

    等等附加功能。
    webpack并没有自己实现所有的功能,它是一个微内核的架构,得益于架构的灵活性,它允许开发者开发自己的loader和plugin来扩展功能。
    在此基础上,经过了七八年的发展,配置式的webpack渐渐打败编程式的gulp,成为前端开发者的主流自动化构建工具。

    bundleless

    webpack在诞生之初采用集中打包方式进行开发,有两个方面的原因:
    一是浏览器的兼容性还不够良好,还没提供对ES6的足够支持,需要把每个JS文件打包成单一bundle中的闭包的方式实现模块化。
    二是为了合并请求,减少HTTP/1.1下过多并发请求带来的性能问题。

    而技术发展到今天,过去的这些问题已经得到了很大的缓解,因为主流现代浏览器已经能充分支持ES6了,import和export随心使用。而且在HTTP2.0普及后,并发请求的性能问题没有不再突出。

    bundleless就是把开发中拖慢速度的打包工作给去掉,从而获得更快的开发速度。代表性工具是vite。

    vite大大提高了开发阶段代码的构建速度,解决了webpack被诟病许久的dev环境构建耗时长的问题,但是在生产阶段的打包还是无法超越目前webpack打包的成熟性和通用性,对于非js文件的支持性也不是很好,需要依赖更多的工具处理。

    vite的出现警醒了webpack,目前不再是一家独大的市场,不在竞争中前进就会被时代抛弃。webpack目前也在测试版本中引入ESM的打包方式,期待后续它的优化。

  • 相关阅读:
    3D 沙盒游戏之人物的点击行走移动
    Linux多核运行机制(SMP)
    事务提交之后再执行某些操作 → 你有哪些实现方式?
    金仓数据库KingbaseES物理备份恢复命令选项(stanza-delete命令)
    selenium教程(2)CSS元素操作
    锐捷链路聚合实验配置
    【广州华锐互动】影视制作VR在线学习:身临其境,提高学习效率
    1488. 避免洪水泛滥
    认识.NET Aspire:高效构建云原生应用的利器
    使用SWIG编写python的扩展
  • 原文地址:https://blog.csdn.net/sinat_31231955/article/details/125989824