失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > angular源码分析:angular的源代码目录结构说明

angular源码分析:angular的源代码目录结构说明

时间:2019-05-02 05:55:33

相关推荐

angular源码分析:angular的源代码目录结构说明

一、读源码,是选择“编译合并后”的呢还是“编译前的”呢?

有朋友说,读angular源码,直接看编译后的,多好,不用管模块间的关系,从上往下读就好了。但是在我看来,阅读编译后的源码至少有两点不好。

1.编译已经将所有的代码合并在一起了,这会丢失掉作者模块设计的思想,不利于理解代码架构的精髓,甚至想理解代码都很难。2.编译合并后的angular代码有2万多行,想要看完,早已望而生畏。相反阅读编译前的代码,可以一个模块一个模块的逐个击破。

但是编译前的源码中的确文件一大堆,一开始靠不清楚都是拿来干嘛的,这可能是初学者源代码阅读一个很大的障碍。我今天要做的事就是把angular的angular的目录和文件的结构理清分享给大家。

二、Gruntfile.js

1.angular的编译合并以及测试使用的是grunt框架,所以首先应该从这个文件着手。

查看其源代码。

var files = require('./angularFiles').files;var util = require('./lib/grunt/utils.js');

注意:在grunt开头引入了这个两个文件:angularFiles.js 和 ./lib/grunt/utils.js。

2.angularFiles.js:

