AngularJS 號稱 '第一框架' ('The first framework') 確實是名不虛傳。由其從jQuery中完全轉入AngularJS後就有無法離開他的感覺了。雖然AngularJS的學習曲線很陡峭,入門的門檻相比較高,但這些付出都是值得的相信用過的朋友都會與我有同感吧。為何我如此
地偏愛AngularJS? 或者這樣說吧,用AngularJS開發的話其實是給我了一種工業化開發的概念,我對軟件工業化的淺顯理解簡單歸結為幾點就是:
前端開發比後端開發要求開發人員做更多繁雜的事,例如:js和css 的壓縮、依賴引入、更新,圖片壓縮、“糖果語言(coffeescript/less/sass)”的語法檢查與編譯、靜態圖片/靜態網頁壓縮,單元測試、E2E測試、等等。這些鎖事往往很耗時間。
再者,當引入AngularJS作為主前端框架的話,大量的js源文件管理對文件結構與模塊結構合理規劃就顯得更為之重要。所幸的是,google 是AngularJS工業化的主力推手,為了增加前端開發人員的生產力他們也不遺余力地做了很多工作,,他能快速地為我們建立各種類型項目的腳手架(項目模板),以他們的“最佳實踐”為基礎快速地為我們完成這一系列繁瑣的工作。
我在實際項目開發覺得官方提供的 angular 生成器並不是十分合用,在經歷了好幾個項目的磨合後我在 google 官方的 yeoman angular 腳手架項目上進行了一些定制與修改,也在此作一些分享,由於時間關系還沒有去將其成一個generator 所以只能在此以博文方式共享了。
如果對Yeoman不了解也不用要,本文將會獨立於yeoman 一步一步詳細地解釋如何部署一個可以用於生產AngularJS前端開發環境。
以下這些可謂是前端開發必備了,如果不清楚具體用法那麼就先請去他們的官網先腦補吧:
npm
Node的依賴包管理工具,可以到 [nodejs 官方下載|http://nodejs.org/download/]頁面獲取安裝包。
** bower **
bower 是由twitter開發的客戶端依賴包管理工具
npm install -g bower
** grunt **
自動化任務管理工具,是整個自動化工程的核心。
npm install -g grunt-cli
安裝此三大工具後我們就可以著手開始了。
以下是基本項目目錄的構成以及每個目錄的功能說明
項目目錄/
├── app // 應用程序目錄
│ ├── bower_components // bower 組件目錄 (由 bower 生成)
│ ├── fonts // 字體
│ ├── images // 圖片資源
│ ├── styles // 樣式目錄 可存放 .css 和 .less
│ └── scripts // 應用程序腳本
│ └── app.coffee // angularJS 應用程序文件
│ └── index.html // HTML HOME 文件
├── dist // 發布後的程序目錄
├── test // 測試程序目錄
│ ├── mocks // 存放mocks組件文件目錄
│ ├── e2e // e2e測試文件目錄
│ └── spec // 單元測試文件目錄
├── node_modules // NodeJS 的組件目錄 (由 npm 生成)
├── docs // 存放生成文檔
├── .tmp // 臨時文件目錄 (由 grunt 任務自動生成)
├── .bowerrc // bower 路徑規則指定文件
├── conffeelint.json // CoffeeScript 語法檢查規則
├── Gruntfile.js // grunt 配置文件
├── karma.conf.js // karma 配置文件
├── protractor.conf.js // protractor 配置文件
├── package.json // nodes 依賴包描述文件
└── bower.json // bower 依賴包描述文件
此項目環境主要提供三種主要的運行方式,分別適用於項目生命周期中的不同的時期,更准備地說應該是適用於不同的場景。
將所有的文件生成至產品交付目錄 dist
內,執行包括:
coffeescript/less
輸出必要的靜態文件
輸出注釋文檔並生成文檔網站
指令:
grunt build
多用於開發期,進行自動化單元測試或是e2e測試,考慮到e2e測試的使用頻率相對於單元測試要低,故此 test指令只默認執行所有單元測試,
而要執行e2e測試則需加入 e2e
參數作明確指定。
指令:
grunt test
- e2e -
grunt test:e2e
如果加入 keepalive
參數的話,test 指令將直接運行於後台,且會檢測所有的文件變化,一但文件發生更改測試將會自動被重新執行。
這種情況多適用於測試程序的編寫與調試。
grunt test:keepalive
主要用於手工調試與HTML界面設計之用,當啟用 debug 模式後,livereload 功能將會被自動載入,也就是所有 app
目錄下的任何
變更都能被捕獲且浏覽器能自動刷新應用更改。
指令:
grunt debug
首先需要安裝 load-grunt-tasks 和 time-grunt 兩個插件
npm load-grunt-tasks --save-dev
npm time-grunt --save-dev
'use strict';
module.exports = function (grunt) {
// 自動加載所有可用的grunt 任務
require('load-grunt-tasks')(grunt);
// 可以顯示每個任務執行的實際時間,可以便於以我們優化任務
require('time-grunt')(grunt);
// 配置主要路徑
var config = {
app: require('./bower.json').appPath || 'app',
dist: 'dist',
tmp: '.tmp',
tasks: grunt.cli.tasks
};
grunt.initConfig({
// 任務配置
});
首先是令CoffeeScript能支持語法檢查,需要安裝 [coffeelint|http://www.coffeelint.org] 插件:
npm install coffeelint --save-dev
此插件安裝後可以與大名鼎鼎的 jshint一樣將語法檢查規則放在一個獨立的文件內,本項目中就是項目根目錄下的 coffeelint.json
,
如果需要增加更多的CoffeeScript語法檢查規則可以修改此文件 。
在Gruntfile.js內的配置如下:
coffeelint: {
options: {
configFile: 'coffeelint.json'
},
all: ['<%= config.app %>/scripts/**/*.coffee'], //檢查應用程序目錄下的 CoffeeScript腳本
test: {
files: {
src: ['tests/**/*.coffee'] //檢查所有測試腳本
}
}
}
然後是安裝CoffeeScript編譯插件: [coffee-script|http://github.com/jashkenas/coffeescript]
npm install grunt-contrib-coffee --save-dev
由於我們編譯出來的 javascript 不會直接使用,因為還要進行連接、壓縮和拷貝過程,所以我們將所有的輸出目錄設置為 .tmp
目錄。
在即使修改時也可以通過livereload 從.tmp目錄直接將變更後的腳本直接加載到浏覽器內,方便調試之用。
還有一點需要特別指出的是 coffee 選項中我將 sourceMap
設置為true,只有這個選項打開,當生成map文件後在浏覽器調試時才能准確地將被壓縮後的
文件正確地重新映射至未壓縮的程序源文件。關於 source map的具體用法可以參考 [javascript source map的使用|http://www.cnblogs.com/Ray-liang/p/4018162.html]
一文。
coffee: {
options: {
bare: false,
sourceMap: true,
sourceRoot: ''
},
dist: {
files: [
{
expand: true,
cwd: '<%= config.app %>/scripts',
src: '{,*/}*.{coffee,litcoffee,coffee.md}',
dest: '.tmp/scripts',
ext: '.js'
}
]
},
test: {
files: [
{
expand: true,
cwd: 'test/spec',
src: '{,*/}*.coffee',
dest: '.tmp/spec',
ext: '.js'
},
{
expand: true,
cwd: 'test/e2e',
src: '{,*/}*.coffee',
dest: '.tmp/e2e',
ext: '.js'
}
]
}
}
Grunt 提供了官方的less 編譯安裝包 [grunt-contrib-less|https://github.com/gruntjs/grunt-contrib-less]
npm install grunt-contrib-less --save-dev
與配置coffee 編譯器的原理一樣我們需要將 styles 目錄下的 .less文件預先編譯成為 .css並存放在 .tmp/styles下,以備後處理
和livereload 之用。
less: {
all: {
files: [
{
expand: true,
flatten: true,
cwd: '<%= config.app %>/styles',
src: ['{,*/}*.less'],
dest: '.tmp/styles',
ext: '.css'
}
]
}
}
在這部分我並沒有直接采用 Grunt 官方的 uglify,concat 而是使用了 usemin 插件這是延續了 yo generator-angular 的做法。他是 yeoman項目的官方插件,這個插件同樣是依賴於 uglify,concat 的,然而他增加了對文件自動引用的支持,可以從頁面讀出腳本文件的引用而不是通過hardcore的方式寫在Gruntfile中。另外,他還能增加對bower_components內的依賴進行合成而取代人工合成,這是一個很棒的功能可以省去我們從bower_components下找輸出文件的麻煩,只需要關注bower.json文件內管理包而不是在Gurntfile.js進行硬編碼了。
usemin是一個合成包需要以下這些插件同時支持,為了節省篇幅以下的指令都是以 npm install [包] --save-dev
方式安裝
以下配置是從 generate-angular 中拷貝過來用的:
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
options: {
dest: '<%= config.dist %>'
},
html: [
'<%= config.app %>/index.html'
]
},
// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
options: {
assetsDirs: [
'<%= config.dist %>',
'<%= config.dist %>/images'
]
},
html: ['<%= config.dist %>/{,*/}*.html'],
css: ['<%= config.dist %>/styles/{,*/}*.css']
},
// The following *-min tasks produce minified files in the dist folder
imagemin: {
dist: {
files: [
{
expand: true,
cwd: '<%= config.app %>/images',
src: '{,*/}*.{gif,jpeg,jpg,png}',
dest: '<%= config.dist %>/images'
}
]
}
},
svgmin: {
dist: {
files: [
{
expand: true,
cwd: '<%= config.app %>/images',
src: '{,*/}*.svg',
dest: '<%= config.dist %>/images'
}
]
}
},
htmlmin: {
dist: {
options: {
customAttrAssign: [/\?=/],
collapseBooleanAttributes: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
removeCommentsFromCDATA: true,
removeEmptyAttributes: true,
removeOptionalTags: true,
removeRedundantAttributes: true,
useShortDoctype: true
},
files: [
{
expand: true,
cwd: '<%= config.dist %>',
src: ['{,*/}*.html', 'views/{,*/}*.html', 'templates/{,*/}*.html'],
dest: '<%= config.dist %>'
}
]
}
}
這裡需要說明的是 app/index.html文件,也就是在配置中:
useminPrepare: {
html: [
'<%= config.app %>/index.html'
]
}
這個選項是給 usemin 插件去找腳本引用的,這裡默認只是設定了 index.html 文件,因為這是一個Angular SPA項目,所以只有一個index.html文件作為主入口,如果你具有多個不同的視圖模板,而且所引用的 script 都不要一樣的話,可以將這些模板頁明確地放在這個 html
數組選項中。
關於usemin的詳細用法可以參考google的官方文檔,以下只是對最常用的部分進行講解,力求不去看官方那個龐大的英文文檔也能快速地使用起來。
打開 index.html :
<!doctype html>
<html ng-app="app">
<head>
<meta charset="utf-8">
<title>Project Title</title>
<!-- build:css styles/vendor.css -->
<!-- bower:css -->
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="bower_components/fontawesome/css/font-awesome.css" />
<!-- endbower -->
<!-- endbuild -->
<!-- build:css styles/main.css -->
<link rel="stylesheet" href="styles/main.css">
<!-- endbuild -->
<!-- build:js scripts/vendor.js -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:js({.tmp,app}) scripts/index.js -->
<!-- endbuild -->
<base target="_blank">
</head>
<body ng-strict-di>
<div ui-view></div>
</body>
</html>
如果你足夠細心你會發現這裡有一些“與眾不同的”標記,<!--build:js--><!-- endbuild -->
和 <!--build:css--><!-- endbuild -->
實際上這不是注釋,他們其實是 usemin 的專用配置標記。其中 <!-- bower:js--><!--endbower-->
是另一個插件 bowerInstall 的
配置標記,我會在下文再詳細講解。
這個標記其實很簡單將他翻譯過來就是:<!-- build:類型[js|css] 生成的目標文件>
, 源文件目錄就是當前html所在的目錄,如果要指定多個
源目錄可以通過<!-- build:類型({目錄1,目錄2}) 生成的目標文件>
的方式指定。
按照這個來理解的話,這裡的設置就會輸出三個文件:
好吧,先來說說 vendor.*
,如果裝了 bowerInstall 這個插件在<!-- bower:類型 --><!-- endbower-->
內的引用是由 bowerInstall 自動加入的,他加入後會修改index.html源文件,我們不需要手工加入。而對於某些比較坑爹的第三包,這裡指的坑爹是他的最終輸出文件放在一些古怪的深層目錄中,而不是在他的發布目錄的根下,那麼我們才需要手工加入引用。如 ace-builds 這個包,他的發布文件是在 ace-builds/src/ace.js,同時他又提供了ace-build/src-min/ace.js 文件,對於這類包我們就不得不手工將具體的引用文件加入到 <!-- bower-->
標記內,否則bowerInstall是不知道應該引用哪一個文件的。
而輸出位置就是前面我們在 usemin選項中設定的:
useminPrepare {
options: {
dest: '<%= config.dist %>'
}
}
也就是 項目目錄/dist
。
接下來是 main.css
和 index.js
,這兩個是從不同的源來生成的,main.css
沒有指定源,所以他會在當前的index.html所在位置中找 styles 目錄也就是 項目目錄/app/styles
,那麼具體需要引用那些自定的css(之前通過 less生成的)就在此設定。
解釋得更為清楚一點就是 假設有一個 app/styles/custom.less 文件,那麼在 index.html內加入這個引用應該是:
<!-- build:css styles/main.css -->
<link rel="stylesheet" href="styles/main.css">
<link rel="stylesheet" href="styles/custom.css">
<!-- endbuild -->
雖然custom.css在設計期並不存在,但他會被less編譯器最終輸出,所以引用時只要名字對了就行了。
同樣的 build:js
的設置也是這理,只是這裡增加了 .tmp
作源搜尋目錄,就是說在 .tmp
找不到的源文件 可以到 app/scripts
下找,反之亦然。
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2015-09/123595p2.htm