1、模块化

在前端开发中,模块化是趋势,毋庸置疑。尤其是单页面程序中,当然还涉及到模块的生命周期等,这些另说。完善的前端模块化规范来的非常的晚,在之前,各种后端开发早已实现这些基础问题,唯独前端一直没有得到良好的解决。与前端的运行环境、异步加载等因素有关。

目前主流的模块化规范是 AMD、CMD、CommonJS 这些,coolie支持的是 CMD 规范。先看下 CMD 规范是怎么样的:

define(function(require, exports, module){
    // 引用相对于当前模块路径的 path/to/file.js
    var a = require('./path/to/file.js');

    // todo
});

注意点:

  • 每个模块都需要define包裹,主要原因是避免全局污染,并且利于静态分析依赖。
  • require字面量,不能被修改为其他值,因为模块加载器是通过正则分析require关键字的。
  • require路径必须为相对或者绝对路径,路径再长也没关系,在构建之后路径会被计算成单个字符。
  • 一个文件仅书写一个模块。
  • 开发环境下,不必显式写明模块的ID和模块的依赖。

2、为什么选用 CMD

2.1、路径清晰

img.png 如上图,animation.js模块依赖了see.js模块,依赖关系一目了然,并且在 idea 编辑器里可以通过comman|ctrl键单击该路径可以直达该模块,非常适合快速开发。

2.2、提示清晰

在开发过程中,各种模块使用起来,难免会对部分模块的 API 不是很熟悉,这时候编辑器的智能提示就非常有用了。 img.png 参数提示: img.png

2.3、定位清晰

如上图,被依赖的模块路径书写错误,有非常明显的错误提示,可以非常快捷的定位。 img.png 因为 nodejs 的模块依赖就是这样的,所以只需要在编辑器配置里勾选 libraries 里的 node 相关选项即可: img.png

3、加载策略

我们约定,每个页面都有且最多只有一个入口模块。模块加载器通过分析入口模块所依赖的模块,然后通过路径的相对关系,找到所依赖的模块。通过这一层层的递归查找过程,直到没有被依赖模块为止,整个寻找过程结束。查找结束之后,才开始从入口模块开始执行,依次递归调用到模块依赖链的终点,这个过程是一个嵌套的关系,因此形成的堆栈也非常的深,不过目前的浏览器都支持成千上万的嵌套层级,无需过分担心。看似原理比较简单,就是一个分析依赖,执行依赖的过程。 假设当前有一个动画模块animation.js。 首先,需要判断需要加载的模块,即是入口模块,这需要手动指定。 然后,该模块加载完毕会执行define方法,该方法有一个参数,参数类型为functionimg.png 反观模块加载器的define方法: img.png 其次,通过分析它的源码: img.png 得到被依赖的模块,注册到模块 MAP 里: img.png 然后,重复上述过程。直到: img.png 最后再执行入口模块即可。

4、构建过程

构建过程与加载策略是一致的,区别有2:

  1. 加载依赖之后,会将当前模块进行压缩,并写入缓存。
  2. 最后执行入口模块的步骤舍去。