题外话
前两天,我平生第一次被人催更,虽然是个伪粉丝,但还是有那么一点点小兴奋。“TypeScript”这一系列,从实际的订阅数据上看非常尴尬,比起vue.js的系列差好远。脚手架(or 手脚架)框架盛行的世界,我的这个东西,便像是一株不合群的奇葩傲立于世间,除了孤芳自赏,剩下就是自娱自乐。
No,No,No。。。。前面这一段并不是丧气的话,只是表明我个人玩技术的一种固有心态,便是“自娱自乐”!
正题
其实,我这几天把业余时间都放在了重构这个TS的Demo项目上。准备把项目弄得相对完整些,并且把代码优化得能够入得了大家的眼后,才逐步把其中的过程和思路剖析出来给大家看。不过,既然有人等不及,我就继续来写边边角角用于填坑的内容吧。
模块化(Module)
首先,什么是模块化?
我的理解:系统功能的拆解归类抽象化而形成的功能区块,然后把这些区块的功能组合起来便形成一套完整的系统解决方案了。我的模块化的依据是OO(Object Oriented,面向对象)。为什么要模块化?不模块化可以吗?
模块化代码可读性更强,好维护,重用方便。至于模不模块化看实际项目情况,功能简单结构单一的其实也没什么好模块化的;如果是比较复杂的系统,建议还是弄一下的好,不然假设再1个ts里面堆上一百几十个类,几千行代码,谁看了谁都会骂娘,程序员何苦为难程序员呢?
我的模块设计
假设,我要做一个用户查询产品的系统。模块划分如下:
src/
├── app.ts
├── libs/
│ └── router.ts
├── modules/
│ ├── product/
│ │ ├── index.ts
│ │ ├── list.ts
│ │ └── detail.ts
│ └── user/
│ ├── index.ts
│ ├── login.ts
│ └── info.ts
└── utils/
├── http.ts
├── ui.ts
└── cache.ts
说明一下,我的demo是web前端,所以modules下对应每个文件对应的是一个页面功能。index.ts
除外!index.ts作为模块聚合导出的入口来用的。例如:
import { List } from "./list";
import { Detail } from "./detail";
export { Detail, List };
然后,在app.ts里的import就可以这样:
import * as Product from "./modules/product/index";
var listPage = new Product.List();
require.js加载模块
说完模块化,趁热打铁就说一下模块的加载。其实,上一篇最后提到过,我是用require.js来做编译后的js的加载。众所周知,require.js是javascript模块加载的AMD派系的代表。早前的项目我也用过,比较熟所以就选它了。
被加载的模块的写法,这里直接略过。因为在tsconfig.json
里面module
设为amd
的话,tsc编译后就会自动生成对应的格式,我们几乎感觉不到。
按照上面的项目模块结构,我只需要在index.html引入require.js,然后加载的入口指向app.js便可,也就是下面data-main
这一段。
<script src="//cdn.staticfile.org/require.js/2.3.6/require.min.js" data-main="scripts/app"></script>
app.js 会按照app.ts 的各项 import 把 模块间的引用关系和次序都弄好,用起来非常非常的轻松。
对于第三方的js库,就要借助require.config来配置一下(没错,上一片有提到过)。可以把这个脚本写在html文件底部,也可以独立弄一个js文件<script>引用进页面。对于外部第三方的库最好,用shim
配置建立一个依赖的关系,避免网络原因,所依赖第三方库没有先加载导致脚本报错。
require.config({
paths: {
'jquery': '//g.alicdn.com/sj/lib/jquery/dist/jquery.min',
'marked': '/js/libs/marked.min'
},
shim: {
'app': {
deps: ['jquery']
}
}
});
模块的发布
细心的读者可能会数一下,我这么一个超简单的Demo项目都已经有十多个js了。那么一个真正的项目岂不是得有上百个js文件?!HTTP请求会吓死人的!冒昧地下个结论,看到这里会吃鲸的很定是新手。因为,老鸟们会很淡定的说,打包起来就完事了嘛~
是的,这里先卖个关子,打包发布的内容留到下一讲,敬请期待~~