现在你应该已经创建完成种子项目,现在我们来看看,这个项目中包含了什么。
Yeoman 工具流
我非常荣幸的使用了 Yeoman 工作流的形式。你可以通过 gulp来唤起你的技术栈。
serve
开发阶段中,使用 gulp serve
可以启动一个监听改变自动刷新的服务器。
test
测试阶段中,脚手架提供了测试代码的编写模板,使用 Karma 编写单元测试代码,最后使用 gulp test
调起这些测试代码,Protractor 使用相同逻辑,实现端到端测试。
具体使用方法可以参考 测试环境配置
build
在执行 gulp build
或者其简略写法 gulp
能够启动脚手架提供的优雅的优化程序,具体使用方法可以参考 优化过程
inject
本脚手架在此处不止实现了 Yeoman 指导手册中所述。而且将脚本和样式以及依赖分门别类的注入到 HTML 文件中。
具体使用方法可以参考 文件注入
开发服务器
脚手架依托功能强大的 Browser Sync为代码提供一个服务器环境。
建议使用本地源码进行 serve,这样就能实现代码的动态监听和自动重载。
如果有服务器远端代码需要挂起,可以使用以下两种方案
- 使用完整的 URL (但需要处理CORS跨域问题)
- 或者你可以使用服务器端提供的代理服务器跳板,这样可以穿过跨域问题
挂起src
文件夹
默认情况下,browser-sync 监听了 src
文件夹,至少包含了并未变化的文件。
对于需要预处理的文件(依赖于你选择的预处理器情况,或许会是你的所有文件)此时,browser-sync 也会监听 .tmp/serve
文件夹
通过文件监听及预处理 过程产出的文件会自动的放在 .tmp/serve
文件夹中,这个过程对 browser-sync 是透明的。
如果两个文件夹中有相同的文件,那会选择 .tmp/serve
中的同名文件
最后,bower_components
中的外部依赖文件,将会使用相对于服务器根目录的绝对地址来引用,bower_components
作为地址的前缀。
自动刷新
当执行 gulp serve
时,会调起 browser-sync 并监听上述两个文件夹。
当 gulp 监听到文件变更,会向 browser-sync 传递重启命令。根据不同文件的修改,浏览器会选择自动刷新还是重绘页面。
使用代理
最好还是使用本地文件,特殊情况可以参考 browser-sync 的文档。
此时,你的应用会同时请求前后端项目的代码。
最简单的方式是添加一个代理,默认是没有的,因为后台配置灵活性比较大。但在 gulp/server.js
文件中使用了注释的方式添加了一段代码 demo
server.middleware = proxyMiddleware('/users',
{target: 'http://jsonplaceholder.typicode.com', changeOrigin: true}
);
使用实际参数替代上文中的配置,重启服务后,即可获取远端代码。更多详情参考
http-proxy-middleware
文件监听及预处理
如果你运行在开发环境或者简单执行了 watch
任务,gulp 会监听 src
文件夹中的变动。每次保存就能够将变动传送到处理程序中。
所有的处理程序都会从 src
取得变更,并将处理结果推送到.tmp/serve
文件夹。
** 脚手架并不提供 src
文件夹中文件之间的相互监听。**
相同的输入路径会产生相同的输出路径。
脚手架中包含了四种处理:
-
Injection (
gulp/inject.js
): 当你向src
文件中添加任何以.js
或.css
为后缀的文件,或者当你添加一个新的 bower 依赖时,处理器会重新进行index.html
文件的插入动作,更多详情参考 文件注入 -
Scripts (
gulp/scripts.js
): 如果使用了JavaScript预处理器, 所有针对文件的修改和新增都会触发这个任务,导致重新编译。 -
Styles (
gulp/styles
): 如果使用了CSS 预处理器, 所有针对文件的修改和新增都会触发这个任务,导致重新编译。 -
Markups (
gulp/markups
): 如果使用了HTML 预处理器, 所有针对文件的修改和新增都会触发这个任务,导致重新编译。
** 注意 ** 脚手架中使用了 gulp3版本,其中包含一些限制,比如新建一个文件夹或者文件夹中新建一个文件都会导致 gulp监听失败。此时需要手动重启服务。有些插件可以解决这个问题,但是我们更希望通过更新 gulp 的版本来解决,4中就解决了这个问题。
文件注入
打开 index.html
文件,你能看到其中并没有script
和 link
标签,取而代之的是一堆注释。
这些注释是脚手架用于自动注入脚本的。自动注入的对象并不是 index.html
而是 .tmp/serve
中生成的新文件。
注入的文件有两类,一类是第三方依赖,另一类是你的源码。
bower 依赖
有个叫 Wiredep的第三方工具,可以列出正在使用的 bower 依赖并将其注入 index.html
你需要注意的是,需要注入的依赖应该写在 bower.json 文件,安装在 bower_components 文件夹中,同时还要求他们自己也有 bower.json 文件。上边三个条件任意一个不符合就不会被正确注入。这种情况发生时,就要手动注入了
源码
脚手架还可以自动注入你的源码,这种注入不会忽略 src
文件夹中的任何一个文件。
由于文件顺序对于 JavaScript 执行有印象,所以使用插件Angular FileSort 这个插件会根据模块之间的依赖对代码进行排序。
对于 CSS,文件出现的顺序虽不重要但也会有一定的影响,可惜没有 CSS 预处理器排序插件。实际执行时按照文件夹排序和文件夹内文件名排序的方式进行排序。
CSS 预处理器注入
使用 CSS 预处理器时,文件注入的方式有所不同,文件是注入在预处理器文件中,而非直接注入在 index.html
中,注入完成后会统一注入。
由于这个缘故,注入处理不会执行 inject
任务,而是直接运行 style
任务,你可以在全局样式中找到 CSS 文件的插入点。
Bower支持 CSS预处理文件的引用,脚手架使用了这种方式,你可以在 CSS 文件中引用第三方依赖。
手动注入
脚手架的注入工作涵盖了大量的应用场景,尽量保证编程过程和构建过程之间透明。
不幸的是,很多情况并不能完全覆盖,最常见的就是安装了“不规范”的第三方插件,导致依赖不能正常打包。
你可以在 index.html
中添加自定义的script
或者 link
来添加未能打包的依赖。关键是,这些应该写在什么位置。
index.html
文件中,你能找到两种注释。一种用于构建,类似于 另一种用于注入
或者 ``. 后者多出现在前者包裹之中,如此设计是想着让外层的构建程序能够对注入的代码进行操作和优化。
** 手动注入的关键就是把你的代码放在构建内部,便于一并优化,但需要放在注入外部,因为注入标签内部的内容会被覆盖 **
例如:
<!-- build:css({.tmp/serve,src}) styles/vendor.css -->
<!--在这里引入第三方依赖 -->
<link rel="stylesheet" href="../custom-theme/style.css">
<!--这里是注入,不要往这里填写文件-->
<!-- bower:css -->
<!-- run `gulp inject` to automatically populate bower styles dependencies -->
<!-- endbower -->
<!-- endbuild -->
Note, that the custom-theme
folder also needs to be added to gulp/server.js:browserSyncInit
's list of routes. Otherwise, it won't be loaded via server.
** 注意 ** 自定义主题 custom-theme
文件夹也需要添加到gulp/server.js:browserSyncInit
文件中路由声明中否则无法加载。
测试环境配置
脚手架提供了测试代码运行环境,让你可以专心写测试代码。
根据最佳实践,单元测试代码会跟进实现,需要使用后缀 *.spec.js
或者*.mock.js
来区分。
项目中生成的karma.conf.js
文件使用了与 gulp 脚本相同的配置项。文件注入中使用的逻辑与测试过程相同。
默认使用 PhantomJS作为测试浏览器,而且已经安装在项目依赖中了,当使用 Taceur作为预处理器时,他们之间有冲突,此时切换为 chrome.
测试框架选用了Jasmine,如果有替代选择就更好了,可惜现在版本还没有。
为了测试 HTML片段,尤其在实现指令的测试时,引入插件 karma-ng-html2js-preprocessor
完成测试。
除此之外,原则上尽量少的使用 Karma 相关的插件,因为这些插件的工作与 gulp 有重合,未来也在寻求更好的兼容两个方面的工具,比如 webpack.
优化过程
优化过程的核心是使用了插件 gulp-useref。这个插件的主要作用是实现代码拼接插入 index.html
文件,主要作用在 ``之间
这个插件在处理代码时,允许使用额外的插件对代码流进行处理。例如使用Uglify 对 JavaScript 代码进行丑化。CSS 的优化过程也是如此。另一个比较重要的插件为gulp-rev ,实现了向文件添加hash 串的功能以避免缓存问题。
优化结果会分为两个文件,一个是第三方依赖,另外一个是项目源码。
源码中的所有 HTML文件都被插件gulp-angular-templatecache处理成了 JavaScript并通过绑定的方式让 JavaScript 可以调用。这个插件的实现与 webpack 打包就很相似了。
剩下的文件会原样复制到目标文件夹中。