沉淀 | JavaScript模块管理之RequireJS

背景

JavaScript这门脚本语言,相对于Python等确实比较简陋、甚至于丑陋。比如在代码文件管理、和模块管理上,存在很多空白。

沉淀 | JavaScript模块管理之RequireJS_第1张图片
Paste_Image.png

JavaScript语言的不足

对于JavaScript文件:

  • 文件按

    data-main指定主模块

    细心的同学会发现script标签上了多了一个自定义属性:data-main="script/main",等号右边的main指的main.js。当然可以使用任意的名称。这个main指主模块或入口模块,好比c或java的主函数main。
    通常在主模块中,进行RequireJS全局配置:

    require.config({
        paths: {
            jquery: 'jquery-1.7.2'
        }
    });
    

    副作用:data-main同时指定了默认的js路径

    上述main.js位于script/,所以之后本地文件的查找、使用相对路径的化、就会相对于这个路径去查找。

    2、require.config:全局配置

    require方法本身也是一个对象,它带有一个config方法,用来配置require.js运行参数。

    应用中所有的js模块都应该在这里配置相关的信息。这些信息包含了每个模块的位置啥的,解决了到哪里去找到模块的问题。这块配置是全局的。

    config方法接受一个对象作为参数。一般配置项都在页面data-main所指的js中 —— 这儿是js代码的总入口。
    常用的配置有baseUrl,paths等。

    require.config({
        baseUrl: "javascript",
        paths: {jquery: ['http//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js','lib/jquery.min'],
                bootstrap: 'lib/bootstrap'
        }
    });
    

    baseUrl 配置本地路径的基准路径

    baseUrl参数指定本地模块位置的基准目录,即本地模块的路径是相对于哪个目录的。该属性通常由require.js加载时的data-main属性指定,此时可以省略baseUrl

    paths 配置每个模块的位置

    paths参数指定各个模块的位置。这个位置可以是同一个服务器上的相对位置,也可以是外部网址。
    可以为每个模块定义多个位置,如果第一个位置加载失败,则加载第二个位置,上面的示例就表示如果CDN加载失败,则加载服务器上的备用脚本。

    需要注意的2点:

    • 关于后缀名 — 指定本地文件路径时,可以省略文件最后的js后缀名。
    • 关于baseUrl — 本地模块的路径是相对于baseUrl去定义的。

    什么样的模块可以不配置path?

    如果模块moudleA.js跟引用它的文件是同一路径下的,那么就可以直接用require(["moduleA"], function(ma){})来引用该模块,不需要配置path —— 这种写法我也不建议。

    shim 加载非AMD规范的js

    通过require加载的模块一般都需要符合AMD规范,即使用define来申明模块
    但是部分时候需要加载非AMD规范的js,这时候就需要用到另一个功能:shim,shim解释起来也比较难理解,shim直接翻译为"垫",其实也是有这层意思的。
    非AMD模块输出,将非标准的AMD模块"垫"成可用的模块,例如:在老版本的jquery中,是没有继承AMD规范的,所以不能直接require["jquery"],
    这时候就需要shim,那我们可以这样配置

    require.config({
      baseUrl: "javascript",
      paths: {
        jquery: 'lib/jquery.1.6',
        bootstrap: 'lib/bootstrap'
      },
      shim: {
        "jquery" : {
          exports : "$"
        }
      }
    });
    

    这样配置后,我们就可以在其他模块中引用jquery模块:

    require(['jquery'], function ($) {
        //do something....
    });
    

    jQuery与RequireJS ???

    我们知道jQuery从1.7后开始支持AMD规范,即如果jQuery作为一个AMD模块运行时,它的模块名是“jquery”。注意“jquery”是固定的,不能写“jQuery”或其它。

    注:如果文件名“jquery-1.7.2.js”改为“jquery.js”就不必配置paths参数了。

    我们知道jQuery最终向外暴露的是全局的jQuery和 $。如下

    window.jQuery = window.$ = jQuery;
    

    如果将jQuery应用在模块化开发时,其实可以不使用全局的,即可以不暴露出来。需要用到jQuery时使用require函数即可

    3、define方法: 定义自己的模块

    define方法用于定义模块,RequireJS要求每个模块放在一个单独的文件里。
    按照是否依赖其他模块,可以分成两种情况讨论。

    • 第一种情况是定义独立模块,即所定义的模块不依赖其他模块;
    • 第二种情况是定义非独立模块,即所定义的模块依赖于其他模块。

    定义没有依赖的独立模块

    如果被定义的模块是一个独立模块,不需要依赖任何其他模块,可以直接用define方法生成。

    • define的参数可以是一个对象,此时该对象就是输出的模块。
    define({
        method1: function() {},
        method2: function() {},
    });
    
    • define的参数也可以是一个函数,此时该函数的返回值就是输出的模块。—— 显然这种写法更具有通用性,建议统一这样写。
    // math.js
      define(function (){
        var add = function (x,y){
          return x+y;
        };
        return {
          add: add
        };
      });
    

    定义有依赖模块的模块

    非独立模块如果被定义的模块需要依赖其他模块,则define方法必须采用下面的格式:

    define(['module1', 'module2'], function(m1, m2) {
       ...
    });
    
    • define方法的第一个参数是一个数组,它的成员是当前模块所依赖的模块。
      比如,['module1', 'module2']表示我们定义的这个新模块依赖于module1模块和module2模块,只有先加载这两个模块,新模块才能正常运行。
      一般情况下,module1模块和module2模块指的是,当前目录下的module1.js文件和module2.js文件,等同于写成['./module1', './module2']。

    思考? 如果新模块同属于module文件下,如何定义引入文件路径?

    • define方法的第二个参数是一个函数,当前面数组的所有成员加载成功后,它将被调用。
      它的参数与数组的成员一一对应,比如function(m1, m2)就表示,这个函数的第一个参数m1对应module1模块,第二个参数m2对应module2模块。这个函数必须返回一个对象,供其他模块调用。
    define(['module1', 'module2'], function(m1, m2) {
      return {
        method: function() {
          m1.methodA();
          m2.methodB();
        }
      };
    });
    

    define回调必须返回一个对象??

    需要注意的是,回调函数必须返回一个对象,这个对象就是你定义的模块。
    如果依赖的模块很多,参数与模块一一对应的写法非常麻烦。

    define(
        [       'dep1', 'dep2', 'dep3', 'dep4', 'dep5', 'dep6', 'dep7', 'dep8'],
        function(dep1,   dep2,   dep3,   dep4,   dep5,   dep6,   dep7,   dep8){
            ...
        }
    );
    

    对于依赖模块特别多的情况,RequireJS有另一种等价写法: —— 还是竖版的好吧。。。!

    define(
      function (require) {
        var dep1 = require('dep1'),
          dep2 = require('dep2'),
          dep3 = require('dep3'),
          dep4 = require('dep4'),
          ……
      }
    });
    

    符合AMD规范的模块

    想象一下,如果你想把jquery、通过RequireJS、当做一个模块的方式引入进来,就像这样:

    require.config({
        paths: {
            jquery: 'jquery-1.7.2'
        }
    });
    

    那么jquery必须首先就是一个requirejs模块,也就是说 —— jquery必须把所有代码包装在require.define的回调函数里、并且返回$变量,对不对?

    所有这样的第三方库,就叫做“符合AMD规范的模块”

    4. require方法:在JS文件头部、声明依赖模块

    require方法用于调用模块。它的参数与define方法类似。
    1.普通加载方式

    require(['jquery','bootstrap'], function ($) {
        $('.carousel').carousel({
            interval: 3000
        });
    });
    

    上面方法表示加载jquery和bootstrap两个模块,当这两个模块都加载成功后,执行一个回调函数。
    该回调函数就用来完成具体的任务。require方法的第一个参数,是一个表示依赖关系的数组。

    有的模块会返回个对象,有的没有返回

    如上,bootstrap就没有返回值。jquery有返回值,所以在function中声明$代表jquery模块返回的值。
    注意前后是按顺序一一对应的
    模块输出变量,如果某个模块不输出变量值,则没有,所以尽量将输出的模块写在前面,防止位置错乱引发误解

    可以看出JavaScript这风格跟我们从前的人生、多么的不同!!同样是在文件头部声明依赖模块,人家横着写。。。而且不干不净。。

    沉淀 | JavaScript模块管理之RequireJS_第4张图片

    小结:RequireJS的风格

    • 一个文件定义一个模块,用文件路径定义模块名,通过模块名声明模块加载
    • 在文件头部声明依赖模块,人家是横着写的哦
    • .js常常可以省略
      比如main-data中指定的js文件,可以省略路径;path中指定的位置、如果是本地文件,可以省略后缀
    • 用别名代替全路径

    ------------------ 华丽丽的分隔线,以下是草稿 -----------------

    Require更多高级特性

    包模块加载

    使用config的package参数

    require方法的第一个参数,是一个表示依赖关系的数组。
    但是页面往往不会只有一个交互效果,如果多了就会展示这样

    require(['jquery','bootstrap'], function ($) {
      $('.carousel').carousel({
        interval: 3000
      });
    });
    //收藏方法
    require(['jquery'], function ($) {
      var collect=$('.goodsOffer-collect');
     
    });
    //出价控制
    require(['jquery','sp-bid-control'], function ($) {
    

    这只是作为参考,目的是为了展示当交互多了的时候会感觉比较乱。为了解决这个问题,可以引入了包加载模块。

    require合并

    运行命令node r.js -o build.js

    实例列表(未完成)

    参考文档

    本文参考:
    RequireJS入门(一)

    更多参考:

    1. require官网 API文档

    2. require.js中文网 —— 好像挂掉了。。

    3. JS模块化工具requirejs教程(一):初识requirejs
      JS模块化工具requirejs教程(二):基本知识
      这两篇是runoob.com网站的教程,很规范。

    4. RequireJS和AMD规范
      Javascript模块化编程(三):require.js的用法
      这两篇是阮一峰的博客,质量很高。

你可能感兴趣的:(沉淀 | JavaScript模块管理之RequireJS)