Angular1距离2009年发布已经好多年了,Angular2也已经出了Beta版,估计今年就能正式发布。大多数人对于Angular1.X的认识仅限于可以在项目中使用,对于其中的深层原理知道的并很少。市面上也没有特别好的介绍Angular实现原理的教程或者书籍。今天在看技术文档的时候偶然发现了一本比较好的Angular底层原理书籍《build your own AngularJS》,费了好大功夫买下了全本,随之开始了Angular1.X的底层实现的探索之旅。本系列文章会按照书中的章节,每一章节独立成为一篇文章,按书中的介绍一步步来动手实现本身的AngularJS,以便深刻学习。本系列文章的目的主要是以更为简单容易接受的方式让读者轻松学习整个过程而不用购买这本书(30多刀啊),同时记录本身的学习过程,关于本系列的全部源代码参见这里。javascript
本文的主要内容是构建一个可运行的项目做为实现AngularJS的基础代码项目库,初始化整个项目,包括代码打包,模块化,测试,代码lint,使用NPM Scripts进行自动化脚本运行等,这些工做是从此实现的基础。html
1.创建项目并初始化package.json文件java
首先确保你的机器上已经安装了NodeJS和NPM,接着运行如下命令行node
mkdir myangular cd myangular mkdir test mkdir src
首先建立项目根目录myangular,而后在根目录下建立test和src两个文件夹,分别用来存放测试文件和源文件,接着输入如下命令行jquery
npm -y init
会在项目根目录下建立一个package.json文件,用来存放NPM相关的配置信息。git
2.建立源文件并启用JSHintgithub
对于一个框架的实现须要保证代码一致性和遵循必定的规范,这就须要用到JSHint插件。首先在src文件夹下建立一个hello.js的文件,用来测试,内容以下:npm
function sayHello() { return "Hello, world!"; }
接着输入如下命令安装JSHintjson
npm install --save-dev jshint
这会在项目根目录下建立node_modules文件夹并将全部NPM install安装的文件都放在这里。并在package.json的devDependencies配置项中加入一条关于JSHint的配置信息,表示这是在开发模式中须要加入的依赖包,在生产模式下不须要。接着在项目根目录下建立一个.jshintrc文件,用来存放JSHint须要读取的配置,它的内容以下:数组
{ "browser": true, "browserify": true, "devel": true }
当咱们运行JShint的时候,就会遵循这个配置文件下的信息来查看代码是否符合规范。
接着在package.json文件中添加以下配置信息,用来运行JShint,检查src目录下的文件是否存在问题。
"scripts": { "lint": "jshint src" }
最后,使用以下命令行运行JSHint
npm run lint
3.为项目加入单元测试
在单元测试阶段须要用到Jasmine,karma以及Sinon.JS,其中Jasmine是一个单元测试框架,karma是一个test runner,Sinon.js是须要用到的一个测试库。
首先安装Jasmine及Sinon.js
npm install --save-dev jasmine-core sinon
接着安装karma及其相关插件
npm install --save-dev karma karma-jasmine karma-jshint-preprocessor
最后安装Phantom.js做为浏览器的测试环境
npm install --save-dev phantomjs karma-phantomjs-launcher
以上都安装完成以后须要对karma进行配置,在项目根目录下建立一个karma.conf.js文件,其内容以下:
module.exports = function(config) { config.set({ frameworks: ['jasmine'], files: [ 'src/**/*.js', 'test/**/*_spec.js' ], preprocessors: { 'test/**/*.js': ['jshint'], 'src/**/*.js': ['jshint'] }, browsers: ['PhantomJS'] }) }
主要做用是告诉karma使用jasmine做为测试框架,须要测试的文件主要是src目录和test目录下的文件,在处理这些文件以前须要使用jshint进行预处理,同时测试的浏览器环境是PhantomJS.
因为咱们须要在测试文件中使用全局变量诸如describe等,因此须要在.jshintrc文件中设置,修改该文件,其被修改的内容以下:
{ "browser": true, "browserify": true, "devel": true, "globals": { "jasmine": false, "describe": false, "it": false, "expect": false, "beforeEach": false, "afterEach": false } }
接着修改package.json文件中的scripts配置项以下,用来运行自动化脚本。
"scripts": { "lint": "jshint src test", "test": "karma start" }
这时,使用npm run lint就可以运行JShint去检测test和src文件夹下的文件是否符合语法规范,使用npm run test 就能运行全局的测试文件。
最后,在test文件夹下建立一个hello_spec.js文件,运来存放咱们的测试用例,其内容以下:
describe("Hello", function() { it("says hello", function() { expect(sayHello()).toBe("Hello, world!"); }); });
这时运行npm test 就能运行hello_spec.js这个测试用例,在命令行中出现诸如如下的结果:
能够看出,它不只有咱们测试用例自身运行的结果,在测试用例运行的时候,还会启动JSHint并将运行结果显示出来。
4.为项目添加模块化解决方案
因为Angular自己出现的较早,当时尚未AMD,CommonJS等模块化解决方案,因此它其实是采用全局变量及函数直接定义整个代码库的,可是在该项目中咱们使用CommonJS辅以browserify做为咱们的模块化解决方案。
首先安装browserify及其相关插件
npm install --save-dev browserify karma-browserify
安装成功后修改src目录下的hello.js文件,让其符合CommonJS格式,其内容以下:
module.exports = function sayHello() { return "Hello, world!"; };
同时修改test目录下的hello_spec.js文件,让其符合CommonJS格式。
var sayHello = require('../src/hello'); describe("Hello", function() { it("says hello", function() { expect(sayHello()).toBe("Hello, world!"); }); });
最后,修改karma.conf.js让其和browserify结合起来使用,修改后的内容以下:
module.exports = function(config) { config.set({ frameworks: ['browserify', 'jasmine'], files: [ 'src/**/*.js', 'test/**/*_spec.js' ], preprocessors: { 'test/**/*.js': ['jshint', 'browserify'], 'src/**/*.js': ['jshint', 'browserify'] }, browsers: ['PhantomJS'], browserify: { debug: true } }) }
配置中发生变化的主要是告诉karma使用browserify而且在进行测试前使用browserify进行预处理,同时启用sourcemap便于程序debug.
5.为项目中添加Lodash和jQuery
Angular自身的实现是没有jQuery的,可是因为咱们更加关注的是Angular自身的实现而不是其对于Utility函数或者某些DOM操做的实现,因此为了简化,这里使用Lodash来为咱们提供对对象或者数组的处理,使用jQuery进行DOM查询及操做。
npm install --save lodash jquery
安装完成后,修改src目录下的hello.js,其内容被修改成使用Lodash的方法以下:
var _ = require('lodash'); module.exports = function sayHello(to) { return _.template("Hello, <%= name %>!")({name: to}); };
并修改test目录下的hello_spec.js,以下:
var sayHello = require('../src/hello'); describe("Hello", function() { it("says hello", function() { expect(sayHello('Jane')).toBe("Hello, Jane!"); }); });
运行npm test能够看到测试的最终效果。
至此,咱们已经搭建成了一个本身实现Angular的基础环境,从此全部的代码及实现都会在这个代码库中进行。全部的代码都须要严格遵循JShint代码规范并进行单元测试,接下来一块儿来进行Angular底层实现吧!PS:本项目的全部代码在这里,该系列文章会不按期更新。