RequireJS模块加载

RequireJS

源码地址:http://www.wcscj.xyz:3000/wcs/requirejs-tutorial

加载JavaScript文件

在一些大的项目里面通常会有很多个js文件,通常使用<script>标签逐个加载。另外一切js的文件可能会依赖于其他的文件,这里我们需要保证被依赖的文件先于当前的文件加载。比如说jquery,很多的库都依赖核心的jquery模块。我们通过模拟真实的环境来讲解requirejs的加载。

purchase.js

function purchaseProduct() {
    console.log('Function :purchaseProduct')
    var credis = getCredits();
    if(credis>0){
        reserveProduct();
        return true;
    }
    return false;
}

products.js

function purchaseProduct() {
    console.log('Function :purchaseProduct')
    var credis = getCredits();
    if(credis>0){
        reserveProduct();
        return true;
    }
    return false;
}

credits.js

function getCredits(){
    console.log('Function : getCredits');
    var credits = "100";
    return credits
}

在这个例子里面,我们试图购买一个产品。首先检查是否有足够的信用可用于购买产品。然后,在确认信用之后保留产品。

现在我们通过main.js通过调用 purchaseProduct()来初始化代码。如下所示

**main.js **

var result=purchaseProduct();

为什么出错

在上面的三个文件中,我们可以发现purchase.js依赖credits.js和products.js模块。所以credits.js和products.js必须先于调用purchaseProduct()前引入。但是我们故意调整错误引入次序,会发现什么事?

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="products.js"></script>
    <script src="purchase.js"></script>
    <script src="main.js"></script>
    <script src="credits.js"></script>
</head>
<body>
</body>
</html>

通过运行上面的html,你会发现浏览器并不会如预期输出信息,而是打印了一条错误信息。

扫描二维码关注公众号,回复: 1004352 查看本文章

purchase.js:3 Uncaught ReferenceError: getCredits is not defined at purchaseProduct (purchase.js:3) at main.js:1

这是因为credits.js是在main.js之后,在我们调用 purchaseProduct()的函数时候并没有加载credits.js文件,浏览器找不到对应的函数的声明。

上面仅仅是3个js的文件,而一个大型的项目当中可能存在着几十个js的文件,你要时刻去关注每个js文件的依赖,是不是想想就觉得头痛。

requireJS简介

按照官方的解释,RequireJS是一个javaScript文件和模块加载器。不仅能够优化浏览器环境。同时也能用于Rhino和Node.RequireJS不仅能够异步进行模块的加载,同时可以定义模块间的依赖关系,通过配置能够优化程序的运行速度以及质量。

在我们进行项目的讲解之前,您需要去github或者官网上面下载最新的requirejs文件并且放置在项目的scripts目录下面。

假设我们的项目结构如下图所示

屏幕快照 2018-03-31 22.39.16

所有的javascript文件(包括RequireJS文件)都位于脚本文件夹内。main.js文件用于初始化,其他文件包含了应用程序的业务逻辑。我们看看script的文件如何应用到html文件当中。

<script data-main="scripts/main" src="scripts/require.js"></script>

上面的代码段是我们使用requireJS文件唯一需要加入的代码。上面的代码块中data-main忏悔定义应用程序的入口点。在上面的案例中我们使用main.js文件。RequireJS会利用main.js文件自动查找其他脚本以及依赖。

现在我们来看看加入requirejs后的main.js文件的代码

// var result=purchaseProduct();
require(['purchase'],function(purchase){
    purchase.purchaseProduct();
})

在RequireJS,所有的代码都被封装在require()和define()函数。上面的require函数的第一个参数指定了依赖。在我们的示例中我们需要调用 purchaseProduct函数,这个函数定义在purchase.js,所以我们需要进行加载。

第二个参数是一个匿名函数,上面的代码我们仅加载了purchase模块,函数函数中的purchase对应的就是purchase文件中暴露的文件。同样的requireJS支持多个依赖的加载如:

require(['a','b','c'],function(a,b,c))

通过RequireJS创建程序

上面的代码我们我们已经介绍了main.js如何转为RequireJS使用。现在我们继续讨论其他文件的定义。

purchase.js

