本节书摘来自华章出版社《AngularJS深度剖析与最佳实践》一书中的第1章,第1.3节,作者 雪狼 破狼 彭洪伟,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1.3 创建项目
接下来,我们要新建一个项目。传统的方式是使用Yeoman工具,它是基于Node的一个项目生成器引擎,但本书使用的是FrontJet方式,所以这里讲两个方式。
1.3.1 Yeoman
这节我们先简单讲讲Yeoman。
首先用cnpm install -g yo命令来安装它。
Yeoman只是个项目生成引擎,我们还需要安装一个Angular的项目模板,可以使用cnpm install -g generator-gulp-angular@0.8.1命令。为了让后续步骤和本书的描述保持一致,请完全按照刚才的命令行来安装指定版本,先不要使用新版本。建议等熟悉了此版本后再尝试。
这个生成器还依赖两个全局命令,也需要先行安装:cpnm install -g gulp bower。
接下来我们就可以创建项目了。先建立一个项目目录,比如:mkdir ~/dev && cd ~/dev,mkdir book-forum-yo,然后进入这个目录cd book-forum-yo,再运行命令yo gulp-angular。
这是一个交互式过程,Yeoman会提出一系列问题供你选择,请跟随我的选项:
Which version of Angular do you want?这里是选择Angular版本,由于我们需要兼容IE8,所以这里要选1.2.x项。按方向键把光标移到1.2.x项上,回车即可。
Which Angular抯 modules would you want to have?这里是选择Angular的子模块,具体的用途我后面会讲,直接回车即可。
Would you need jQuery or perhaps Zepto?这里是选择jQuery的版本,由于我们需要兼容IE8,所以这里要选择 jQuery 1.x 版本。
Would you like to use a REST resource library?这里选择ngResource,这是Angular内置的REST API访问库。另一个选项Restangular有点过度设计,不够简洁,所以这里不选择它。
Would you like to use a router?这里选择UI Router,这是一个第三方库。另一个选项ngRoute是内置路由库,UI Router用起来比ngRoute稍好一些。
Which UI framework do you want?这里选择Bootstrap,这是Twitter开源的一个CSS库,也有一些JavaScript组件,它简洁大方,成熟度高,而且可以自由使用在商业项目中,所以作为首选。
How do you want to implements your Bootstrap components?这里选择Angular UI Bootstrap,这是Angular-ui组推出的一个第三方Angular组件库,本项目中会使用到其中的一些指令。
Which CSS preprocessor do you want?这里选择Sass (Node)。Sass是一种CSS的增强语言,支持嵌套以及变量、循环等,最终要编译成CSS,这里选择的是用C语言编写的一个Sass编译程序,相对Ruby的版本,它功能较少,但是执行速度要快很多,而这种差别在大中型项目中是相当显著的,所以宁可牺牲Sass的高级特性,也要选择它。
Which JavaScript preprocessor do you want?这里选择None,也就是普通JavaScript。考虑到一些读者可能不熟悉其他几种语言,所以为了便于示范,我们选择普通JavaScript。
Which html template engine would you want to have?这里选择Jade,事实上这里选择什么都可以,因为为了便于示范,我们在这里不会使用HTML模板引擎,而是直接使用普通HTML。
至此,选项的选择已经全部完成,系统会开始安装bower和npm包,前者用来安装前端组件,而后者用来安装开发环境。
不过,由于GFW的阻挡,npm的某些包可能安装失败,因此我们要按Ctrl+C组合键阻止这个自动安装过程,而是自己手动安装,请用如下命令:
bower install
rm -fr node_modules
cnpm install
如果以前用过cnpm和npm,那么可能会出现一些版本不匹配的警告。这些一般不会导致问题,不过如果要去掉这些警告,那么可以用如下命令清除一下缓存,并重新安装:
npm cache clean
cnpm cache clean
rm -fr node_modules
cnpm install
1.3.2 FrontJet
用Yeoman/gulp-angular@0.8.1方式创建的项目有一些缺点:
它会在当前目录下放入一个巨大的node_modules目录,但是这些文件只是给gulp工具集使用的。除了浪费很大空间外,它还具有很深的目录结构,容易导致Windows系统下的复制、剪切、移动等操作出错。
对中文的支持不够好—它引入script时没有加上utf-8选项。
目录结构设计不理想,这主要表现在它将bower_components放入app目录中,这将干扰“在目录中搜索”等操作。
选项过多,容易让新手困惑,这也阻碍了通过在社区提问来解决问题,因为过多的选项让你很难简短地说清问题。
自动化程度不够。每个程序文件都需要自己手动加入index.html中。
工具部分不容易升级。gulp-angular本身也会升级,但由于老版本已经嵌入项目中,所以要对它进行升级会比较困难,特别是在项目比较多的时候。
有Bug,创建了新文件或者删除了文件时不会触发reload。
针对这些缺点,我写了一个开源工具—FrontJet(前端喷气式引擎),它是我根据自己的一些项目经历逐步改造而成的。相对于gulp-angular,它主要有以下亮点:
可独立安装、升级。
去掉了很多选项,直接选用经过实践检验的固定技术栈,简化创建过程。
自带一个种子工程,里面包含根据实战经验总结出来的目录结构和开发指南,可用于创建新工程。
自动注入项目中的JavaScript文件和Scss文件,引入JavaScript文件时会加上charset="utf-8"选项。
对文件进行增删改时都能正常触发reload。
增加编译Web font的功能,即把一个svg文件放入icons目录,就会自动编译成font文件(ttf、woff等),以及相应的Scss文件。
增加Forks功能,可生成针对不同操作系统的文件,开发服务器会根据浏览器所在的操作系统返回相应分支下的文件,这特别适合于手机版调试。
增加Mock功能,基于node-restify库,生成一个内置的Mock服务器,可在与真实服务端对接之前提供一个模拟服务器。这些Mock数据也会被自动用于单元测试。
增加内置的启动为https服务的功能,可用于排查https的特有问题。
增加针对特定URL的反向代理、模拟延迟功能。反向代理虽然在gulp-angular中也有实现,不过比较粗糙,需要修改gulp源码才能工作,我将其移到fj.conf.js中。模拟延迟则用于模拟真实环境中的网络延迟,以便设计更好的用户体验。
在Linux/Mac下增加了系统级错误提示框:当FrontJet编译过程中发现语法错误时,会通过系统本身的通知功能显示一个错误提示框,以免被忽略。
FrontJet的安装非常简单,使用cnpm install -g fj即可。fj是FrontJet的缩写,而且正好是键盘上的两个定位基准键,非常便于输入。安装完之后,即可在任何目录下使用fj命令,常用的命令见表1-3。
1.使用FrontJet创建项目
使用FrontJet创建项目非常简单:
mkdir ~/dev && cd ~/dev
fj create BookForum
2.启动开发服务器
现在就可以直接在IDE中打开它了。对于IntelliJ/WebStorm的最新版本,只要在“File|Open”菜单中选择BookForum目录即可。
如果IDE支持内嵌命令行窗口功能,如IntelliJ/WebStorm的Terminal窗口,那么建议打开它,并且在此处执行fj serve命令来启动一个开发服务器,这样就可以在不切换窗口的情况下直接看到JavaScript或Scss的语法错误等问题。如果不支持,请打开一个独立的终端窗口来运行fj serve,并且时常留意一下终端窗口和系统的错误提示框。
3.项目结构
用FrontJet创建的项目,具有一个默认的目录结构。
这个结构中有很多README.md文件,用于解释当前目录的结构以及用途,它们不会出现在编译结果中,并且可以随意删除。也可以自行编辑它,用于在项目组中保持共识。
本项目的结构简介如下:
|-- app(源码的根目录)
| |-- animations(自定义动画)
| | |-- README.md
| | `-- ease.js(动画样例)
| |-- app.js(app模块的定义文件)
| |-- components(组件型指令)
| | |-- README.md
| | `-- layout(外框架)
| | |-- _layout.html(模板)
| | |-- _layout.js(控制器)
| | |-- _layout.test.js(与控制器对应的单元测试)
| | |-- _layout.scss(样式)
| | |-- footer.html
| | |-- footer.js
| | |-- footer.scss
| | |-- header.html
| | |-- header.js
| | |-- header.scss
| | |-- menu.html
| | |-- menu.js
| | `-- menu.scss
| |-- configs(配置)
| | |-- README.md
| | |-- config.js(config阶段的代码)
| | |-- router.js(路由定义)
| | `-- run.js(run阶段的代码)
| |-- consts(常量)
| | |-- README.md
| | `-- api.js(API定义)
| |-- controllers(控制器)
| | |-- README.md
| | `-- home(首页)
| | |-- index.html(模板)
| | |-- index.js(控制器)
| | |-- index.scss(样式)
| | |-- notFound.html(模板)
| | |-- notFound.js(控制器)
| | `-- notFound.scss(样式)
| |-- decorators(装饰器型指令)
| | `-- README.md
| |-- favicon.ico(网站图标)
| |-- filters(过滤器)
| | `-- README.md
| |-- forks(系统分支)
| | |-- README.md
| | |-- android(适用于安卓浏览器的文件)
| | | `-- README.md
| | |-- default(适用于其他系统的文件)
| | | `-- README.md
| | `-- ios(适用于iOS浏览器的文件)
| | `-- README.md
| |-- icons(svg图标源文件)
| | `-- README.md
| |-- images(普通图片)
| | |-- README.md
| | `-- logo.png
| |-- index.html(首页)
| |-- libraries(第三方非Angular库、非bower文件,会被最先引用)
| | `-- README.md
| |-- services(服务)
| | |-- interceptors(拦截器,用于过滤通过Ajax上传或下载的数据)
| | | |-- AuthHandler.js(401的处理器)
| | | |-- ErrorHandler.js(其他4xx、5xx错误码的处理器)
| | | |-- LoadingHandler.js(加载中界面)
| | | `-- README.md
| | |-- sao(服务访问对象)
| | | `-- README.md
| | `-- utils(工具类服务)
| | `-- README.md
| `-- styles(样式定义)
| |-- README.md
| |-- _app.scss(应用程序的定义,自动引入所有具体页面的Scss)
| |-- _bootstrap.scss(对Bootstrap的样式重定义)
| |-- _common.scss(具有跨项目复用价值的样式)
| |-- _icons.scss(根据svg图标编译出的样式文件)
| |-- _variables.scss(变量定义,包括对Bootstrap的覆盖式样式定义)
| `-- main.scss(总的CSS文件,用于依次引入其他文件,一般不在此处定义样式)
|-- bower.json(bower库的名称及版本列表)
|-- bower_components(bower库文件)
|-- dist(编译结果/供最终发布的文件)
|-- fj.conf.js(FrontJet的配置文件,详情见注释)
|-- mock(Mock服务器)
| |-- README.md
| |-- package.json
| |-- resources(资源数据定义)
| | `-- users.js
| |-- routers(服务端路由实现)
| | `-- users.js
| |-- routers.js(路由列表)
| |-- server.js(服务器启动文件)
| `-- utils(工具类)
| `-- resourceMixin.js
|-- test(测试)
| |-- e2e(端到端测试)
| | |-- demo.js
| | `-- readme.md
| |-- karma.conf.js(Karma的配置文件,用于单元测试)
| |-- protractor.conf.js(Protractor的配置文件,用于端到端测试)
| `-- unit(单元测试)
| `-- readme.md
|-- .bowerrc(bower的配置文件,用于指定bower路径等)
|-- .editorconfig(编辑器配置,用于在不同的编辑器之间统一缩进等代码风格)
|-- .gitignore(Git的忽略列表,匹配的不会被添加到Git库中)
|-- .jshintrc(JavaScript代码风格检查工具jshint的配置文件,用于定制代码检查规则)
|-- tsd.json(第三方库名称及版本列表)
`-- typings(第三方库定义)
其中app目录的内部结构都是可以任意调整的,不会影响FrontJet的运行。当要对传统项目使用FrontJet时,可以将其源文件拷贝到app目录下。其他目录和文件的用途这里只做简单介绍,后面的文章中涉及时再展开讲解。