[Step-By-Step Angular2](1)Hello World与自动化环境搭建

随着rc(release candidate,候选版本)版本的推出,万众瞩目的angular2终于离正式发布不远啦!五月初举办的ng-conf大会已经过去了整整一个月,大多数api都如愿保持在了相对稳定的状态——当然也有router这样的例外,在rc阶段还在大面积返工,让人颇为不解——不过总得说来,现在学习angular2不失为一个恰当的时机。

Google为angular2准备了完善的文档和教程,按理说,官网(https://angular.io)自然是学习新框架的最好教材。略显遗憾的是,在Basic章节的Overview部分中,作者在开篇就明确提到这是一份准备给有经验的开发者的一份文档(This is a practical guide to Angular for experienced programmers who are building client applications in HTML and TypeScript)。换言之,如果要较好地理解官网上的文档和教程,对阅读者是有一定要求的。最显而易见的是,在angular2中,连运行入门级的hello world都需要配置编译环境和后端支持——别忘了,即使是去年火遍大江南北的react,我们在学习hello world时还能通过script引入babel来在运行时解析jsx呢(当然在生产环境上可不能这么干)。如果要细数下来,要求就更多了:node和npm、webpack或者systemjs之类的打包和模块化工具、面向对象编程、es6的基本语法和概念、Web Components等新标准……

博主在新技术新框架面前并不是一个因循守旧的人,只是有一点让我比较担忧:如果angular2的入门门槛太高,那对以后的框架推广和社区发展会不会有一些不利的影响呢?出于这个想法,博主决定推出一个step by step的博客系列,希望将angular2带给更多感兴趣、但可能暂时缺少相关开发经验的同学。

下面就是本系列博客的第一篇:Hello World与自动化环境搭建。

官网在quickstart中使用了systemjs、lite-server,配置较为复杂;为了简单起见,本文将使用大家更熟悉的gulp、browserify方案。出于相同的目的,编译的目标版本将选择es6而非es5,所以请读者在继续阅读之前请确保已经将chrome升级到最新版本。另外,node环境也请先安装好,具体步骤这里就不赘述了。

1. 创建项目,初始化package.json
创建一个新文件夹angular2-learn,然后使用输入npm init命令初始化npm环境。

npm init

如果没有特殊需求,这里可以一直使用回车键,直到整个过程完成。此时查看angular2-learn文件夹,应该多了一个package.json文件,它最重要的作用之一是保存当前项目所需要的依赖。

2. 使用npm安装运行依赖
在正式开发之前,我们需要将angular2的相关类库下载到本地,以便于之后的打包和运行。在本篇教程中,我们暂时只需要如下几个依赖:@angular/common, @angular/compiler, @angular/core, @angular/platform-browser, @angular/platform-browser-dynamic
在angular2-learn文件夹下,执行如下命令:

npm install --save @angular/common @angular/compiler @angular/core @angular/platform-browser @angular/platform-browser-dynamic --registry=https://registry.npm.taobao.org

执行完成后,再检查angular2-learn目录,发现多了node_modules文件夹,里面就是刚刚通过npm install安装的依赖。
package.json的dependencies字段下也多了很多记录,这是--save参数的作用:如果没有--save参数,这些文件依旧会被下载下来,但是不会被保存到package.json中。
--registry参数用于指定npm的镜像仓库,由于网络被墙,不使用--registry很多时候都无法完成下载;registry.npm.taobao.org是阿里给广大前端同学的福利,长期维护且高速稳定,在这里顺便也向阿里的同学说一声谢谢 :)

3. 安装gulp和其他开发依赖
在上一步中,我们下载了angular2框架,angular2框架是程序运行时所依赖的。但是我们在编译时还需要一些其他的类库或框架支持。
首先是gulp,我们要靠它完成编译流程的自动化,比如检测文件修改、自动编译、生成目标js等。
我们还需要browserify,因为angular2和大多数托管在npm的类库遵循的都是commonjs标准而非amd标准,它们适用于nodejs环境而非浏览器环境。browserify,正如它的名字所暗示的一样,可以帮助我们把符合commonjs标准的代码“浏览器化”,使之成为符合amd标准的代码。
当然我们也需要typescript编译器。博主本来想用非模块化的angular2框架以及原生javascript来为大家演示angular2 hello world的例子,但是尝试后发现,这样做虽然看起来简单一些,但实在是味同嚼蜡——缺少了模块化和元信息注解的支持,angular2的韵味一下就掉了一大半。因此这里我们还是坚持用typescript作为编程语言,可以预见的是,angular2团队将来会把大部分精力花在typescript的相关支持上,typescript一定是angular2的默认推荐语言。对于不熟悉typescript的同学,其实也不用担心,typescript是javascript的超集,所有合法的javascript代码都是合法的typescript代码,只要面向对象的基础比较扎实,学习起来会有一脉相承的感觉,曲线不会太陡峭。
首先来安装gulp

