简单介绍下modJS

近期把团队的项目构建迁移到fis3,同时把模块加载器也由之前的requirejs切换到了modJS。

有些同学可能不了解modJS,这里做个简单的介绍。

那么,modJS是什么呢?

简单的说,modJS是百度fex-team提供的一个轻量级的模块加载器,类似requirejs。

但modJS并不完全兼容规范amd/cmd,事实上,只支持非常简单的全局方法define(id,factory)。

另外factory提供了3个参数require/exports/module,用于引用和导出模块。

modJS源码只有200行左右,相比之下requirejs的源码达到了2000+行。

除了体量非常小之外,modJS配合fis3的fis3-hook-commonjs插件,可以在纯前端项目中实现类似nodejs一样的开发体验。

那么,我们为什么要使用modJS呢?

有以下几点:

  1. 加载器更小

上面已经提到,200+行和2000+行的差异

  1. 配合构建工具,开发体验更好

之前开发时,需要将每一个模块的代码单独放在define内部,并且需要申明每一个依赖。 而现在,只需要使用类似nodejs的方式编写代码,需要使用某个依赖模块时,直接require('id')即可。 发布编译时,由构建工具统一添加define包裹,自动添加模块id(默认根据路径生成,也可以在fis3的配置中声明格式)。整体的开发体验更好一些。

此外,js文件打包及异步依赖的问题,也可以通过生成resourceMap来解决。

一般情况下,modJS配合fis3已经可以满足大部分需求,并且官方还提供了完整支持amd规范的esl-mod.js。

如果不够用,也可以在modJS的基础上定制一些功能来满足需求,因为源码只有200行,代码也很清晰简单。

我们的项目在切换到modJS时,由于项目比较复杂(2000+文件),一些特殊的需求最终也是通过定制modJS得到解决,这里分享几点:

遇到哪些问题

  • 同步(直接require)的依赖需要打包,异步依赖使用require.async加载

requirejs将所有依赖模块在define方法的参数中声明,所以可以保证先异步加载需要的模块,最后再执行factory。

而modJS设计之初,便考虑到稍微大型点的前端项目都会打包模块js减少请求优化性能,依赖的模块其实早已合并打包,并不需要在define中声明后再异步加载。

所以需要将所有异步的模块以require.async方法来加载。

以我们的项目为例,首次加载时,会加载3个打包的js文件,分别是基础库(modjs、jquery、badjs)、base.js(其他打包的通用模块,初始化一些变量)、mod.main.js(当前页面用到的逻辑打包)。 当用户点击其他页面(非刷新)时,再异步加载该页面用到的mod.main.js(其他页面打包合并后的js),这部分js的模块id和url由构建工具统一打到resourceMap中。

  • 不支持直接引用远程url,包括同步和异步方式都不支持。

由于历史原因,项目中存在一些如下形式的代码:

define(id,['http://a','http://b'],function(a,b){
    a.xxx(b)
    ...
})

通过脚本统一替换为commonJS规范后,旧代码变成了这样:

var a = require('http://a');
var b = require('http://b');
a.xxx(b)
...

这种同步方式的代码目前没什么好的解决办法,最后重构代码解决。

异步的方式稍微好一些,可以通过构建将远程url打入到resourceMap。

  1. 异步加载方法require.async([deps],callback)中的callback触发

modJS加载异步模块时,将callback回调加入一个队列,然后将依赖模块的script标签打入html的head。 但是callback并不是通过script的onload事件触发,而是通过依赖模块的define方法触发。

当我们只是想用require.async异步加载一个非amd规范的脚本时(例如一些第三方的组件、jquery插件等),由于该脚本并没有被define方法包裹,所以无法触发回调的逻辑。

虽然理论上不应该有这个问题,一个项目的模块化方案应该统一,每一个模块都应该使用define包裹,但现实就这样。

  1. 同时异步加载多个模块时,脚本的加载顺序问题

modJS异步加载时,会将多个script脚本同时插入到head,并不会维护脚本的加载顺序。

这个问题,怎么说,理论上模块的依赖关系都应该由加载器来管理,而不应该出现脚本的加载依赖问题。但现实就这样。

当然,如果你愿意的话也可以将源码改成这样的形式:

require.async(moduleA,function(){
    require.async(moduleB,function(){
        ...do something
        ...囧
        ...do something
    });
});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏高爽的专栏

Aptana:JavaScript开发利器

简介        Aptana是一个非常强大、开源的专注于Ajax开发的开发工具,看下开源中国社区中对它的功能描述: JavaScript,JavaScri...

27800
来自专栏西安-晁州

easyui内嵌iframe问题解决

项目中使用easyui的tab页,每个tab页均内嵌iframe,现在要在tab页中控制新增一个同级别的tab页,记录如下: 首先是main.html主页面: ...

42200
来自专栏高爽的专栏

oncopy和onpaste

       在Javascript中,有相应的事件可以监听复制和粘贴,那就是oncopy和onpaste。        oncopy: demo: <bo...

24700
来自专栏西安-晁州

js返回树形结构数据

/** * 树形结构转换 * @param a * @param idStr * @param pidStr * @param chindrenStr...

51700
来自专栏老马寒门IT

01-老马jQuery教程-jQuery入口函数及选择器

这套jQuery教程是老马专门为寒门子弟而录制,希望大家看到后能转发给更多的寒门子弟。视频都是免费,请参考课程地址:https://chuanke.baidu....

26100
来自专栏腾讯IVWEB团队的专栏

Promise 实践

promise已经是成为我们解决回调炼狱的常用方案,而且已经得到官方标准支持,如果你刚刚开始使用Promise,本文将帮助你了解几个常见的几个Promise的使...

35200
来自专栏社区的朋友们

Amazon Aurora 深度探索(一)

本文对 Aurora 系统的实现从整体架构、存储、事务处理三个方面进行深入探讨,基于其论文和相关资料讨论具体实现细节,又跳出其外、从数据库内核技术实现的角度对 ...

2.5K20
来自专栏谭正中的专栏

TensorFlow 入门(2):使用DNN分类器对数据进行分类

本文作者通过分析《高级API入门教程》这篇文章中的实例:教我们如何使用DNN(深度神经网络)分类器实现对鸢尾花的分类,并对其提出举一反三的案例,提升学习效果,并...

15.5K40
来自专栏高爽的专栏

JS判断滚动条是否停止滚动

       背景:昨天一个同事有种需求,有一个展示数据区域的div,带滚动条,当滚动条滚动时,需要向后台发请求,计算数据,再拿到前台展示。        分析...

47900
来自专栏Script Boy (CN-SIMO)

[JavaScript]自执行函数

最近在接触mui的时候,遇到了一段代码: 1 (function($, doc) { 2 $.init({ 3 ...

32100

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励