首页 > 其他分享 >使用RequireJS并实现一个自己的模块加载器 (一)

使用RequireJS并实现一个自己的模块加载器 (一)

时间:2023-10-08 15:58:30浏览次数:57  
标签:require baseUrl js 模块 main RequireJS 加载

使用RequireJS并实现一个自己的模块加载器 (一)

 

RequireJS & SeaJS

在 模块化开发 开发以前,都是直接在页面上引入 script 标签来引用脚本的,当项目变得比较复杂,就会带来很多问题。

  • JS项目中的依赖只有通过引入JS的顺序来确定,项目会变得复杂难以维护。
  • 复杂的脚本会暴露很多全局变量, 比如 $,_. ... 。
  • 同步加载的时候,网页会停止渲染,加载时间越长,网页失去响应的事件就越长。

于是,AMD 规范就诞生了,AMD 即为异步模块定义,有效避免同步加载导致页面的假死现象。RequireJS 是一个 AMD 的实现,后来还有CMD规范,玉伯的 而SeaJS 是 CMD 的一个实现,两者最大的区别就是

RequireJS 是预加载,而sea.js 是懒加载,也就是按需加载

什么意思 ??

比如下面的代码

define(function(require,exports,module){
    // do something
    var mod1 = require('./mod1');
    // do something
    var mod2 = require('./mod2');
})

RequireJS 会全部找到这个模块的依赖,并在开始执行是就加载全部的依赖,
而SeaJS 则是按需加载,直到遇到 require 才会加载。

RequireJS 内部通过 Function.prototype.toString() ,然后使用正则匹配所有的require 方法,将其转化为

