理论可见上文模块加载方案 ,这次探讨下如何设计 api 使用 js 模拟其他语言常见的模块 与包 的概念:
1.添加模块:
通过 S.add 向运行环境添加模块,模块可以添加一个简单对象,或者一个加载函数。
简单对象:
S.add("module1",{ name:"value" });
加载函数:
S.add("module2",function(S){ return something; });
如果添加的是加载函数,模块真正的值则是该函数的执行结果。
依赖注入:
添加模块时可以通过声明该模块的依赖模块名字,运行环境会将依赖的模块值通过参数注入到加载函数中:
S.add("module3",function(S,DOM,module2){ // DOM 为 dom 模块的值 //module2 为 模块2 的值 可以使用 dom ,module2 构建复杂的 module3 return module3; },{ requires:["dom","module2"] });
引用子模块:
声明依赖模块后,可以通过 require 来使用依赖模块的子模块:
S.add("module_event",function(S,Event){ //引入子模块 var EventTarget=S.require("event/target"); },{ requires:["event"] });
2.包与模块命名空间
添加模块时可以通过 “/” 引入模块命名空间 :
S.add("js/lang/integer",function(){ function Interger(){} return Integer; },{requires:["js/lang/core"]});
将定义文件放入 : http://modules/js/lang/interger.js 中,使用时,通过
S.packages({ name:"js" path:"http://modules" });
来声明 js package 对应的路径(url,not file path),而 js 包下可类似定义多个同类模块。
最终通过 use 来使用某个模块:
S.use("js/lang/interge",function(S,Integer){ //use Integer now ! });
3.执行流程
S.use("A",function(S,A){});
下载模块A,下载模块A的依赖 a,执行 a 的加载函数并初始化 a 模块值,注入 a 到 A 的加载函数并执行,初始化 A 的模块值,最终注入A到用户回调函数并执行。
小结:
约定优先配置,模块名隐含路径
去除冗余信息,模块名代表了命名空间,不需重新挂载
内置模块例如 dom ,event 并无包,属于 unnamed package ,应用模块推荐使用包机制并且顶层包名不要和内置模块冲突。
4.后期优化
主要就是自动化合并,自动管理依赖项,可见:定制模块编译工具