乐趣区

最全的前端模块化方案

模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。将一个复杂的系统分解为多个模块以方便编码。

会讲述以下内容

  1. CommonJS
  2. AMD 及 核心原理实现
  3. CMD 及 核心原理实现
  4. UMD 及 源码解析
  5. ES6 Module
  6. webpack 打包策略

CommonJS

同步加载

CommonJS API 是以在浏览器环境之外构建 JS 生态系统为目标而产生的项目

如果没有写后缀名 Node 会尝试为文件名添加.js、.json、.node 后再搜索。

.js 件会以文本格式的 JavaScript 脚本文件解析,.json 文件会以 JSON 格式的文本文件解析,.node 文件会以编译后的二进制文件解析。

AMD

异步加载(对象)

“Asynchronous Module Definition”(异步模块定义),是由 RequireJS 提出的

AMD 核心实现

  function require (url, callback) {
    // url 可以换成 List,然后遍历;var $script = document.createElement('script');
    $script.src = url;

    // 利用 onload 回调,实现依赖加载
    $script.onload = function (e) {
      // 省略 callback 检测
      callback();}
    document.body.appendChild($script);
  }

CMD

按需加载

由玉伯提出的(seajs),按需解析加载模块(代价挺大的),需要使用把模块变为字符串解析一遍才知道依赖了那些模块

CMD 核心实现

  // ajax,怕忘了原生 ajax 怎么写。顺手写一个

  function myAjax (url, callback) {var xhr = new XMLHttpRequest();
    xhr.open('get', url);
    xhr.send();

    xhr.onreadystatechange = function () {if (request.readyState === 4) {if (request.status === 200) {return callback(request.responseText);
          } else {// 省略...}
      } else {// 省略...}
    }
  }

  // 实现
  function require(url) {myAjax(url, function(res) {
      // 此时 res 的对应 JS 的 String 形式
      // 解析 省略
      // 执行
      eval(res);
    });
  }

UMD

兼容 AMD,CommonJS 模块化语法。

UMD 源码解析

  (function (root, factory) {

    // 判断是否支持 AMD(define 是否存在)if (typeof define === 'function' && define.amd) {define(['b'], factory);

    // 判断是否支持 NodeJS 模块格式(exports 是否存在)} else if (typeof module === 'object' && module.exports) {module.exports = factory(require('b'));

    // 前两个都不存在,则将模块公开到全局(window 或 global)} else {root.returnExports = factory(root.b);
    }
  } (this, function (b) {// ...}));

import

加载引用

  • 编译时加载(静态执行)。
  • 加载的是引用
  • 不能处于代码块中

    • 为了实现编译时加载

      • 提案表示可以用 import()使用时加载
  • 不能使用表达式和变量 等运行时加载的语法

    • 同上

webpack 打包策略

import 会被编译成 require/exports(CommonJS 规范)

1. 直接引入

import xxx.js或者 import xxx.css 会像添加 <script><link>标签一样注入到全局中去

2. commonjs 同步语法

webpack 会将 require('abc.js') 打包进引用它的文件中。以对象的形式获取。

3. commonjs 异步加载

webpack(require.ensure):webpack 2.x 版本中的代码分割。

在 commonjs 中有一个 Modules/Async/ A 规范,里面定义了 require.ensure 语法。webpack 实现了它,作用是可以在打包的时候进行代码分片,并异步加载分片后的代码。

此时 list.js 会被打包成一个单独的 chunk 文件。像这样:1.d6f343b727f5923508bf.js

例如:vue 路由懒加载const Foo = () => import('./Foo.vue')

manifest

manifest 文件是最先加载的,manifest 是在 vendor 的基础上,再抽取出要经常变动的部分,通过 manifest.js 文件来管理 bundle 文件的运行和加载。(比如关于异步加载 js 模块部分的内容)

webpack v4.6.0+ 添加了预取和预加载的支持

  import(/* webpackPrefetch: true */ 'LoginModal');
  
  会生成 <link rel="prefetch" href="login-modal-chunk.js"> 并追加到页面头部

整理不易,喜欢请 star,https://github.com/zhongmeizhi

退出移动版