define(["credits", "products"], function(credits, products) {
  console.log("Function : purchaseProduct");

  return {
    purchaseProduct: function() {
      var credit = credits.getCredits();
      if (credit > 0) {
        products.reserveProduct();
        return true;
      }
      return false;
    }
  };
});

purchase需要调用getCredits()reserveProduct(),所以必须加载credits.jsproducts.js文件

products.js

define(function(products) {
  return {
    reserveProduct: function() {
      console.log("function : reserveProduct");
      return true;
    }
  };
});

credits.js

define(function() {
  return {
    getCredits: function() {
      console.log("Function : getCredits");
      var credits = "100";
      return credits;
    }
  };
});

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script data-main="scripts/main" src="scripts/require.js"></script>

</head>
<body>
    
</body>
</html>

上面的两个文件被配置成独立的模块,意味着不依赖于其他任何的东西。同样的我们发现我们用的是define()而不是require()。有关require()和define()之间的选择,我们在下节中来讨论。

require() VS define()

之前我们提到可以同时使用require()和define()来加载依赖关系。理解这两个函数之间的差异对于管理依赖关系至关重要。require()用于运行即时功能,而define()用于定义多个位置的模块。在main.js文件中我们需要立即调用**purchaseProduct()**函数,所以我们使用require,而其他文件是可征用的模块,仅被其他文件调用,所以我们使用define()

管理相关文件的顺序

RequireJS使用异步模块加载(AMD)来加载文件。每个依赖模块通过给定的顺序异步请求开始加载。尽管考虑了文件的顺序,由于 异步的特点,我们无法保证第一个文件会在第二个文件之前被加载。因为RequireJS需要通过shim配置来定义按正确的顺序加载文件。我们来看看RequireJS中如何创建配置选项。

requirejs.config({
  shim: {
    source1: ["dependency1", "dependency2"],
    source2: ["source1"],
    backbone: {
        //backbone加载前需要加载的模块
      deps: ["underscore", "jquery"],
      exports: "Backbone"//暴露全局的名称
  },
       'jquery.scroll': {
            deps: ['jquery'],
            exports: 'jQuery.fn.scroll'//将scroll挂在jQuery的原型上
        },
  },
  
});

RequireJS允许我们使用config()函数提供配置选项。按接收一个shim的参数,我们来使用它来定义强制的依赖关系序列。

deps:表示当前模块需要依赖哪些库

exports:暴露的全局名称

项目真实的配置

