背景
公司的产物线涵盖多个产物,这些产物中会有一些雷同的功用,如登录,认证等,为了坚持这些功用在各个产物中的一致性,我们在各个产物中保护一份雷同的代码。这带来了很大的不方便:当涌现新的需求时,不能差别时在多个产物中变动代码,使它们坚持一致。为了处理这个题目,我们能够将这些大众部份抽取出来放在一个零丁的子项目中,其他项目只是援用该子项目,当涌现新的需求时,我们只需转变该子项目即可。
在这个思绪的基本上,有两个题目须要处理:
以何种体式格局保护子项目
怎样保护产物对子项目标援用
我们先从一个一般的angular项目提及。比方,假如你想在你的项目中引入Angular UI Bootstrap组件,一般你会怎么做?
在bower.json中增添所须要的dependencies:
{ "name": "your project", "version": "0.0.1", "dependencies": { "angularJS": "1.4.x", "angular-animate": "1.4.x", .... } }
运用bower install敕令,装置dependencies,并援用:
<script src="../bower_components/angular.js" type="text/javascript"></script>
在你的项目中声明dependencies:
angular.module('myModule', ['ui.bootstrap']);
经由历程以上的例子我们能够获得肯定的启发:
子项目终究应当以angular module的情势涌现
运用bower去保护对包的援用
模块化
模块需求剖析
可设置,当运用该模块时能够对该模块通报参数
可构建,将星散的多个文件构建成一个文件
可测试,保证模块的鲁棒性
可宣布,供其他项目援用
包含完全的事例代码,供其他人参考
观点剖析
可设置
我们在代码层面上能够经由历程provider来完成。比方:
angular.module('myModule')
.provider('myProvider', function() {
var name = null;
// setName can be called duaring module init
this.setName = function (newName) {
name = newName;
};
return {
handleName : function() {
// do something with name
}
};
})
在另一个module中引入该module时,我们能够转变该module中name的值:
angular.module('anotherModule', ['myModule'])
.config(function(myProviderProvider){
myProviderProvider.setName('name');
});
provider是模块之间交换的桥梁,它能够使模块到达可设置。
可构建
在angular中,一个模块的实质就是一个定名空间,在该定名空间中我们能够增添provider, directive, factory, constant等,它实际上就是一个功用的鸠合。声明情势一般以下:
angular.module('myModule', [dependencies])
.directive('myDirective', ...)
.factory('myFactory', ...);
...
directive是angular中最重要的观点,它是angular 1.x中完成组件化的基本。factory一般是为了完成一些辅佐功用,如与后端举行数据交互或供应一些util要领等。然则为了代码的可保护性,一般它们会将它们放在一个零丁的文件中, 如:
file1.js为模块的声明文件:
angular.module('myModule', [dependencies]);
file2.js为一个directive声明文件:
angular.module('myModule')
.directive('mydirective', function() {
...
});
file2.js为一个factory的声明文件:
angular.module('myModule')
.factory('myfactory', function() {
...
});
然则在宣布版本中,我们愿望一切的这些文件兼并在同一个js文件中,这就是构建的历程。我们能够运用gulp构建东西完成该目标。directive中有时会包含模板html文件,我们将html文件经由历程angular的$templateCache效劳也打包进js中。
可测试
一般前端的测试分为两种: 单位测试和集成测试(又叫做E2E测试)。单位测试的目标是为了测试一个接口或许功用是不是能获得预期的效果,测试对象一般为一个函数,然则前端最大的题目就是浏览器的兼容题目,可能在一个浏览器中能跑的代码在另一个浏览器中涌现毛病,所以我们须要在多个浏览器中去举行测试,我们能够运用gulp搭配测试框架karma去简朴的完成在多浏览器下的单位测试。集成测试是站在用户的角度上去实行种种操纵,看产物是不是稳固等。因为该模块中只是涌现一些简朴的UI组件,并不是一个完全的产物,所以并没有做相干的集成测试。
可宣布
这一部份会鄙人一章bower治理对子项目援用中细致申明。
包含事例代码
因为模块会在多个项目中被差别的人运用,关于这些人最快熟习该模块的要领就是经由历程一些demo去相识,所以每一个模块中应当包含肯定的事例代码供模块的运用者参考。
模块完成
目次构造以下:
javascript-modules
- module1
- lib
- myproject.module.js
- component
- mydirective.directive.js
- template.html
- templateStyle.scss
- myfactory.factory.js
- myprovider.provider.js
- ....spec.js
...
- release
- myproject.bundle.js
- myproject.bundle.css
- example
- example1
- example2
- gulp
- task1.js
- task2.js
...
- gulpfile.js
- karma.js
- package.json
申明:
lib: 源代码目次
release: 宣布版本目次(只包含js和css文件)
example: 事例代码目次,详细的事例代码目次下包含index.html文件,在该html文件中引入release版本的js和css,然后启动http-server敕令翻开当地效劳器举行测试
gulp: gulp task目次
gulpfile.js: 用于实行gulp目次中的种种task
karma.js: karma设置文件
package.json: 设置文件
gulp中应包含以下task:
build: 兼并一切的html文件到$templateCache中,兼并一切的js文件,将scss等编译成css
test: 实行lib下的一切测试文件
release: 将打包后的终究代码上传到内部包治理效劳器等
PS: 因为汗青遗留题目,angular中component和directive之间的界线模糊不清。指令应只封装DOM操纵,而组件代表一个自力更生的自力单位 – 有本身的视图和数据逻辑。在angular1.5中增添了component的观点,我们应当越发清楚的区分component和directive,在运用时directive只应当实行封装DOM的操纵,而不该当去制造DOM节点,也就是说directive中的restrict应设置为A。
bower治理援用
模块版本宣布应遵照semver(语义化版本)准绳。
版本花样为:主版本号.次版本号.订正号(MAJOR.MINOR.PATCH)。版本号递增划定规矩以下:
主版本号:当你做了不兼容的API修改,
次版本号:当你做了向下兼容的功用性新增,
订正号:当你做了向下兼容的题目修改。
版本号的治理应当包含在gulp release使命中。
一般我们愿望我们开发出的模块只是对企业内部可见,对外部不可见。这就请求我们不能运用寻常的体式格局去运用bower举行包的宣布和依靠治理。在自创了后端的一些包治理思绪后,我们将该包宣布在企业内部的私有包治理效劳器上,然后在bower.json中经由历程以下体式格局来引入包:
{
"module":"address/module-version.zip"
}
每次当有新的版本的包宣布时,我们只须要在bower.json中转变version号,然后运用bower install重新装置新版本的包即可到达更新包的目标。
总结
本文总结了angular 1.x多项目同享子项目工程化方面的一些实践,并不涉及到庞杂的代码,重要涉及到angular module的观点,运用bower举行包治理,运用gulp作为自动化东西等工程化的学问。
上述要领也存在肯定的题目,每次版本更新时,都要在援用它的各个项目中更新版本号并运用bower install重新装置该模块。
一种更好的思绪是运用git submodule/subtree,因为并没有在这方面的实践经验,所以不再赘述。
本文重如果针对angular1.x版本的实践。因为当前angular2已宣布,它供应了壮大的组件功用,所以针对angular2会有更好的组件化体式格局完成。