define(['./mod1',./mod2']function(mod1,mod2)

这种方式。

有很多关于这两种方式的争吵,由于我没有做过较大的项目,所以对于这两种方式在正真项目中使用的区别也不清楚。

回顾 RequireJS

主要接口有两个: require & define,define 是模块的定义方法,require 是模块的使用方法。
define 的参数为 define (id?,deps?,factory)。第一个为模块ID,第2个为依赖列表,第三个是工厂方法 。如果不定义ID,则为匿名方法,通常情况,模块ID 等于模块在工程的路径。deps 和 factory 有约定,deps 数组有多少个元素,factory 就会有多少个形参,形参对于与依赖模块工厂函数执行后的返回值。

define ("id",["mod1","mod2"],function(mod1,mod2){
    return {
        ///
    };
})

require 方法和 define 基本一致。

文件目录

└─ use-require/ 
   ├─ app/ 
   │  ├─ js/ 
   │  │  ├─ module/ 
   │  │  │  ├─ a.js
   │  │  │  └─ b.js
   │  │  ├─ main.js
   │  └─ lib/  
   │  │  └─ require.js
   ├─ index.html
   └─ readme.md 

现在,需要在 index.html 引导整个程序 。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
     <script src="./app/lib/require.js" data-main="./app/js/main">
    </script>
</body>
</html>

引入 requirejs,并通过 data-main 申明 启动 js 文件。

注意: data-main 指向的文件所在路径就是 baseUrl,在这里就是app/js ,
baseUrl 也可以通过require.config 设置 。如果没有通过 data-main 属性指定 baseUrl ,也没有通过config的方式显示声明 baseUrl ,那么 baseUrl 默认为加载requirejs的那个页面所在的路径
下面 b 依赖 a ,那么就应该写 module/a,而 main 依赖 b ,写为 module/b ,这个路径会和 baseUrl 拼接,与a ,b 所在的路径无关 。有时候,你可能需要生成一个相对于模块的URL地址。你可以将require作为一个依赖注入进来,然后调用require.toUrl()以生成该URL 。

define(["require"], function(require) {
var url = require.toUrl("./style.js");

});

有时候你想避开"baseUrl + paths"的解析过程,而是直接指定加载某一个目录下的脚本。此时可以这样做:如果一个module ID符合下述规则之一,其ID解析会避开常规的"baseUrl + paths"配置,而是直接将其加载为一个相对于当前HTML文档的脚本:
注意是 相对于 HTML 文档,因为 js脚本是会被插入到 html 文档中执行的 。

  • 以 ".js" 结束 。
  • 以 "/" 开始。
  • 包含 URL 协议, 如 "http:" or "https:"。

一般来说,最好还是使用baseUrl及"paths" config去设置module ID。它会给你带来额外的灵活性,如便于脚本的重命名、重定位等。 同时,为了避免凌乱的配置,最好不要使用多级嵌套的目录层次来组织代码,而是要么将所有的脚本都放置到baseUrl中,要么分置为项目库/第三方库的一个扁平结构,如下:

└─ project/ 
   ├─ js/ 
   │  ├─ app/ 
   │  │  └─ sub.js
   │  ├─ lib/ 
   │  │  ├─ jquery.js
   │  │  └─ require.js 
   │  └─ app.js 
   ├─ index.html                           
   └─ readme.md 

下面自然就顺利成章
申明模块a

define(function() {
    'use strict';
    return {
        name: "hello , i am a"
    }
})

模块 b

define(["module/a"], function(a) {
  'use strict';
    var aName = a.name;
    var name = "hello i am b";
    return {
        sayHello: function() {
            console.log(name + "  my brother is " + aName);
        }
    }
})

在模块b 里面依赖模块a 。

main.js

require(["module/b"], function(b) {
  'use strict';
    b.sayHello();
})

看看效果

如果使用 require.config() 配置呢?
将上面的目录复制一份,命名 use-require-config,目录结构完全一致

main.js

requirejs.config({
    baseUrl: './app/js/module'
})

require([".b"], function(b) {
    'use strict';
    b.sayHello();
})

在这里,将配置放在 main.js 里面,等会儿会讲如果不放在它里面会又什么问题。

模块 b 依赖 于 a

define(["./a"], function(a) {
    'use strict';
    var aName = a.name;
    var name = "hello i am b";
    return {
        sayHello: function() {
            console.log(name + "  my brother is " + aName);
        }
    }
})

由于将baseUrl 设置为 app/js/module ,所以这里依赖a 就可以直接写a
在这里,我使用 ./a, 与直接写 a 一模一样,还是使用 baseUrl+ moduleName `来寻找模块路径。

如果不将 requirejs.config 放在main中,而是另外在引入一个script 节点来放置 呢

<body>
    <script src="./app/lib/require.js" data-main="./app/js/main">
    </script>
    <script>
        requirejs.config({
           baseUrl: './app/js/module'
        })
    </script>
</body>

在浏览器运行

发现报错了,怎么回事呢?
看它寻找 main.js 的路径

file:///E:/HFLib/module/code/use-require-config/app/js/module/main.js 

是 baseUrl + main.js。 这说明,配置的 baseUrl 覆盖了为 data-main 配置的路径
也就是说,一旦使用requirejs.config 来配置 baseUrl,那么所有的路径都会以 baseUrl 为基准。
所以,data-main 应改为: ..\main,注意这里必须要使用反斜杠,正斜杠拼接总是会出现问题。
通过这样就可以解决 data-main 和 requirejs.config() 的冲突了 。

paths 和 shim 。

当模块名过长是,require.js 为我们提供了路径 paths 的方式 。
理想状况下,每个加载的脚本都是通过define()来定义的一个模块;但有些"浏览器全局变量注入"型的传统/遗留库并没有使用define()来定义它们的依赖关系,你必须为此使用shim config来指明它们的依赖关系。

这是我的文件目录

index.html

<body>
    <script src="./app/lib/require.js" data-main="./app/main">
    </script>
</body>

main.js

requirejs.config({
    paths: {
        jQuery: 'lib/jQuery'
    },
    shim: {
        'jQuery': {
            exports: '$'
        }
    }
})

require(['jQuery'], function($) {
    'use strict';
    console.log($);
})

可以看到,已经顺利注入了 jQuery 依赖。

require.js 中还有很多配置和用法,我用的就比较少,就简单介绍到这里。
下来,我要实现一个简化的模块加载器,类似于 require.js.

实现一个自己的模块加载器

太晚了 。

就在 实现一个自己的模块加载器(二)中实现一个类似 require.js 的Demo 吧 。

标签:require,baseUrl,js,模块,main,RequireJS,加载
From: https://www.cnblogs.com/tomcat2022/p/17749272.html

相关文章

  • smtplib、zmail模块发邮件
    1、zmail发送邮件脚本#!/usr/bin/envpython#-*-coding:utf-8-*-#__author__=#https://www.jianshu.com/p/b9e11dbbc9cf#https://github.com/zhangyunhao116/zmail/blob/master/README-cn.md#pipinstalldocx-mailmerge将相同格式的模板与一组数据合并#pipins......
  • ansible常用模块总结
    常用模块帮助文档参考:https://docs.ansible.com/ansible/2.9/modules/modules_by_category.htmlhttps://docs.ansible.com/ansible/2.9/modules/list_of_all_modules.html1)Command模块功能:在远程主机执行命令,此为默认模块,可忽略-m选项说明:此命令不支持$VARNAME<>|;&......
  • destoon修改公司模块url路径com
    destoon修改公司模块url路径com,只需要修改两处即可。1、打开文件include/global.func.php,修改:$URL=DT_PATH.'com/'.$username.'/';将com改成你希望的公司模块地址即可,例如:b2b、gongsi、changjia等。2、修改网站的伪静态,将com相关的伪静态改成对应的路径即可。rewrite^/......
  • 如何用tfds加载本地数据库
    云端的数据库存储在google的服务器,所以无法通过tfds.load('mnist',split='train')这样的方式直接加载,下面是一些变通的方式来读取。一、MNIST数据库1.我用tfds.load去加载本地的mnist数据库,mnist/3.0.1应该具有什么样的数据格式答:如果你正在使用`tfds.load`来加载本地的MNIST......
  • 02. request模块
    一、什么是request模块  requests模块是基于代码实现发送网络请求。该模块的作用是模拟浏览器发请求。Python中默认不带有requests模块,我们可以通过pip来安装。pipinstallrequests二、request模块的基本使用2.1、什么是UA伪装  UA检测是指门户网站的服务器会......
  • 初始化 Angular 懒加载模块:使用MODULE_INITIALIZER的高级技巧
    Angular是一个强大的前端开发框架,它提供了各种机制来优化应用程序的性能和可维护性。在本文中,我们将深入探讨Angular中的MODULE_INITIALIZER,这是一个用于初始化懒加载模块的强大工具。我们将详细介绍MODULE_INITIALIZER的用法以及它在Angular中的作用。什么是懒加载模块?懒加载模......
  • Anaconda配置Python的xlrd模块
      本文介绍在Anaconda环境下,安装Python读取.xls格式表格文件的库xlrd的方法。  xlrd是一个用于读取Excel文件的Python库,下面是xlrd库的一些主要特点和功能:读取Excel文件:xlrd可以打开和读取Excel文件,并提取其中的数据和元数据。支持多种数据类型:xlrd可以处理包括数字、日期......
  • Requests模块
    该文总结了requests这个http模块,该模块主要用于发送请求获取响应,该模块有很多的替代模块,比如说urllib模块,但是在工作中用的最多的还是requests模块,requests的代码简洁易懂,相对于臃肿的urllib模块,使用requests编写的爬虫代码将会更少,而且实现某一功能将会简单。......
  • 【爬虫】python数据挖掘-lxml模块-3
    Python爬虫掌握lxml模块中使用xpath语法定位元素提取属性值或文本内容掌握lxml模块中etree.tostring函数的使用1.lxml模块的安装与使用示例lxml模块是一个第三方模块,安装之后使用1.1lxml模块的安装对发送请求获取的xml或html形式的响应内容进行提取pip/pip3installlxml知识......
  • python 中map模块
     map函数会根据提供的函数对指定的序列做映射。第一个参数接受一个函数名,后面的参数接受一个或多个可迭代的序列,返回的是一个集合。 001、>>>deffun01(x):##测试函数...returnx*100...>>>list1=[8,3,2,7]>>>>>>list(map(fun01,......