npm install -g gulp --registry=https://registry.npm.taobao.org

注意,这一步中我们使用了-g而非--save参数。这是因为gulp安装在全局,并不是为某个特定项目安装的,g指的就是global。Linux和Mac环境下的读者在这一步时请注意读写权限问题。
然后回到angular2-learn文件夹,为项目安装编译时依赖:

npm install --save-dev gulp gulp-browserify gulp-typescript --registry=https://registry.npm.taobao.org

这里为什么使用--save-dev而非--save呢?因为这些工具只在脚本编译的时候使用,最终生成的js并没有它们的身影,因此只能算作开发依赖。
安装完成后检查package.json,发现刚刚的几个工具都被加到了devDependencies字段。
到这里我们就完成了hello world例子所依赖的类库的安装。

4. 配置gulpfile.js
正如上文所提到的,我们使用gulp的目的是搭建自动化的编译环境,使之产出可以在浏览器中运行的js代码。更详细地说,我们需要gulp检测ts(typescript脚本的默认后缀名)文件的变化,一旦有变化发生(比如新建、修改、删除等),就使用gulp-typescript将脚本从typescript编译为javascript;由于angular2本身遵循的是适用于nodejs的commonjs标准,从typescript编译为javascript脚本后,我们还需要使用browserify将它转变为符合amd标准的javascript文件。流程见下图:

按照这个思路,我们可以写出如下gulpfile.js,并将其放到angular2-learn目录下:

var gulp = require(‘gulp‘);
var typescript = require(‘gulp-typescript‘);
var browserify = require(‘gulp-browserify‘);

