Angular1距离2009年发布已经好多年了,Angular2也已经出了Beta版,估计今年就能正式发布。大多数人对于Angular1.X的认识仅限于能够在项目中使用,对于其中的深层原理知道的并不多。市面上也没有特别好的介绍Angular实现原理的教程或者书籍。今天在看技术文档的时候偶然发现了一本比较好的Angular底层原理书籍《build your own AngularJS》,费了好大功夫买下了全本,随之开始了Angular1.X的底层实现的探索之旅。本系列文章会按照书中的章节,每一章节独立成为一篇文章,按书中的介绍一步步来动手实现自己的AngularJS,以便深入学习。本系列文章的目的主要是以更为简单容易接受的方式让读者轻松学习整个过程而不用购买这本书(30多刀啊),同时记录自己的学习过程,关于本系列的所有源代码参见这里

  本文的主要内容是构建一个可运行的项目作为实现AngularJS的基础代码项目库,初始化整个项目,包括代码打包,模块化,测试,代码lint,使用NPM Scripts进行自动化脚本运行等,这些工作是今后实现的基础。

1.建立项目并初始化package.json文件

首先确保你的机器上已经安装了NodeJSNPM,接着运行以下命令行

mkdir myangular
cd myangular
mkdir test
mkdir src

首先创建项目根目录myangular,然后在根目录下创建test和src两个文件夹,分别用来存放测试文件和源文件,接着输入以下命令行

npm -y init

会在项目根目录下创建一个package.json文件,用来存放NPM相关的配置信息。

2.创建源文件并启用JSHint

对于一个框架的实现需要保证代码一致性和遵循一定的规范,这就需要用到JSHint插件。首先在src文件夹下创建一个hello.js的文件,用来测试,内容如下:

function sayHello() {
return "Hello, world!";
}

接着输入以下命令安装JSHint

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.为项目加入单元测试

在单元测试阶段需要用到Jasminekarma以及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:本项目的所有代码在这里,该系列文章会不定期更新。

  

一步步构建自己的AngularJS(1)——项目初始化的更多相关文章

  1. 一步步构建自己的AngularJS(2)——scope之$watch及$digest

    在上一节项目初始化中,我们最终得到了一个可以运行的基础代码库,它的基本结构如下: 其中node_modules文件夹存放项目中的第三方依赖模块,src存放我们的项目代码源文件,test存放测试用例文件 ...

  2. JAVA8,SPRING,ANGULARJS对项目

    java8+spring+angularjs 项目应用 最近有写一个电子订单商务网站,使用JAVA8,SPRING,ANGULARJS对项目使用的技术和大家分享. 第一次写博客,哪有不对需要改正的请联 ...

  3. Github+yeoman+gulp-angular初始化搭建angularjs前端项目框架

    在上篇文章里面我们说到了Github账号的申请与配置 那么当你有了Github账号并创建了一个自己的Github项目之后,首要的当然是搭建自己的项目框架啦! 本人对自己的定位是web前端狗,常用开发框 ...

  4. Java网络编程与NIO详解2:JAVA NIO 一步步构建I/O多路复用的请求模型

    微信公众号[黄小斜]作者是蚂蚁金服 JAVA 工程师,专注于 JAVA 后端技术栈:SpringBoot.SSM全家桶.MySQL.分布式.中间件.微服务,同时也懂点投资理财,坚持学习和写作,相信终身 ...

  5. 构建自己的AngularJS,第一部分:作用域和digest 转摘:http://www.ituring.com.cn/article/39865

    构建自己的AngularJS,第一部分:Scope和Digest 原文链接:http://teropa.info/blog/2013/11/03/make-your-own-angular-part- ...

  6. 使用spring 4.0 + maven 构建超简单的web项目

    一.需求 使用spring去管理web项目,是目前非常流行的一种思路,本文将介绍使用maven+spring 4.0.2 来构建一个简单的web项目. 二.实现 1.新建一个maven项目,如下图所示 ...

  7. webpack构建具备版本管理能力的项目

    webpack是时下十分流行的编译和打包工具,它提供一种可扩展的loader的方式,简单的配置,便可以编译打包各类型的文件,包括js.css.image.font.html,以及各种预编译语言都不在话 ...

  8. AngularJS+requireJS项目的目录结构设想

    AngularJS+requireJS项目的目录结构设想 准备用AngularJS + require.js 作为新项目的底层框架,以下目录结果只是一个初步设想: /default    放页面,不过 ...

  9. Spring Boot 构建电商基础秒杀项目 (十二) 总结 (完结)

    SpringBoot构建电商基础秒杀项目 学习笔记 系统架构 存在问题 如何发现容量问题 如何使得系统水平扩展 查询效率低下 活动开始前页面被疯狂刷新 库存行锁问题 下单操作步骤多,缓慢 浪涌流量如何 ...

随机推荐

  1. 博客打开慢?请禁用WordPress默认的谷歌字体!

    最近几天,谷歌中国挂了之后,发现我的博客打开极慢,原以为是空间问题,可一查,发现同台服务器的用户打开并不慢,排除了空间问题后,这边查询元素发现博客打开时加载了一个链接地址“fonts.googleap ...

  2. iOS7中的ViewController切换

    转自:https://onevcat.com/2013/10/vc-transition-in-ios7/ iOS 7 SDK之前的VC切换解决方案 在深入iOS 7的VC切换效果的新API实现之前, ...

  3. MySQL数据库管理用户权限

    http://blog.itpub.net/7607759/viewspace-675079/ 2.2 授予权限 前面提到了grant命令,grant的语法看起来可是相当复杂的呐: GRANT pri ...

  4. javascript画直线和画圆的方法(非HTML5的方法)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. [Jquery]判断数据类型

    typeof [1, 2, 4] === 'object';typeof new Date() === 'object';  typeof null === 'object'; 由于typeof数组. ...

  6. Android - 广播接收者 - BroadcastReceiver

    BroadcastReceiver 介绍: 广播是一种广泛运用的在应用程序之间传输信息的机制 .而 BroadcastReceiver 是对发送出来的广播 进行过滤接收并响应的一类组件 接受一种或者多 ...

  7. HDU 4507 吉哥系列故事——恨7不成妻

    需要推下平方和的式子..维护个数,和,平方和. #include<iostream> #include<cstdio> #include<cstring> #inc ...

  8. Unity UGUI RectTransform图解

    UGUI RectTransform.Unity RectTransform详解 The first:look look API. http://docs.unity3d.com/ScriptRefe ...

  9. C# 对List<T>取交集、连集及差集

    1. 取交集 List A :{1,5,9,3,7} List B:{1,6,8,5,3,2,9,4} var intersectedList = listA.Intersect(listB, new ...

  10. 【转】Lua coroutine 不一样的多线程编程思路

    Lua coroutine 不一样的多线程编程思路 Sunday, Apr 26th, 2009 by Tim | Tags: coroutine, Lua 上周末开始看<Lua程序设计> ...