写这篇文章呢,主要是想帮助那些想尝鲜Angular2的童鞋们,因为我自己在玩Angular2时碰到了不少坑,而且Angular2语法一直处于变化中,让人很头疼。不过也怪不了Anguar2,因为它现在是处于并长期处于alpha阶段,本文是基于最新的angular2.0.0-alpha.25来写的。
敬告 : Angular2.x与Angular1.x是雷锋与雷峰塔的区别,内心脆弱者请慎入,因为你将会遇到各种挫折,各种折腾,所有你必须要有一个坚强的内心! 废话少说,我们开始吧!
环境搭建?什么? Angular不就是一个框架么,搞什么环境搭建,不是像angular1那样引入一个angular.js就搞定了么?
亲,你这么想就错了。我前面就说了,Angular2.x与Angular1.x是雷峰与雷峰塔的区别,Angular2.x是不兼容Angular1.x的,所在在框架的构造上,它们是完全不同的。在Angular2.x中,因为其是基于ES6来开发的,所以会有很多第三方依赖。由于很多浏览器还不支持ES6,所以Angular2引入了很多polyfill或者shim, 导致我们引入了第三方依赖。不够直观? 我给你看一下运行一个所谓的"hello world"需要的代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Angular2 Hello world</title> </head> <body> <sample-app>正在加载中...</sample-app> <!-- ES6-related imports --> <script src="lib/traceur-runtime.js"></script> <script src="lib/es6-module-loader-sans-promises.src.js"></script> <script src="lib/extension-register.js"></script> <script src="lib/reflect.js"></script> <script> register(System); </script> <!-- Angular2-related imports --> <script src="lib/zone.js"></script> <script src="lib/long-stack-trace-zone.js"></script> <script src="lib/angular2.js"></script> <!-- Application bootstrap logic --> <script> System.import('app') .then(function(app) { app.main(); }, function(e) { console.error('Boostrap angular2 failed!', e); }); </script> </body> </html>
我想,看到上面的代码,很多童鞋会发出“我靠,我X”的国骂吧。的确,运行Angular2真他妈不容易,真是惊天地,泣鬼神。这里我还要吐槽下官方的“get started"文档,不知道写的鞋什么鬼玩意,你按照那个,很难跑起来。而且和Angular2的版本还不同步,因为它在不断更新中,官方文档会相对比较旧点。
关于上面的代码,大家暂时不要关注它意思是什么,因为我后面会介绍。现在我们关注的是:这些乱七八糟的js文件从哪里来的? 我应该从哪里找到这些玩意。
现在,牛逼闪闪的 Gulp 闪亮登场了!
按照官方的说法,它是基于数据流的构建系统(streaming build system),主要用来让自动化和增强你的工作流程(Automate and enhance your workflow)。简单说,比如我们有时候需要把less编译成css,需要对js进行jshint检查,然后把脚本合并后再进行压缩, 通过gulp,我们可以自动化这些过程,一个命令,就全部搞定了。类似的系统还有 Grunt 。因为本文不是讲解 Gulp的文章,所以大家可以自行google下,或者阅读 gulp开发教程 这篇文章,写的还是不错的。还有一个 gulp的中文站点 ,也可以访问下。
貌似有童鞋开始奔溃了:为了跑一个Angular2,我容易么? 唉,又要学习新知识咯。这个年代,不涨姿势无法获得快感呀,所以少年别哭,别45°仰望天空,努力吧!
类似于java中的Ant构建工具有一个build.xml文件,在gulp中,我们得有一个gulpfile.js,这个文件定义了我们需要完成的任务。因为里面设计到了很多操作,大家看看就好,别害怕呀。
'use strict'; var gulp = require('gulp'), del = require('del'), plumber = require('gulp-plumber'), rename = require('gulp-rename'), traceur = require('gulp-traceur'); var connect = require('gulp-connect'), open = require('gulp-open'), port = 3456; var PATHS = { src: { js: 'src/**/*.js', html: 'src/**/*.html' }, lib: [ 'node_modules/gulp-traceur/node_modules/traceur/bin/traceur-runtime.js', 'node_modules/es6-module-loader/dist/es6-module-loader-sans-promises.src.js', 'node_modules/systemjs/lib/extension-register.js', 'node_modules/angular2/node_modules/zone.js/dist/zone.js', 'node_modules/angular2/node_modules/zone.js/dist/long-stack-trace-zone.js', 'node_modules/reflect-metadata/Reflect.js', 'node_modules/reflect-metadata/Reflect.js.map', ] }; gulp.task('watch', function() { gulp.watch(PATHS.src.js, ['js']); gulp.watch(PATHS.src.html, ['html']); }); gulp.task('js', function() { return gulp.src(PATHS.src.js) .pipe(rename({ extname: '' })) //hack, see: https://github.com/sindresorhus/gulp-traceur/issues/54 .pipe(plumber()) .pipe(traceur({ modules: 'instantiate', moduleName: true, annotations: true, types: true, memberVariables: true })) .pipe(rename({ extname: '.js' })) //hack, see: https://github.com/sindresorhus/gulp-traceur/issues/54 .pipe(gulp.dest('dist')); }); gulp.task('html', function() { return gulp.src(PATHS.src.html) .pipe(gulp.dest('dist')); }); gulp.task('angular2', function() { var buildConfig = { paths: { "angular2/*": "node_modules/angular2/es6/prod/*.es6", "rx": "node_modules/angular2/node_modules/rx/dist/rx.js" }, meta: { // auto-detection fails to detect properly here - https://github.com/systemjs/builder/issues/123 'rx': { format: 'cjs' } } }; var Builder = require('systemjs-builder'); var builder = new Builder(buildConfig); return builder.build('angular2/angular2', 'dist/lib/angular2.js', {}); }); gulp.task('libs', ['angular2'], function() { var size = require('gulp-size'); return gulp.src(PATHS.lib) .pipe(size({ showFiles: true, gzip: true })) .pipe(gulp.dest('dist/lib')); }); gulp.task('connect', function() { connect.server({ root: __dirname + '/dist', port: port, livereload: true }); }); gulp.task('open', function() { var options = { url: 'http://localhost:' + port, }; gulp.src('./index.html') .pipe(open('', options)); }); gulp.task('build', ['js', 'html']) gulp.task('default', ['build', 'libs']); gulp.task('serve', ['connect', 'open']); gulp.task('clean', function(done) { del(['dist'], done); });
代码比较多呀,不过没关系,我们可以不用太关注你实现细节,关注其运行效果即可,也可以顺便关注下 gulp.task 这个函数,因为我们定义的任务都是靠它来完成的。
哦,对了,值得提醒下, gulp 是基于node.js开发的,所有各位童鞋必须配置好node.js环境,然后安装好gulp,安装很简单。只需要:
npm install gulp -g
关于上面的那个gulpfile.js文件,我简单说下它的功能:
所以, 如果我们想构建angular2及其所有的依赖文件,只需要在命令行下输入二句话即可:
gulp // gulp其实相当于运行gulp default, Gulp有一个默认的任务就是default
gulp serve // 在新一个终端运行该命令,开启本地服务器
运行上面的命令,大家会看到错误。为啥,因为我们在Gulpfile.js中引入一些第三方插件,而且我们还没有看到angular2的代码呢,所以接下来,我们需要下载angular2的代码,然后把第三方依赖都安装上。
如果大家熟悉node.js,我们直接定义一个package.json文件即可,这个文件定义好了我们所需的依赖和版本。如下所示:
{ "name": "angular2-seed", "version": "0.2.0", "description": "", "main": "index.js", "author": "flyingzl(flyingzl@gmail.com)", "repository": { "type": "git", "url": "https://github.com/flyingzl/angular2-seed" }, "license": "MIT", "devDependencies": { "del": "~1.1.1", "gulp": "~3.8.10", "gulp-connect": "^2.2.0", "gulp-plumber": "^1.0.0", "gulp-open": "^0.3.2", "gulp-rename": "~1.2.0", "gulp-size": "^1.2.1", "gulp-traceur": "0.17.*", "systemjs-builder": "^0.10.3", "through2": "~0.6.3" }, "dependencies": { "angular2": "2.0.0-alpha.25", "es6-module-loader": "0.16.5", "systemjs": "0.16.7", "reflect-metadata": "0.1.0" } }
在目录下运行 npm install , 程序就会自动下载好相关依赖文件,并且放到 node_modules文件夹,这个时候再运行gulp命令就可以正常运行了,这样运行Angular2所需要的必要条件都满足了。看下运行结果:
好了,今天就到这里了,好像说了很多废话。其实这些都是我们工作的基础,大家不要嫌麻烦。下次我们来构建传说中的 Hello world。
如果大家迫不及待的想看到效果,就看我的github上的 angular2-seed 吧,这个是一个快速构建angular2的小工程。