var angularFiles = {'angularSrc': [...],'angularLoader': [...],'angularModules': {'ngAnimate': [...],'ngCookies': [...],'ngMessageFormat': [...],'ngMessages': [...],'ngResource': [...],'ngRoute': [...],'ngSanitize': [...],'ngMock': [...],'ngTouch': [...],'ngAria': [...]},'angularScenario': [...],'angularTest': [...],'karma': [...],'karmaExclude': [...],'karmaScenario': [...],"karmaModules": [...],'karmaJquery': [...],'karmaJqueryExclude': [...]};...if (exports) {exports.files = angularFiles;exports.mergeFilesFor = function() {var files = [];Array.prototype.slice.call(arguments, 0).forEach(function(filegroup) {angularFiles[filegroup].forEach(function(file) {// replace @refvar match = file.match(/^\@(.*)/);if (match) {files = files.concat(angularFiles[match[1]]);} else {files.push(file);}});});return files;};}

可以看到,其中就是定义了一个数组(files,其中每个元素都是一个文件名的数组。我们可以轻易的发现,files其实将所有的angular源码给分组追踪起来了)和一个函数(mergeFilesFor,用于合并angularFiles中的元素)。

3.将“/lib/grunt/utils.js”文件跳过,在Gruntfile.js中搜索 关键词 build,可以看到如下代码:

build: {scenario: {...},angular: {dest: 'build/angular.js',src: util.wrap([files['angularSrc']], 'angular'),styles: {css: ['css/angular.css'],generateCspCssFile: true,minify: true}},loader: {...},touch: {...},mocks: {...},sanitize: {...},resource: {...},messageformat: {...},messages: {...},animate: {...},route: {...},cookies: {...},aria: {...},"promises-aplus-adapter": {...}},

我们可以猜测,"angular: {...}"就是对应angular.js的编译配置,而"loader: {...}"对应的是angular-loader.js,"touch: {...}"对应的是angular-touch.js,……

那么,我们重点分析angular.js的编译配置,其他的都是类似的。

angular: {dest: 'build/angular.js',src: util.wrap([files['angularSrc']], 'angular'),styles: {css: ['css/angular.css'],generateCspCssFile: true,minify: true}},

4.util.wrap是什么鬼。从var util = require('./lib/grunt/utils.js');,我们知道应该阅读./lib/grunt/utils.js。

果然其中有一个导出的函数wrap

wrap: function(src, name){src.unshift('src/' + name + '.prefix');src.push('src/' + name + '.suffix');return src;},

另外还有一个build函数,主要功能是合并js代码

build: function(config, fn){var files = grunt.file.expand(config.src);var styles = config.styles;var processedStyles;//concatvar src = files.map(function(filepath) {return grunt.file.read(filepath);}).join(grunt.util.normalizelf('\n'));//processvar processed = this.process(src, grunt.config('NG_VERSION'), config.strict);if (styles) {processedStyles = this.addStyle(processed, styles.css, styles.minify);processed = processedStyles.js;if (config.styles.generateCspCssFile) {grunt.file.write(removeSuffix(config.dest) + '-csp.css', CSP_CSS_HEADER + processedStyles.css);}}//writegrunt.file.write(config.dest, processed);grunt.log.ok('File ' + config.dest + ' created.');fn();function removeSuffix(fileName) {return fileName.replace(/\.js$/, '');}},

通过简单推理,build函数对代码的合并时根据配置数组的顺序粘贴完成的,而angular所包含的文件如下:

'angularSrc': ['src/angular.prefix', //util.wrap函数加入的前缀代码'src/minErr.js','src/Angular.js','src/loader.js','src/stringify.js','src/AngularPublic.js','src/jqLite.js','src/apis.js','src/auto/injector.js','src/ng/anchorScroll.js','src/ng/animate.js','src/ng/animateCss.js','src/ng/browser.js','src/ng/cacheFactory.js','src/ng/compile.js','src/ng/controller.js','src/ng/document.js','src/ng/exceptionHandler.js','src/ng/forceReflow.js','src/ng/http.js','src/ng/httpBackend.js','src/ng/interpolate.js','src/ng/interval.js','src/ng/locale.js','src/ng/location.js','src/ng/log.js','src/ng/parse.js','src/ng/q.js','src/ng/raf.js','src/ng/rootScope.js','src/ng/sanitizeUri.js','src/ng/sce.js','src/ng/sniffer.js','src/ng/templateRequest.js','src/ng/testability.js','src/ng/timeout.js','src/ng/urlUtils.js','src/ng/window.js','src/ng/cookieReader.js','src/ng/filter.js','src/ng/filter/filter.js','src/ng/filter/filters.js','src/ng/filter/limitTo.js','src/ng/filter/orderBy.js','src/ng/directive/directives.js','src/ng/directive/a.js','src/ng/directive/attrs.js','src/ng/directive/form.js','src/ng/directive/input.js','src/ng/directive/ngBind.js','src/ng/directive/ngChange.js','src/ng/directive/ngClass.js','src/ng/directive/ngCloak.js','src/ng/directive/ngController.js','src/ng/directive/ngCsp.js','src/ng/directive/ngEventDirs.js','src/ng/directive/ngIf.js','src/ng/directive/ngInclude.js','src/ng/directive/ngInit.js','src/ng/directive/ngList.js','src/ng/directive/ngModel.js','src/ng/directive/ngNonBindable.js','src/ng/directive/ngOptions.js','src/ng/directive/ngPluralize.js','src/ng/directive/ngRepeat.js','src/ng/directive/ngShowHide.js','src/ng/directive/ngStyle.js','src/ng/directive/ngSwitch.js','src/ng/directive/ngTransclude.js','src/ng/directive/script.js','src/ng/directive/select.js','src/ng/directive/style.js','src/ng/directive/validators.js','src/angular.bind.js','src/publishExternalApis.js','src/ngLocale/angular-locale_en-us.js','src/angular.suffix' //util.wrap函数加入的后缀代码],

5.分析下angular.prefix 和 angular.suffix

angular.prefix

/*** @license AngularJS v"NG_VERSION_FULL"* (c) - Google, Inc. * License: MIT*/(function(window, document, undefined) {

angular.suffix

jqLite(document).ready(function() {angularInit(document, bootstrap);});})(window, document);

很熟悉吧,angular.prefix 和 angular.suffix 刚好构成一个自动执行的匿名函数。在这个函数的最后做了一个操作,等待jqLite准备好后,执行angularInit(document, bootstrap);,如果我们今天是分析angular的代码可能就会继续去追jqLite函数以及angularInit函数。但是今天不是,我们的目标是树立代码目录结构。其实目录结构已经出来了。

三、angular的代码目录结构:

├─── angular.prefix //util.wrap函数加入的前缀代码 │ ├─── minErr.js //错误处理 ├─── Angular.js//主要定义angular的工具函数,我们[上一期]主要讲了这个 ├─── loader.js //定义了setupModuleLoader函数 ├─── stringify.js //定义了对象序列化serializeObject,和对象调试输出字符串serializeObject ├─── AngularPublic.js //定义了angular导出的函数和变量 ├─── jqLite.js //定义jqLite,一个mini的jQuery ├─── apis.js//定义了关于对象hash值的几个函数 ├─── auto │└─── injector.js //依赖注入和模块加载,主要在这里实现,我在[第二期]讲过部分 │ ├─── ng//定义angular的各种服务的目录,该目录下一个文件按名字对应一个服务 │ ├─── anchorScroll.js │ ├─── animate.js │ ├─── animateCss.js │ ├─── browser.js │ ├─── cacheFactory.js │ ├─── compile.js │ ├─── controller.js │ ├─── document.js │ ├─── exceptionHandler.js │ ├─── forceReflow.js │ ├─── http.js │ ├─── httpBackend.js │ ├─── interpolate.js │ ├─── interval.js │ ├─── locale.js │ ├─── location.js │ ├─── log.js │ ├─── parse.js │ ├─── q.js │ ├─── raf.js │ ├─── rootScope.js │ ├─── sanitizeUri.js │ ├─── sce.js │ ├─── sniffer.js │ ├─── templateRequest.js │ ├─── testability.js │ ├─── timeout.js │ ├─── urlUtils.js │ ├─── window.js │ ├─── cookieReader.js │ ├─── filter.js │ ├─── filter //过滤器目录,该目录下一个文件对应一个过滤器 │ │├─── filter.js │ │├─── filters.js │ │├─── limitTo.js │ │└─── orderBy.js │ └─── directive//指令目录,该目录下一个文件对应一个angular指令 │├─── directives.js │├─── a.js │├─── attrs.js │├─── form.js │├─── input.js │├─── ngBind.js │├─── ngChange.js │├─── ngClass.js │├─── ngCloak.js │├─── ngController.js │├─── ngCsp.js │├─── ngEventDirs.js │├─── ngIf.js │├─── ngInclude.js │├─── ngInit.js │├─── ngList.js │├─── ngModel.js │├─── ngNonBindable.js │├─── ngOptions.js │├─── ngPluralize.js │├─── ngRepeat.js │├─── ngShowHide.js │├─── ngStyle.js │├─── ngSwitch.js │├─── ngTransclude.js │├─── script.js │├─── select.js │├─── style.js │└─── validators.js ├─── angular.bind.js //简单几行代码,判断是否已经加载了jQuery,如果是,直接使用jQuery,而不使用jqLite ├─── publishExternalApis.js // `publishExternalAPI(angular);`导出变量和接口 ├─── ngLocale │ └───angular─locale_en─us.js //本地化处理,其中定义地区性的星期月份神马的 │ └── angular.suffix //util.wrap函数加入的后缀代码

上一期:angular源码分析:angular中各种常用函数,比较省代码的各种小技巧

下一期:angular源码分析:angular中jqLite的实现——你可以丢掉jQuery了

ps:在这《angular源码分析:angular中jqLite的实现——你可以丢掉jQuery了》这一期中,我将讲述笔者在其中遇到的一个坑。

如果觉得《angular源码分析:angular的源代码目录结构说明》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。