前端开发环境搭建 Grunt Bower、Requirejs 、 Angular
现在web开发的趋势是前后端分离。前端采用某些js框架,后端采用某些语言提供restful API,两者以json格式进行数据交互。
如果后端采用node.js,则前后端可以使用同一种语言,共享某些可重用的Js代码,并共享构建工具。但很多时候我们可能采用别的语言,如ruby/java/scala等,此时前后端代码基本上是完全独立的。虽然大家都在同一个项目中,但可以分成互相独立的两块,并且前后端通常使用不同的构建工具。
比如当后端使用Scala时,我们会使用sbt进行项目构建,对scala代码进行编译、测试、打包等。它的专长是处理与scala相关的任务,但对于前端的支持比较弱。前端一些常见的任务,如js库的下载和管理、css文件的转换、js文件合并压缩、js测试的执行等,很难在sbt中找到好用的插件,而利用js世界里的工具来做反而更加方便一些。
我们项目组这几天正在讨论是否在项目中引入一些前端框架,还是直接用原生Javascript写。经过反复讨论和调研,最终决定引入AngularJs。但AngularJs的引入并不是单一的任务,因为我们还需要考虑前端代码的测试、依赖管理等,都需要有相应的工具支持,所以最后引入了这么一整套工具:
- Grunt – Js任务管理工具,通过各种插件对项目进行各种操作,比如文件转换、运行测试、打包部署等。相当于java里的ant/maven/gradle,ruby中的rack,scala中的sbt。
- Bower – Js库依赖管理工具。当你需要jquery时,不需要手动下载,只需要执行
bower install jquery
- RequireJs – Js库加载管理,及模块化支持。可以按需及并行加载js库,可以把我们的代码以模块化的方式组织。
- AngularJs – Js前端框架,支持依赖注入,双向绑定等我认为很重要的功能
这套东西都是比较基础且使用比较广泛的。一般一旦在项目中引入前端框架,或者需要写比较多的Js代码时,我们都会采用它们,所以很有必要学习并掌握它们。
各工具都相当的独立
在开始前,需要先提示一下,在javascript的世界里,很多东西都是由社区提供的,所以每一种工具都相当独立。比如,很多工具都有着自己独立的配置文件,自己的命令行参数,有时候还需要有一些额外的插件把两个工具结合起来。
所以下面将会有很多比较琐碎的命令,我们需要一一了解。不过好在我们一旦了解了,下次就可以使用已经配置好的文件,通过几条命令将把有的东西都准备好,很方便。
安装nodejs
在Mac中,我们可以使用brew来安装。在其它系统下,请使用相应的工具或直接到官网下载。
brew install node
Nodejs可以让我们在服务器端使用javascript编程,它是很多js工具的基础。如果你已经安装,请确保使用最新版本:
brew upgrade node
查看版本:
node -v
我这里显示:
v0.10.28
npm
Npm是node官方提供的包依赖管理工具。我们下面使用的grunt等,都是以插件形式下载安装的。
当我们安装好nodejs后,npm
就自动可用了。
查看版本:
npm -v
我这里显示:
2.0.0-alpha-5
创建项目目录
下面我们从零开始,首先在任意位置新建一个目录作为我们的项目根目录,比如:
mkdir ~/myproject
然后进入该目录:
cd ~/myproject
后面的命令都将在项目根目录下操作。
为npm创建package.json
首先我们需要为npm提供一个package.json
,告诉它我们的项目信息,特别是项目中将会使用的插件。我们不需要手动创建,因为可以直接调用以下命令:
npm init
它会问我们一些问题,我们可以按需回答,也可以全部使用默认值,反正以后可以改起来也很容易。
最后将会产生如下的package.json
文件:
{
"name": "grunt-bower-angular-demo",
"version": "0.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/freewind/grunt-bower-angular-demo.git"
},
"author": "",
"license": "BSD",
"bugs": {
"url": "https://github.com/freewind/grunt-bower-angular-demo/issues"
}
}
对于像我们这样的非nodejs项目来说,里面的大部分内容都没用,可以删掉大部分,只剩下:
{
"name": "grunt-bower-angular-demo",
"version": "0.0.0"
}
安装 grunt
npm install grunt --save-dev
将使用npm下载grunt插件,它们将保存到项目根目录下的node_components
目录下。
后面的--save-dev
参数是说,把这个插件信息,同时添加到package.json
的devDependencies
中:
"devDependencies": {
"grunt": "~0.4.5"
}
由于grunt仅在开发阶段使用,所以使用--save-dev
。如果是运行时使用的,则用--save
安装 grunt-cli
上面安装的grunt
并不包含命令行工具,我们还需安装相应的grunt-cli
,才能在命令行中调用grunt
命令:
npm install grunt-cli -g
后面的-g
是说,把grunt-cli
安装成全局工具,以便在任意目录下使用。
安装后,输入:
grunt --version
我这里显示为:
grunt-cli v0.1.13
grunt v0.4.5
在比较少的情况下,可能提示找不到grunt,则需要根据安装grunt-cli时的提示信息,把相应的路径添加到PATH
中:
echo PATH=$PATH:/your/path/to/grunt >> ~/.bashrc
source ~/.bashrc
为grunt创建配置文件Gruntfile.js
安装grunt-init
npm install grunt-init -g
下载grunt模板
git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile
生成Gruntfile
grunt-init gruntfile
根据需要回答问题,或者使用默认值,将得到以下Gruntfile.js
文件:
/*global module:false*/
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON(‘package.json‘),
banner: ‘/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ‘ +
‘<%= grunt.template.today("yyyy-mm-dd") %>\n‘ +
‘<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>‘ +
‘* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;‘ +
‘ Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n‘,
// Task configuration.
concat: {
options: {
banner: ‘<%= banner %>‘,
stripBanners: true
},
dist: {
src: [‘lib/<%= pkg.name %>.js‘],
dest: ‘dist/<%= pkg.name %>.js‘
}
},
uglify: {
options: {
banner: ‘<%= banner %>‘
},
dist: {
src: ‘<%= concat.dist.dest %>‘,
dest: ‘dist/<%= pkg.name %>.min.js‘
}
},
jshint: {
options: {
curly: true,
eqeqeq: true,
immed: true,
latedef: true,
newcap: true,
noarg: true,
sub: true,
undef: true,
unused: true,
boss: true,
eqnull: true,
browser: true,
globals: {
jQuery: true
}
},
gruntfile: {
src: ‘Gruntfile.js‘
},
lib_test: {
src: [‘lib/**/*.js‘, ‘test/**/*.js‘]
}
},
qunit: {
files: [‘test/**/*.html‘]
},
watch: {
gruntfile: