【Yeoman】热部署web前端开发环境
本文来自 “简时空”:《【Yeoman】热部署web前端开发环境》(自动同步导入到博客园)
1、序言
记得去年的暑假看RequireJS的时候,曾少不更事般地惊为前端利器,写了《Speed up! 提速你的网站访问速度[压缩JS与CSS]》。随着学习的深入,发现前端的还有许多东西需要整合,纯手工劳动无疑降低了开发效率。这四天的工作,真是把这两年所学习到的知识综合应用了一番:
软实力层面包括:使用Photoshop+Bootstrap3+Grid System 设计页面UI图;
工具语言包括:CoffeeScript、LESS、Handlebars等;
图形库的使用:Highchart、jvectorMap、D3等这些一年前就开始用的库
>>>>> 页面效果:http://www.janscon.com/weibo/index.html <<<<
当然重点不在于这个,这次学习的重点在于使用Yeoman热部署了前端环境,使用Grunt、NPM、Bower等工具 起“穿针引线”作用将这些技术互相联系起来,使得前端的开发从未如此“一气呵成”~
既然这些工具都把重要的工作做了,那么作为程序猿的我意义何在呢?
呃~ OK,“我们不生产代码,我们只是英文字母的搬运工而已啦”
这几天的工作还是留下遗憾的,就是没能用上前端自动化测试工具——以后得好好学习Qunit+Mocha+ Selenium这些玩意儿了
2、工作准备
如果读者对Grunt、Yeoman还不是很了解,建议先参看这几篇文章,非常适合入门:
① Xianjing.《Grunt - 基于任务的Javascript构建工具》. 2013-05-16
② RIA之家. 《前端项目可以更简单—Yeoman入门指南》.2013-4-25
③ 阮一峰. 《任务管理工具Grunt》.
上面这三篇文章已经将Yeoman、Grunt等语法讲解非常明了了,所以我的文章里就不在这些方面多费口舌。这里将只重点讲解我工作的流程,作文以记之。
找到目标:如何使用Yeoman搭建单页面、多页面的开发环境
使用工具:Bootstrap(基于LESS)、Handlebars、CoffeeScript,使用RequireJS组织JS代码
示例代码:
本文所讲的程序代码可以从这儿下载:
① 单页面前端环境搭建示例代码:jscon-single-page.zip (百度云盘)
② 多页面前端环境搭建示例代码:jscon-multi-pages.zip (百度云盘)
3、构建单页面开发环境
3.1、使用Bootstrap-less生成器
使用Yeoman入门的时候,使用的webapp这个生成器,不过里面的Bootstrap是基于SASS的。个人倾向于使用LESS语言的,毕竟它是基于我熟悉的Node环境而非Ruby。
Step 1: 安装Bootstrap-less生成器
npm install generator-bootstrap-less
Step 2: 生成程序脚手架
yo bootstrap-less
Step 3: 代码热部署
grunt server
看到这个自动跳出来的 “Allo,“Allo! 页面,说明已经成功搭建环境了。可以开始在这个基础上编写代码,只是我还有使用Handlebars以及RequireJS,所以还得自己安装这些组件。
在继续之前,在这里顺便对比一下webapp与bootstrap-less这两个脚手架的区别:
如果除去我想要的Bootstrap之外,bootstrap-less生成器是一无所有啊(Bootstrap的JS文件和FontAwesome都勾上吧,因为都要用到的),而webapp还有RequireJS和Modernizr呢,显然是“高富帅”一枚。
不过我还是选bootstrap-less,因为它使用的是LESS而不是SASS(我难道有强迫症?);至于RequireJS和Modernizr的使用可以借鉴webapp生成的index.html中写法即可——我就是这么干的!
3.2、引入Handlebars
引入Handlebars是看中了它使用方便且能够预编译这两优点的。一般使用bower工具引入所需要的包,不过Handlebar是个例外,这是因为官方Github并不提供现成的前端页面的Handlebar.js文件,需要通过其文档主页到Amazon的S3平台(http://handlebarsjs.com/)上下载;所以不要使用bower install handlebar.js命令
在模板预编译的时候是需要借助Node环境,所以使用npm安装Handlebars插件:
Step 1: 使用npm,下载contrib模块
npm install --save-dev grunt-contrib-handlebars
Step 2: 同时在Gruntfile.js中注册下面的Task:
(在Gruntfile.js文件中修改)
handlebars:{
dist: {
options: {
namespace: "JST",
wrapped:true
},
// files: {"<%= yeoman.app %>/hbs/templates.js":["<%= yeoman.app %>/hbs/*.hb"]}
expand:true,
src:"<%= yeoman.app %>/hbs/*.hb",
ext:".js"
}
}
默认的namespace是“Handlebars.templates”,后期使用uglify.js进行优化的时候会将Handlebars用变量“a”(或者其他名字)代替,从而提示该变量没有templates属性;因此推荐像上面那样使用“JST”等作为命名空间。
Step 3: 还需要配置编译及livereload功能
首先在watch任务中添加对.hb文件的监视即可
(在Gruntfile.js文件中修改)
watch: {
handlebars:{
files:['<%= yeoman.app %>/hbs/{,*/}*.hb'],
tasks:['handlebars']
},
….
livereload: {
files: [
'<%= yeoman.app %>/*.html',
'{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css',
'{.tmp,<%= yeoman.app %>}/{scripts,hbs}/{,*/}*.js',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
],
tasks: ['livereload']
}
},
Step 4: 注册预编译任务
在concurrent任务中注册handlebars任务,确保项目发布的时候所有模板都经过编译:
(在Gruntfile.js文件中修改)
concurrent: {
dist: [
'handlebars',
'coffee',
'recess',
'imagemin',
'svgmin',
'htmlmin'
]
}
配置完后,这里就简单的举个例子表明如何使用:
Step 1:创建模板
创建hbs文件夹,并在其下面新建一个messages.hb文件,此时文件夹结构如下:
messages.hb内容如下:
{{#messages}}
<div class="message">
<h2 class="name">{{name}}</h2>
<div class="msgContent">{{msgContent}}</div>
<div class="msgTime">{{msgTime}}</div>
</div>
{{/messages}}
Step 2:添加JS代码
先在index.html页面中添加ID为“list”的空白DIV:
<div id="list"></div>
再在index.html文件中添加runtime.js官方文件,以及messages.js文件(注意不是messages.hb文件,热部署的时候会自动调用Node将其编译成messages.js文件):
(在app/index.html文件中修改)
<!-- build:js scripts/main.js -->
<script src="bower_components/jquery/jquery.js"></script>
<script src="scripts/lib/handlebars/handlebars.runtime-v1.1.2.js"></script>
<script type="text/javascript" src="hbs/messages.js"></script>
<script src="scripts/main.js"></script>
<!-- endbuild -->
其中的main.js是逻辑实现代码:
app/scripts/main.js
$(function(){
var data = {
messages:
[
{name:"Zhang",msgContent:"I'm San",msgTime:"Yesterday"},
{name:"Li",msgContent:"I'm Si",msgTime:"Today"},
{name:"Wang",msgContent:"I'm Wu",msgTime:"Tomorrow"}
],
name:"jscon"
};
var template = JST["app/hbs/messages.hb"];
console.log(template)
$("#list").html(template(data));
});
这里下划线标出的:
var template = JST["app/hbs/messages.hb"];
需要注意两个地方,一个是命名空间“JST”要与配置文件中保持一致;另外一个当调用模板的时候注意路径是相对app的路径。至于如何去掉“app/hbs”这个路径,目前还不知道如何解决。
Step 3:查看效果
在程序根目录下运行:
grunt server
发现还是之前的页面,调出chrome console会提示找不到“messages.js”文件;好吧下面见证奇迹的时刻,打开messages.hb文件,直接按下“Ctrl+S”保存文件,触发watch任务,其中就包括执行handlebars任务(其他的还有coffee、recess任务),然后自动执行livereload任务刷新页面。现在看看效果页面:
参考文章:
[1] 官方Github文档《grunt-contrib-handlebars》
[2] 官方Grunt文档:https://npmjs.org/package/grunt-contrib-handlebars
3.3、使用RequireJS组织JS文件
我们看看现在的index.html页面的截图:
可以看到这么简单的页面里面有一大串的JS文件需要加载,主要包括:
1) 个人的JS文件,比如上节讲的模板文件(message.js)和逻辑文件(main.js)。
2) 官方的JS库文件,比如jQuery、还有许多BootStrap需要的组件JS文件;
通过RequireJS组织JS文件,到时就只用一句话就够了:
<!-- build:js scripts/main.js -->
<script data-main="scripts/main" src="bower_components/requirejs/require.js"></script>
<!-- endbuild -->
Step 1:安装RequireJS包
bower install --save requirejs
执行此语句之后,就会自动更新bower.json文件,同时在app/bower_components中下载官方的requirejs组件。
Step 2:添加RequireJS的Node模块
npm install grunt-contrib-requirejs --save-dev
这样能够将grunt-contrib-requirejs组件自动下载到node_modules文件夹下,同时因为使用了--save-dev会自动更新package.json文件。
官方文档:https://github.com/gruntjs/grunt-contrib-requirejs
Step 3:修改Gruntfils.js文件,配置requirejs任务
为了能够利用RequireJS的r.js文件对输出文件进行优化,需要在Gruntfiles.js中注册相应任务。关于r.js的详细配置可以参考官方示例:
(在Gruntfile.js文件中修改)
requirejs: {
dist: {
// Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
options: {
// `name` and `out` is set by grunt-usemin
baseUrl: yeomanConfig.app + '/scripts',
mainConfigFile:'<%= yeoman.app %>/scripts/config.js',
optimize: 'none',
// TODO: Figure out how to make sourcemaps work with grunt-usemin
// https://github.com/yeoman/grunt-usemin/issues/30
//generateSourceMaps: true,
// required to support SourceMaps
// http://requirejs.org/docs/errors.html#sourcemapcomments
preserveLicenseComments: false,
useStrict: true,
wrap: true
//uglify2: {} // https://github.com/mishoo/UglifyJS2
}
}
},
这里的config.js是专门的RequireJS配置文件,主要是所有文件中的依赖关系,配置了paths和shim项:
app/scripts/config.coffee
require.config
paths:
## jQuery
'jquery':'../bower_components/jquery/jquery' ## BootStrap
'bootstrap-affix': "../bower_components/bootstrap/js/affix"
'bootstrap-transition': "../bower_components/bootstrap/js/transition"
"bootstrap-alert": "../bower_components/bootstrap/js/alert"
"bootstrap-button": "../bower_components/bootstrap/js/button"
"bootstrap-collapse": "../bower_components/bootstrap/js/collapse"
"bootstrap-dropdown": "../bower_components/bootstrap/js/dropdown"
"bootstrap-modal": "../bower_components/bootstrap/js/modal"
"bootstrap-tooltip": "../bower_components/bootstrap/js/tooltip"
"bootstrap-popover": "../bower_components/bootstrap/js/popover"
"bootstrap-scrollspy": "../bower_components/bootstrap/js/scrollspy"
"bootstrap-tab": "../bower_components/bootstrap/js/tab"
"bootstrap-carousel": "../bower_components/bootstrap/js/carousel" ## Handlebars runtime
'runtime':'lib/handlebars/handlebars.runtime-v1.1.2' ## Templates
'messages':'../hbs/messages'
Step 4:将requirejs添加build任务中
为了能够在发布时,使用r.js进行页面优化(合并、压缩等),需要将requirejs任务作为build任务的子任务:
(在Gruntfile.js文件中修改)
grunt.registerTask('build', [
'clean:dist',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'requirejs',
'concat',
'cssmin',
'uglify',
'modernizr',
'copy:dist',
'rev',
'usemin'
]);
Step 5:重新组织index.html页面中的js文件
接下来删除Figure 9中的所有script标签,代之以下面的语句:
(在app/index.html文件中修改)
<!-- build:js scripts/main.js -->
<script data-main="scripts/main" src="bower_components/requirejs/require.js"></script>
<!-- endbuild -->
入口文件还是main.js,只是现在改成RequireJS要求的格式:
app/scripts/main.coffee
require.config
paths:
'jquery':'../bower_components/jquery/jquery',
'runtime':'lib/handlebars/handlebars.runtime-v1.1.2',
'messages':'../hbs/messages' require ['jquery','runtime','messages','bootstrap'],($)->
'use strict';
$ ->
data =
messages:[
{name:"Zhang",msgContent:"I'm San",msgTime:"Yesterday"}
{name:"Li",msgContent:"I'm Si",msgTime:"Today"}
{name:"Wang",msgContent:"I'm Wu",msgTime:"Tomorrow"}
]
name:"jscon"
template = JST["app/hbs/messages.hb"]
$("#list").html(template(data))
注意这里的bootstrap依赖文件用来配置需要哪些bootstrap组件用的,可以自己定制所需要的插件内容,挺方便的。这里给出最全的配置,内容如下:(参考自https://gist.github.com/taxilian/4790603)
app/scripts/bootstrap.coffee
require.config
paths:
'jquery':'../bower_components/jquery/jquery',
'bootstrap-affix':"../bower_components/bootstrap/js/affix",
'bootstrap-transition':"../bower_components/bootstrap/js/transition",
"bootstrap-alert":"../bower_components/bootstrap/js/alert",
"bootstrap-button":"../bower_components/bootstrap/js/button",
"bootstrap-collapse":"../bower_components/bootstrap/js/collapse",
"bootstrap-dropdown":"../bower_components/bootstrap/js/dropdown",
"bootstrap-modal":"../bower_components/bootstrap/js/modal",
"bootstrap-tooltip":"../bower_components/bootstrap/js/tooltip",
"bootstrap-popover":"../bower_components/bootstrap/js/popover",
"bootstrap-scrollspy":"../bower_components/bootstrap/js/scrollspy",
"bootstrap-tab":"../bower_components/bootstrap/js/tab",
"bootstrap-carousel":"../bower_components/bootstrap/js/carousel"
shim:
"bootstrap-affix": ["jquery"],
"bootstrap-transition": ["bootstrap-affix"],
"bootstrap-alert": ["bootstrap-transition"],
"bootstrap-button": ["bootstrap-alert"],
"bootstrap-collapse": ["bootstrap-button"],
"bootstrap-dropdown": ["bootstrap-collapse"],
"bootstrap-modal": ["bootstrap-dropdown"],
"bootstrap-tooltip": ["bootstrap-modal"],
"bootstrap-popover": ["bootstrap-tooltip"],
"bootstrap-scrollspy": ["bootstrap-popover"],
"bootstrap-tab": ["bootstrap-scrollspy"],
"bootstrap-carousel": ["bootstrap-tab"]
define ['jquery',
"bootstrap-affix",
"bootstrap-transition",
"bootstrap-alert",
"bootstrap-button",
"bootstrap-collapse",
"bootstrap-dropdown",
"bootstrap-modal",
"bootstrap-tooltip",
"bootstrap-popover",
"bootstrap-scrollspy",
"bootstrap-tab",
"bootstrap-carousel"
],($)->
至此配置完成,在命令行中输入 grunt server 就可以看到以前熟悉的页面了,没错,you make it!
3.4、发布程序
程序的发布,使用
grunt build --force 或者 grunt --force
加force选项的目的是为了在执行任务时的出现warning提示时,并不中断任务的执行而是继续执行到完成(或出现Error)。
此时你会在根目录下出现一个dist文件夹, 这个文件夹的结构和app文件夹相似
可以发现只有一个js文件和css文件,都是经过压缩的。js的压缩是RequireJS、concat和uglify共同的作用结果,css的压缩则是concat和cssmin的作用结果。使用RequireJS会根据入口文件main.js中找到所有的依赖,然后合并成一个大的main.js文件:
这个dist文件夹就是可以发布的版本了,(改个名字后)扔到服务器上就可以了。
4、构建多页面前端环境
还记得小时候看过的童话故事中的那只偷香油的小老鼠么?有时候,一种优势在另外一种情况下就成了弊端。上面我们讲的usemin就是这个一个情况。
我们回过头来看发布时命令窗口中的几行提示:
这些反馈信息都来自usemin的工作,usemin组件能够自动更新Gruntfile中诸如concat、uglify、requirejs的配置文件,所以前面我们在单页面环境时根本不用考虑如何合并、压缩文件,因为usemin默默地帮你完成了——真是人民的好公仆呢。
usemin所做的工作对单页面来讲非常有用,增加了配置过程的自动化。不过在RequireJS用于多页面开发时,需要使用dir以及modules配置,但是usemin“仍然不知情”,还是会自动给requirejs任务添加name属性和out属性(单页面配置),从而导致配置冲突。
要想自动部署多页面,那么只能忍痛割爱抛弃usemin组件,需要自己写concat和uglify任务,还好这些都不难。在前面单页面环境搭建的基础上,配置多页面环境也是非常方便快捷的。
4.1、抛弃usemin任务
因为usemin和requirejs任务都是用于发布时执行的,所以只要在build任务中除名即可,除名之后build任务的配置如下:
grunt.registerTask('build', [
'clean:dist',
'copy:server',
'concurrent',
'requirejs',
'cssmin',
'concat',
'uglify',
'copy'
]);
4.2、修改requirejs任务
修改requirejs任务,添加用于多任务的dir和modules配置:
(在Gruntfile.js文件中修改)
requirejs: {
dist: {
…
baseUrl:'<%= yeoman.app %>/scripts',
mainConfigFile:'<%= yeoman.app %>/scripts/config.js',
optimize: 'none',
dir: '.tmp/scripts/requirejs/',
modules:[
{name:"main"},
{name:"main2"}
],
…
}
},
注意
① 输出的文件暂时放在 .tmp临时文件夹下,这样到时clean任务会清空这个临时文件夹。
② 这里的modules中模块的名字都是以“main”开头的,是为了方便后面concat任务找文件。
4.3、修改concat、uglify任务
移走了usemin任务之后,concat和uglify需要自己定制。其实concat任务更像是copy功能,因为合并的工作已经由requirejs做了。
(在Gruntfile.js文件中修改)
concat:{
dist:{
expand:true,
cwd:".tmp/scripts/requirejs/",
src:['main*.js'],
dest:'<%= yeoman.dist %>/scripts/',
ext:'.js'
},
dep:{
files:{
"<%= yeoman.dist %>/scripts/vendor/modernizr.js":["<%= yeoman.app %>/bower_components/modernizr/modernizr.js"],
'<%= yeoman.dist %>/bower_components/requirejs/require.js':['<%= yeoman.app %>/bower_components/requirejs/require.js']
}
}
},
这里的“dist”任务是用来搬运的之前requirejs放在.tmp中的入口文件(main*.js)到结果文件夹dist下。而“dep”任务则是搬运其他需要的js文件,这里是modernizr.js和require.js两个文件。
由于requirejs和concat已经把该合并的文件都放到目标文件下面去了,所以uglify的任务就非常简单了,把这些目标文件下的文件“就地”压缩一下即可:
uglify: {
src:['<%= yeoman.dist %>/{,*/}*.js']
},
4.4、测试
把index.html另存一份为index2.html,并将其中的入口文件改成main2:
<script data-main="scripts/main2" src="bower_components/requirejs/require.js"></script>
然后把main.js另存为一份main2.js。接下去使用 grunt --force 发布程序,可以看到效果。
参考文献:
[1] 科学的爱情. 《Grunt + RequireJS with multi-page website》. 2013-03-11
[2] Xianjing《玩转Grunt(一): Minification》.2013-10-7
最后友情提醒一句,本文所讲的程序代码可以从这儿下载:
单页面前端环境搭建示例代码:jscon-single-page.zip
多页面前端环境搭建示例代码:jscon-multi-pages.zip
~~The End~~
【Yeoman】热部署web前端开发环境的更多相关文章
- 用grunt搭建自动化的web前端开发环境实战教程(详细步骤)
用grunt搭建自动化的web前端开发环境实战教程(详细步骤) jQuery在使用grunt,bootstrap在使用grunt,百度UEditor在使用grunt,你没有理由不学.不用!前端自动化, ...
- 用grunt搭建web前端开发环境
1.前言 本文章旨在讲解grunt入门,以及讲解grunt最常用的几个插件的使用. 2.安装node.js Grunt和所有grunt插件都是基于nodejs来运行的,如果你的电脑上没有nodejs, ...
- 【前端福利】用grunt搭建自动化的web前端开发环境-完整教程
jQuery在使用grunt,bootstrap在使用grunt,百度UEditor在使用grunt,你没有理由不学.不用! 1. 前言 各位web前端开发人员,如果你现在还不知道grunt或者听说过 ...
- 转:【前端福利】用grunt搭建自动化的web前端开发环境-完整教程
原文地址:http://blog.csdn.net/wangfupeng1988/article/details/46418203 jQuery在使用grunt,bootstrap在使用grunt,百 ...
- 用grunt搭建自动化的web前端开发环境-完整教程
原稿:http://www.cnblogs.com/wangfupeng1988/p/4561993.html#!comments jQuery在使用grunt,bootstrap在使用grunt,百 ...
- Web 前端开发环境
创建 Web 前端开发环境 Web 前端开发涉及多种工具,这里将常用工具的安装和配置进行说明,提供了详细的说明,为后继的开发创建一个坚实的基础. 本文介绍的工具有:NodeJS, NPM, Bower ...
- 用grunt搭建自动化的web前端开发环境
用grunt搭建自动化的web前端开发环境 jQuery在使用grunt,bootstrap在使用grunt,百度UEditor在使用grunt,你没有理由不学.不用! 1. 前言 各位web前端开发 ...
- Grunt搭建自动化web前端开发环境--完整流程
Grunt搭建自动化web前端开发环境-完整流程 jQuery在使用grunt,bootstrap在使用grunt,百度UEditor在使用grunt,你没有理由不学.不用! 1. 前言 各位web前 ...
- grunt搭建自动化的web前端开发环境(转)
1. 前言 各位web前端开发人员,如果你现在还不知道grunt或者听说过.但是不会熟练使用grunt,那你就真的真的真的out了(三个“真的”重复,表示重点).至于grunt的作用,这里不详细说了, ...
随机推荐
- [Java Web]Error parsing HTTP request header Note: further occurrences of HTTP header parsing errors
手机客户端向服务器提交Http请求时,Tomcat抛出错误: 十二月 31, 2014 2:32:45 下午 org.apache.coyote.http11.AbstractHttp11Proces ...
- css 水平垂直居中
主要是垂直居中有点麻烦,以下代码可以实现,先记下来: <style type="text/css"> div{ border:1px solid #ccc; heigh ...
- HttpClient,DefaultHttpClient使用详解
HttpClient:是一个接口 首先需要先创建一个DefaultHttpClient的实例 HttpClient httpClient=new DefaultHttpClient(); 发送GET请 ...
- Android Studio 自定义debug签名文件keystore
Android Studio 自定义debug签名文件keystore
- 某预约系统分析 > 某区公共自行车租车卡在线预约,关于如何提高成功概率
概诉 网上提交预约申请单,线下面交完成实体卡的交付和办理. 本文主要从技术角度分析预约页面,仅供初学者技术交流使用. 表单输入和校验 系统通过2步的确认点击到达信息输入页面. 地址:/bjggzxc/ ...
- tinkphp登录验证码的使用
登录和验证(控制器) <?php namespace Come\Controller; use Think\Controller; class RenController extends Con ...
- centos6.6_64位操作系统安装时候出现kernel panic - not syncing: Attempted to kill init 解决办法
最近在VM上安装centos时候经常被这个问题虐,后来进入单用户模式在 kernel /vmlinuz-XXXXro root=/dev/vogroup00/logvol00 rhgb quie ...
- 20161127-emmagee
Android 自动化测试 Emmagee Emmagee 是一个性能测试小工具 用来监控指定被测应用在使用过程中占用机器的CPU, 内存,流量资源的性能小工具 阅读目录 Emmagee 介绍 Emm ...
- Word 宏命令大全
1. 为宏命令指定快捷键.在WORD中,操作可以通过菜单项或工具栏按钮实现,如果功能项有对应的快捷键的话,利用快捷键可以快速实现我们需要的功能.如最常见的CTRL+O.CTRL+A等等.WOR ...
- 前言,学习ios编程(坚持)
其实,尝尝有人很疑惑,不知道自己要干嘛,看到很多的培训机构,不知道怎么选择但是又想进入软件行业.其实呢学习不一定要靠培训机构,一定要培训,特别是 当人家把自己吹的天花乱坠的时候,然并卵.出来之后,也只 ...