require.config({
    urlArgs: "v=" + requirejs.s.contexts._.config.config.site.version,
    packages: [{
            name: 'moment',
            location: '../libs/moment',
            main: 'moment'
        }
    ],
    //在打包压缩时将会把include中的模块合并到主文件中
    include: ['css', 'layer', 'toastr', 'fast', 'backend', 'backend-init', 'table', 'form', 'dragsort', 'drag', 'drop', 'addtabs', 'selectpage'],
    paths: {
        'lang': "empty:",
        'form': 'require-form',
        'table': 'require-table',
        'upload': 'require-upload',
        'validator': 'require-validator',
        'drag': 'jquery.drag.min',
        'drop': 'jquery.drop.min',
        'echarts': 'echarts.min',
        'echarts-theme': 'echarts-theme',
        'adminlte': 'adminlte',
        'bootstrap-table-commonsearch': 'bootstrap-table-commonsearch',
        'bootstrap-table-template': 'bootstrap-table-template',
        //
        // 以下的包从bower的libs目录加载
        'jquery': '../libs/jquery/dist/jquery.min',
        'bootstrap': '../libs/bootstrap/dist/js/bootstrap.min',
        'bootstrap-datetimepicker': '../libs/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min',
        'bootstrap-daterangepicker': '../libs/bootstrap-daterangepicker/daterangepicker',
        'bootstrap-select': '../libs/bootstrap-select/dist/js/bootstrap-select.min',
        'bootstrap-select-lang': '../libs/bootstrap-select/dist/js/i18n/defaults-zh_CN',
        'bootstrap-table': '../libs/bootstrap-table/dist/bootstrap-table.min',
        'bootstrap-table-export': '../libs/bootstrap-table/dist/extensions/export/bootstrap-table-export.min',
        'bootstrap-table-mobile': '../libs/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile',
        'bootstrap-table-lang': '../libs/bootstrap-table/dist/locale/bootstrap-table-zh-CN',
        'tableexport': '../libs/tableExport.jquery.plugin/tableExport.min',
        'dragsort': '../libs/fastadmin-dragsort/jquery.dragsort',
        'sortable': '../libs/Sortable/Sortable.min',
        'addtabs': '../libs/fastadmin-addtabs/jquery.addtabs',
        'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll',
        'validator-core': '../libs/nice-validator/dist/jquery.validator',
        'validator-lang': '../libs/nice-validator/dist/local/zh-CN',
        'plupload': '../libs/plupload/js/plupload.min',
        'toastr': '../libs/toastr/toastr',
        'jstree': '../libs/jstree/dist/jstree.min',
        'layer': '../libs/layer/dist/layer',
        'cookie': '../libs/jquery.cookie/jquery.cookie',
        'cxselect': '../libs/fastadmin-cxselect/js/jquery.cxselect',
        'template': '../libs/art-template/dist/template-native',
        'selectpage': '../libs/fastadmin-selectpage/selectpage',
        'citypicker': '../libs/city-picker/dist/js/city-picker.min',
        'citypicker-data': '../libs/city-picker/dist/js/city-picker.data',
    },
    // shim依赖配置
    shim: {
        'addons': ['backend'],
        'bootstrap': ['jquery'],
        'bootstrap-table': {
            deps: [
                'bootstrap',
//                'css!../libs/bootstrap-table/dist/bootstrap-table.min.css'
            ],
            exports: '$.fn.bootstrapTable'
        },
        'bootstrap-table-lang': {
            deps: ['bootstrap-table'],
            exports: '$.fn.bootstrapTable.defaults'
        },
        'bootstrap-table-export': {
            deps: ['bootstrap-table', 'tableexport'],
            exports: '$.fn.bootstrapTable.defaults'
        },
        'bootstrap-table-mobile': {
            deps: ['bootstrap-table'],
            exports: '$.fn.bootstrapTable.defaults'
        },
        'bootstrap-table-advancedsearch': {
            deps: ['bootstrap-table'],
            exports: '$.fn.bootstrapTable.defaults'
        },
        'bootstrap-table-commonsearch': {
            deps: ['bootstrap-table'],
            exports: '$.fn.bootstrapTable.defaults'
        },
        'bootstrap-table-template': {
            deps: ['bootstrap-table', 'template'],
            exports: '$.fn.bootstrapTable.defaults'
        },
        'tableexport': {
            deps: ['jquery'],
            exports: '$.fn.extend'
        },
        'slimscroll': {
            deps: ['jquery'],
            exports: '$.fn.extend'
        },
        'adminlte': {
            deps: ['bootstrap', 'slimscroll'],
            exports: '$.AdminLTE'
        },
        'bootstrap-datetimepicker': [
            'moment/locale/zh-cn',
//            'css!../libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css',
        ],
        'bootstrap-select': ['css!../libs/bootstrap-select/dist/css/bootstrap-select.min.css', ],
        'bootstrap-select-lang': ['bootstrap-select'],
//        'toastr': ['css!../libs/toastr/toastr.min.css'],
        'jstree': ['css!../libs/jstree/dist/themes/default/style.css', ],
        'plupload': {
            deps: ['../libs/plupload/js/moxie.min'],
            exports: "plupload"
        },
//        'layer': ['css!../libs/layer/dist/theme/default/layer.css'],
//        'validator-core': ['css!../libs/nice-validator/dist/jquery.validator.css'],
        'validator-lang': ['validator-core'],
//        'selectpage': ['css!../libs/fastadmin-selectpage/selectpage.css'],
        'citypicker': ['citypicker-data', 'css!../libs/city-picker/dist/css/city-picker.css']
    },
    baseUrl: requirejs.s.contexts._.config.config.site.cdnurl + '/assets/js/', //资源基础路径
    map: {
        '*': {
            'css': '../libs/require-css/css.min'
        }
    },
    waitSeconds: 30,
    charset: 'utf-8' // 文件编码
});

猜你喜欢

转载自my.oschina.net/u/215677/blog/1788072