gulp.task(‘compile‘, function () {
    gulp.src(‘app/**.ts‘)
        // typescript编译配置信息
        .pipe(typescript({
            target: ‘es6‘,
            module: ‘commonjs‘,
            moduleResolution: ‘node‘,
            sourceMap: true,
            emitDecoratorMetadata: true,
            experimentalDecorators: true,
            removeComments: false,
            noImplicitAny: false
        }))
        .on(‘error‘, function () {
            console.log(‘unhandled error from typescript compilation‘);
        })
        // 将typescript编译后的javascript文件存放到out目录下
        .pipe(gulp.dest(‘./out‘))
        .on(‘end‘, function () {
            console.log(‘typescript compilation done‘);
            // 将main.js作为入口文件,使用browserify按amd规范进行合并
            gulp.src(‘out/main.js‘)
                .pipe(browserify())
                .on(‘error‘, function (error) {
                    console.log(‘unhandled error from browserify resolution‘);
                    console.log(error);
                })
                // 将browserify后的文件放到项目根目录
                .pipe(gulp.dest(‘./‘))
                .on(‘end‘, function () {
                    console.log(‘browserify work done‘);
                });
        });
});

gulp.task(‘default‘, [‘compile‘], function () {
    gulp.watch(‘app/**.ts‘, [‘compile‘]);
});

不熟悉gulp的同学也不用紧张,这个配置文件其实就是为了表达出上图中的编译流程。另外,在typescript编译配置部分,这里除了将target设为es6和官网不同外,其余配置都是使用的angular2推荐的配置。为什么要编译到es6而不是es5呢,因为es6的大多数特性新版的浏览器已经支持了,而且我们的hello world本身也没有必要考虑浏览器兼容性,直接使用es6更为方便。

gulpfile配置好之后,对angular2编译环境的配置到这里就结束了。

5. 入口组件app.component.ts
接下来我们就进入到angular2 hello world的编码部分。作为一门新的前端框架,angular2吸收了很多前端社区近年来的发展成果,比如我们马上就要看到的基于es6的模块化开发和typescript提供的装饰器(decorator)。typescript虽然是javascript的超集,但其语言特性并不是天马行空的,大多数还是javascript正常发展的自然延续,例如装饰器将来就有很大希望成为新的ecmascript标准的一部分。
好了回到正题。我们先在angular2-learn根目录下创建app文件夹,作为存放所有typescript脚本的目录。
然后在app文件夹中创建app.component.ts文件,用于入口组件的定义。
在组件的定义中,我们需要使用到@angular/core模块中的Component装饰器。
import {Component} from ‘@angular/core‘;

有Java开发经验的同学会发现装饰器的使用和注解(annotation)的使用方法十分相似。在Component装饰器中,我们需要定义两个属性,selector和template。selector的作用在于告知angular要在哪些元素上使用这个组件,它本身类似于css选择器。template是Component对应的模板,在本篇教程可以暂时认为它是html代码的容器。
@Component({
    selector: ‘hello-world‘,
    template: ‘<h1>hello world</h1>‘
})

最后是AppComponent类的定义。本节中暂时还不需要为其添加额外的属性,但是作为模块化开发的一部分,为了将该类暴露给其他的文件,我们需要在类的定义前加上export关键字。
export class AppComponent {}

app.component.ts的完整文件内容:

// 从@angular/core中引入Component
import {Component} from ‘@angular/core‘;

// Component装饰器的使用
@Component({
    // selector告知angular在哪里初始化AppComponent这个组件
    selector: ‘hello-world‘,
    // AppComponent组件的具体模板
    template: ‘<h1>hello world</h1>‘
})
// 定义AppComponent类并将其暴露给外部环境
export class AppComponent {};

6. 启动脚本main.ts
上文中,AppComponent类的定义已经完成了,我们还需要一个类似于C语言main函数或者Java静态main方法的启动器来开始angular2的初始化。
依然在app目录下,这次创建main.ts文件。
angular2在浏览器中的启动依赖于定义在@angular/platform-dynamic-browser上的bootstrap函数。为什么要将bootstrap定义在这样一个模块中而非@angular/core中呢,难道启动不是核心功能吗?事实上,angular2这样做是为了解耦框架的核心运行时逻辑和初始化逻辑,方便将来后端、原生移动端上的加载和初始化。
除此以外,我们还需要引入刚刚定义的AppComponent。
main.ts的完整文件内容:

// 从@angular/platform-browser-dynamic引入bootstrap函数
import {bootstrap} from ‘@angular/platform-browser-dynamic‘;
// 从app.component.ts引入AppComponent
import {AppComponent} from ‘./app.component‘;

// 调用bootstrap函数,并将AppComponent作为参数,即入口组件
bootstrap(AppComponent);

上面的代码中有一个小地方需要注意,引入AppComponent时,from ‘./app.component‘中不能写./app.component.ts,.ts的后缀必须被省略掉。否则在typescript的编译完成后,browserify就找不到相应的类而只能抛出异常了。

7. 创建index.html
html!终于来到了本篇教程的最后一个编码步骤!
由于angular2的部分运行时依赖我们没有通过gulp打包进去,这里需要通过cdn加载,当然不嫌麻烦的同学也可以下载到本地。
body里需要放入hello-world标签,和AppComponent中selector属性所定义的hello-world相对应。
最后引入gulp编译、打包结束后生成的在angular2-learn根目录下的main.js。

index.html的完整内容:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>angular2-learn</title>
        <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
        <script src="http://cdn.bootcss.com/reflect-metadata/0.1.3/Reflect.min.js"></script>
        <script src="http://cdn.bootcss.com/angular.js/2.0.0-beta.17/Rx.umd.min.js"></script>
        <script src="http://cdn.bootcss.com/zone.js/0.6.12/zone.min.js"></script>
    </head>
    <body>
        <hello-world></hello-world>
        <script src="main.js"></script>
    </body>
</html>

8. 运行gulp并在浏览器中打开
上面的步骤完成后,angular2-learn目录下的结构应该如图所示:

在命令行中回到angular2-learn目录,输入如下命令并回车:

gulp

如果上面的代码没有错误,应该可以看见
typescript compilation done
browserify work done
的提示,并且angular2-learn目录下多了out文件夹和main.js。此时在浏览器中打开本地index.html,应该就可以看到最终的效果了。


因为gulp监视了ts文件的变动,如果之后要修改和调试,只需要在browserify work done的提示出来之后刷新网页即可。

angular2 hello world的例子以及随后的教程所需要的自动化编译环境就搭建完啦,对angular2是不是多多少少有了点感觉呢?欢迎继续阅读本系列的后续教程。

时间: 2024-10-06 04:43:23

[Step-By-Step Angular2](1)Hello World与自动化环境搭建的相关文章

angular2.0学习笔记1.开发环境搭建

开发环境, 1.安装Node.js®和npm, node 6.9.x 和 npm 3.x.x 以上的版本. 更老的版本可能会出现错误,更新的版本则没问题. 控制台窗口中运行命令 node -v 和 npm -v,来查看版本 2. 运行 npm config set registry https://registry.npm.taobao.org 因为国内访问http://npmjs.org(angular2.0组件库) 的站点访问经常不是很顺畅,所以换成淘宝的镜像, 3. 然后全局安装 Angu

数论之高次同余方程(Baby Step Giant Step + 拓展BSGS)

什么叫高次同余方程?说白了就是解决这样一个问题: A^x=B(mod C),求最小的x值. baby step giant step算法 题目条件:C是素数(事实上,A与C互质就可以.为什么?在BSGS算法中是要求a^m在%c条件下的逆元的,如果a.c不互质根本就没有逆元.) 如果x有解,那么0<=x<C,为什么? 我们可以回忆一下欧拉定理: 对于c是素数的情况,φ(c)=c-1 那么既然我们知道a^0=1,a^φ(c)=1(在%c的条件下).那么0~φ(c)必定是一个循环节(不一定是最小的)

Git Step by Step – (8) Git的merge和rebase

前面一篇文章中提到了"git pull"等价于"git fetch"加上"git merge",然后还提到了pull命令支持rebase模式,这篇文章就介绍一下merge和rebase之间有什么差别. 由于我们主要是想看看merge跟rebase之间的区别,这里就是用本地仓库的分支进行演示了. merge 其实在介绍分支的那篇文章中已经介绍过了一些分支merge的内容,这里就进行一些补充和总结. 下面我们基于本地一个仓库开始介绍,当前仓库的分支情

C# 2012 step by step 学习笔记8 CHAPTER 9 Creating Value types with enumerations and Structures

C# 2012 step by step 学习笔记8 CHAPTER 9 Creating Value types with enumerations and Structures things about 1. Declare an enumeration type. 2. Create and use an enumeration type. 3. Declare a structure type. 4. Create and use a structure type. 5. Explain

Linux Booting Process: A step by step tutorial for understanding Linux boot sequence

One of the most remarkable achievement in the history of mankind is computers. Another amazing fact about this remarkable achievement called computers is that its a collection of different electronic components, and they work together in coordination

C++开发WPF,Step by Step

示例代码 使用C++来开发WPF,主要是如何在MFC(Win32)的窗口中Host WPF的Page.下面我就做个详细的介绍. 一.创建工程, 由于MFC的Wizard会生成很多用不到的代码,所以我准备从一个空的工程开始创建一个MFC的工程. a)         打开VS2005,菜单File->New->Projects-, 左面选择Visual C++->Win32,右面选择Win32 Console Application,给工程起个名字CPlusPlus_WPF, Ok进入下一

数据库设计 Step by Step (1)——扬帆启航

引言:一直在从事数据库开发和设计工作,也看了一些书籍,算是略有心得.很久之前就想针 对关系数据库设计进行整理.总结,但因为种种原因迟迟没有动手,主要还是惰性使然.今天也算是痛下决心开始这项卓绝又令我兴奋的工作.这将是一个系列的文 章,我将以讲座式的口吻展开讨论(个人偷懒,这里的总结直接拿去公司培训新人用). 系列的第一讲我们先来回答下面几个问题 数据库是大楼的根基 大多数程序员都很急切,在了解基本需求之后希望很快的进入到编码阶段(可能只有产出代码才能反映工作量),对于数据库设计思考得比较少. 这

数据库设计 Step by Step (2)——数据库生命周期

引言:数据库设计 Step by Step (1)得到这么多朋友的关注着实出乎了我的意外.这也坚定了我把这一系列的博文写好的决心.近来工作上的事务比较繁重,加之我期望这个系列的文章能尽可能的系统.完整,需要花很多时间整理.思考数据库设计的各种资料,所以文章的更新速度可能会慢一些,也希望大家能够谅解. 系列的第二讲我们将站在高处俯瞰一下数据库的生命周期,了解数据库设计的整体流程 数据库生命周期 大家对软件生命周期较为熟悉,数据库也有其生命周期,如下图所示. 图(1)数据库生命周期 数据库的生命周期

Shell Step by Step (3) —— Stdin &amp;amp; if

4.输入输出 #! /bin/bash # Read users input and then get his name read -p "Please input your first name: " firstName read -p "Please input your last name: " lastName echo -e "Your full name is: $firstName $lastName" read使用方法: read