基于Gulp + Browserify构建es6环境下的自动化前端项目
随着React、Angular2、Redux等前沿的前端框架越来越流行,使用webpack、gulp等工具构建前端自动化项目也随之变得越来越重要。鉴于目前业界普遍更流行使用webpack来构建es6(ECMAScript 2015)前端项目,网上的相关教程也比较多;相对来说使用gulp来构建es6项目的中文教程就比较少。
经过一段时间的摸索,我觉得其实使用gulp
也可以很方便地构建es6项目。以下是我感觉gulp
和webpack
主要的不同之处:
gulp
的任务机制和流式管道函数和webpack
的配置参数风格有着显著区别,它能使开发者更清晰地了解项目的构建流程。- 由于
gulp
是编程式风格的,所以使用起来可定制化的功能也就更灵活一些,可应对一些构建过程较为复杂的情况。
本文特此给大家介绍下如何使用gulp
配合browserify
来构建基于es6的前端项目。
Browserify vs Webpack
browserify
与webpack
都是当下流行的commonjs模块(或es6模块)合并打包工具,打包后的js文件可以直接运行在浏览器环境中。
很多人都知道,webpack
功能全面,可以对js、css、甚至图片、字体文件统一进行合并打包,并且插件丰富。而browserify
的特点是职责单一,只负责js模块合并打包,有些项目也并不需要将css等资源文件和js打包在一起的功能;它的代码风格也类似管道函数,和gulp
的契合度较高;在github上也可以找到相当多的browserify
插件,如热替换、代码分割等等。
有一篇文章对
browserify
和webpack
的对比进行了探讨:webpack 跟 browserify 比到底有什么好?
示例项目
本文中使用的示例项目是我为重构过去搞的UI组件库而建的项目,使用browserify
构建的分支地址请戳这里。这个项目目前已改用gulp
+webpack
构建,但是保留了原先用browserify
构建的分支代码可供参考。
项目结构目录
- 项目目录
- dist (生产代码目录,存放生成合并后的各类文件)
- js
- 构建出的项目js文件
- fonts
- ...
- css
- 构建出的项目css文件
- js
- examples (示例目录)
- src (开发代码目录)
- styles (样式文件目录)
- base.js (打包入口文件)
- ...
- test (单元测试目录)
- vendor (第三方依赖库)
- babelHelpers.js
- ...
- gulpfile.js (gulp配置文件)
- package.json
- LICENSE
- README.md
- dist (生产代码目录,存放生成合并后的各类文件)
示例项目目录大体如上所示,其中使用babel
进行es6至es5转换,并使用eslint
进行js代码检验。大家看到这里可能有疑问,为什么项目中没有babel及eslint的配置文件.babelrc
和.eslintrc
呢?原因就是这些配置文件里的内容其实是可以直接配置在gulpfile.js
中的相关插件内的。
配置package.json
在这里只列出项目依赖的各种包,大致分为如下几类:
{
...
"devDependencies": {
/*browserify包及相关插件*/
"browserify": "^13.0.0",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0",
"standalonify": "^0.1.3",
/*babel相关插件*/
"babelify": "^7.2.0",
"babel-plugin-external-helpers": "^6.4.0",
"babel-plugin-transform-es2015-classes": "^6.5.2",
"babel-plugin-transform-es2015-modules-commonjs": "^6.5.2",
"babel-plugin-transform-object-assign": "^6.3.13",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babel-preset-stage-0": "^6.3.13",
/*eslint相关插件*/
"babel-eslint": "^5.0.0",
"estraverse": "^4.2.0",
"estraverse-fb": "^1.3.1",
/*gulp包及相关插件*/
"gulp": "^3.9.0",
"gulp-clean": "^0.3.1",
"gulp-concat": "^2.6.0",
"gulp-cssnano": "^2.1.1",
"gulp-eslint": "^2.0.0",
"gulp-if": "^2.0.0",
"gulp-jasmine": "^2.2.1",
"gulp-less": "^3.0.5",
"gulp-rename": "^1.2.2",
"gulp-sequence": "^0.4.4",
"gulp-uglify": "^1.5.1",
/*postcss相关插件*/
"gulp-postcss": "^6.1.0",
"autoprefixer": "^6.3.4",
/*外部依赖包*/
"nornj": "^0.3.0",
"react": "^0.14.8",
"react-dom": "^0.14.8",
/*其他依赖包*/
"jsdom": "^8.1.0",
"yargs": "^4.2.0",
...
},
...
}
编写gulpfile.js
gulpfile.js即为gulp
的配置文件,其作用类似于webpack
的webpack.config.js文件。在代码风格方面,与webpack.config.js的配置参数风格不同的是,gulpfile.js更偏向编程风格。gulpfile.js整体结构如下所示:
//引入依赖的各种包:
var gulp = require('gulp'),
browserify = require('browserify'),
...
//定义一些全局函数及变量
function getJsLibName() {
...
}
...
//定义各种任务
gulp.task('build-all-js', ...);
gulp.task('build-all-css', ...);
gulp.task('build', ['build-all-js', 'build-all-css', ...]);
...
//定义默认任务
gulp.task('default', ['build']);
使用gulp
需要定义各种任务来处理各类文件的构建生成。如例中所示,定义build-all-js任务来构建js文件,执行任务时须输入命令:
gulp build-all-js
可以定义一个默认任务,一般在这个任务里依次执行全部子任务,执行时输入命令:
gulp
关于
gulp
基础使用方法的更多细节大家可以参考这篇文章:前端构建工具gulpjs的使用介绍及技巧
使用Browserify进行js模块合并
配合gulp
使用browserify
需要引入的包:
var browserify = require('browserify'),
source = require('vinyl-source-stream'),
buffer = require('vinyl-buffer'),
standalonify = require('standalonify'),
argv = require('yargs').argv;
创建gulp
任务build-js:
gulp.task('build-js', function () {
return browserify({
entries: './src/base.js' //指定打包入口文件
})
.plugin(standalonify, { //使打包后的js文件符合UMD规范并指定外部依赖包
name: 'FlareJ',
deps: {
'nornj': 'nj',
'react': 'React',
'react-dom': 'ReactDOM'
}
})
.transform(babelify, ...) //使用babel转换es6代码
.bundle() //合并打包
.pipe(source(getJsLibName())) //将常规流转换为包含Stream的vinyl对象,并且重命名
.pipe(buffer()) //将vinyl对象内容中的Stream转换为Buffer
.pipe(gulp.dest('./dist/js')); //输出打包后的文件
});
function getJsLibName() {
var libName = 'flarej.js';
if (argv.min) { //按命令参数"--min"判断是否为压缩版
libName = 'flarej.min.js';
}
return libName;
}
- 和
webpack
类似,browserify
也需要指定打包的入口文件。在本例中只有一个入口文件,browserify
会自动分析文件内依赖的各js模块,最终生成一个完整的打包文件。 - 使用
standalonify
插件使打包后的js文符合UMD规范,并可以指定不将一些外部依赖包打进包内。一开始我使用了dependify
,之后发现它生成的包有bug且作者又不维护,于是就参考它重发了一个更完善的standalonify
。使用这个插件打出来的包可以更好地生成依赖包的信息,此功能就类似于webpack
中的externals参数。例如UMD中的AMD部分会这样生成:
...
else if (typeof define === 'function' && define.amd) { define(["nornj","react","react-dom"], ...)
...
其实使用browserify
自带的standalone属性也可以打出UMD包,并配合browserify-shim插件也可以排除外部依赖包,但是打包后依赖包的信息只能定义为全局的。
- 然后使用bundle方法进行js模块合并打包,如代码为es6环境则需在此之前执行transform方法进行es6转es5。
browserify
在打包后须要进行Stream转换才可和gulp
配合,在这里需要使用vinyl-source-stream
和vinyl-buffer
这两个包。- 在使用
vinyl-source-stream
时可以将打包文件重命名,此时可用yargs
包提供的获取命令参数功能来决定是否使用压缩版命名。例如命名为压缩版需输入命令:
gulp build-js --min
- 最后使用gulp.dest方法指定打包后文件保存的目录。
关于
browserify
更详细的技术资料大家可以参考这篇文章:browserify使用手册
使用Babel将es6代码转换为es5
由于es6代码目前大部分浏览器还未能完全支持,因此一般都需要转换为es5后执行。本示例中使用babel
配合browserify
在打包的过程中进行转换,babel
的版本为6.0+。需要引入babelify
,这个包是browserify
的一个transform插件。使用方法如下:
gulp.task('build-js', function () {
return browserify({
entries: './src/base.js'
})
.plugin(standalonify, ...)
.transform(babelify, { //此处babel的各配置项格式与.babelrc文件相同
presets: [
'es2015', //转换es6代码
'stage-0', //指定转换es7代码的语法提案阶段
'react' //转换React的jsx
],
plugins: [
'transform-object-assign', //转换es6 Object.assign插件
'external-helpers', //将es6代码转换后使用的公用函数单独抽出来保存为babelHelpers
['transform-es2015-classes', { "loose": false }], //转换es6 class插件
['transform-es2015-modules-commonjs', { "loose": false }] //转换es6 module插件
...
]
})
.bundle()
...
});
babelify
插件的配置项格式与.babelrc
文件完全相同。在babel
升级6.0+后与之前的5.x差别较大,它拆分为了很多个模块需要分别引入。这些模块都需要单独安装各自的npm包,具体请查看package.json文件。- presets项需要使用es2015、stage-x、react三个模块:
es2015
,用于转换es6代码stage-x
,用于转换更新的es7语法,x是指es7不同阶段的语法提案,目前有0-3可用react
,用于转换React的jsx代码。
- plugins项可引入转换时需要的插件。一般来说babel-preset-es2015这个包中已经包含了大多数转换es6代码的模块,但也有部分模块需要在plugins中引入。例如:
transform-object-assign
,用于转换Object.assign- 如转换时使用loose模式(设置了loose为true时代码才可适应IE8,默认为false),则需要单独引入这些模块的包。如
transform-es2015-classes
即为转换es6 class的包,如有需要可设置loose模式为true。 external-helpers
,这个模块的作用是将babel转换后的一些公用函数单独抽出来,这样就可以减少转换后的冗余代码量。具体使用方法为先全局安装babel:
npm install babel-cli -g
然后执行命令:
babel-external-helpers #可加-t参数按不同方式生成,值为global|umd|var,默认为global
这样就可以在命令行中生成babelHelpers的代码,然后将之保存为babelHelpers.js,在本例中放在vendor目录内。
生成最终的js代码
由于本例中使用external-helpers方式进行es6转换,故需要将babelHelpers.js与browserify
打包后的项目js文件进行连接合并:
var concat = require('gulp-concat'),
sequence = require('gulp-sequence'),
gulpif = require('gulp-if'),
uglify = require('gulp-uglify');
//定义连接js任务
gulp.task('concat-js', function () {
var jsLibName = getJsLibName();
return gulp.src(['./vendor/babelHelpers.js', './dist/js/' + jsLibName])
.pipe(concat(jsLibName))
.pipe(gulpif(argv.min, uglify()))
.pipe(gulp.dest('./dist/js'));
});
//将两个任务串联起来
gulp.task('build-all-js', sequence('build-js', 'concat-js'));
- 先使用
gulp-concat
插件将babelHelpers.js和项目js文件进行连接合并。 - 然后使用
gulp-if
插件判断当前执行命令是否输入了--min
参数,如果是则使用gulp-uglify
插件进行js代码压缩。 - 定义build-all-js任务来将build-js和concat-js任务串联起来,但是需要使用
gulp-sequence
插件才能保证这两个任务是按顺序执行的。 - 最后,在/dist/js目录下会生成最终的项目js文件。
执行单元测试
本例中使用jasmine
进行单元测试。代码比较简单,执行所有test目录内以"Spec"结尾的文件:
var jasmine = require('gulp-jasmine');
gulp.task("test", function () {
return gulp.src(["./test/**/**Spec.js"])
.pipe(jasmine());
});
- 执行命令:
gulp test
即可在命令行中查看测试结果。
执行js代码检验
本例中使用eslint
进行js代码检验,需引入gulp-eslint
插件:
var eslint = require('gulp-eslint');
gulp.task('eslint', function () {
return gulp.src(['./src/**/*.js']) //获取src目录内全部js文件
.pipe(eslint({ //此处eslint的各配置项格式与.eslintrc文件相同
"rules": {
"camelcase": [2, { "properties": "always" }],
"comma-dangle": [2, "never"],
"semi": [2, "always"],
"quotes": [2, "single"],
"strict": [2, "global"]
},
"parser": "babel-eslint"
}))
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
- 执行命令:
gulp eslint
即可在命令行中查看js代码检测结果。
- 另外如果是在es6环境下使用
gulp-eslint
,那么还需要安装babel-eslint
这个包。此处有个小坑,就是babel-eslint
包是依赖estraverse
和estraverse-fb
包的,但这两个包其实却需要单独安装。
生成css及字体文件
例中的css及字体文件也需要合并构建,这里只简单介绍一下构建css的流程:
var less = require('gulp-less'),
cssnano = require('gulp-cssnano'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer');
function getCssLibName() {
var libName = 'flarej.css';
if (argv.min) {
libName = 'flarej.min.css';
}
return libName;
}
//构建项目css文件
gulp.task('build-css', function () {
return gulp.src('./src/styles/base.less')
.pipe(less()) //转换less
.pipe(rename(getCssLibName())) //重命名转换后的css文件
.pipe(gulp.dest('./dist/css'));
});
//将normalize.css与项目css进行合并
gulp.task('concat-css', function () {
var cssLibName = getCssLibName();
return gulp.src(['./vendor/normalize.css', './dist/css/' + cssLibName])
.pipe(concat(cssLibName)) //连接合并
.pipe(gulpif(argv.min, cssnano())) //执行css压缩
.pipe(postcss([autoprefixer({ browsers: ['last 50 versions'] })])) //自动补厂商前缀
.pipe(gulp.dest('./dist/css'));
});
//将两个任务串联起来
gulp.task('build-all-css', sequence('build-css', 'concat-css'));
构建全部代码
本例中的gulp
默认任务即为构建全部代码,输入命令:
gulp #可加"--min"参数构建压缩版
即可执行,具体构建流程如下:
更多细节大家可以查看本文示例的源代码。
(完)
基于Gulp + Browserify构建es6环境下的自动化前端项目的更多相关文章
- gulp+Babel 搭建ES6环境
Gulp是什么? Gulp是一个工作流的构建系统,开发者可以使用它在网站开发过程中自动执行常见任务.Gulp是基于Node.js构建的,因此Gulp源文件和你用来定义任务的Gulp文件都被写进了Jav ...
- 【简书】在阿里云自带的CentOS + LAMP环境下部署一个Laravel项目
在阿里云自带的CentOS + LAMP环境下部署一个Laravel项目 作者 DonnieZero 关注 2017.07.29 22:02* 字数 2218 阅读 5556评论 3喜欢 1赞赏 1 ...
- ES6 初体验 —— gulp+Babel 搭建ES6环境
ES6已经火了好久了,我却一直没有在项目中尝试过使用ES6写代码,只是写过几个Demo,在大型项目中使用ES6这件事,我一直不太敢做.最近公司要求做一个小的H5活动专题,我想不如就在这个小项目中使用E ...
- 如何在ES5与ES6环境下处理函数默认参数
函数默认值是一个很提高鲁棒性的东西(就是让程序更健壮)MDN关于函数默认参数的描述:函数默认参数允许在没有值或undefined被传入时使用默认形参. ES5 使用逻辑或||来实现 众所周知,在ES5 ...
- Linux16.04 LTS 环境下将cmake的项目转换成eclipse可导入可调试的工程项目
Linux作为一个开源系统,其中的一个优势就是有效的将各种源码编译得到的库集合在一起,为项目的使用创建了便捷.通常情况下,我们在开发自己的开源项目时,喜欢使用cmake调用各种三方库,如opencv ...
- Windows 环境下vue+webpack前端开发环境搭建
一.开发环境搭建 1.前端框架一般依赖node.js,我们首先要安装node.js. 2.由于许多npm 的源都在国外的地址,安装起来特别慢,所以我们这里利用淘宝的镜像服务器. 安装命令为:npm i ...
- 基于centos7的真实机环境下安装 vmware workstastion
通常我们在在虚拟机里面搭建大数据集群,如果我们换在真实机里面搭建大数据集群的话, 我们的每一台电脑就是centos系统了,这个时候如果我们需要按vmware 软件的话我们就需要下载不同的版本了 废话不 ...
- 用k8s构建生产环境下应用服务
1.生成镜像 见https://www.cnblogs.com/mushou/p/9713741.html,把测试成熟的应用添加到tomcat镜像生成新的镜像,用ansible部署到集群的几点服务器中 ...
- Linux 环境下用Tomcat 发布项目
1.前提条件: a.安装远程连接Linux软件:F-Secure SSH File Transfer Trial[简写为:FSSH]: b.打开FSSH,远程连接Linux[单击“Quick Conn ...
随机推荐
- Python 解LeetCode:671. Second Minimum Node In a Binary Tree
题目在这里,要求一个二叉树的倒数第二个小的值.二叉树的特点是父节点的值会小于子节点的值,父节点要么没有子节点,要不左右孩子节点都有. 分析一下,根据定义,跟节点的值肯定是二叉树中最小的值,剩下的只需要 ...
- PLSQL锁表之后改如何操作
(1)查看哪个表被锁select b.owner,b.object_name,a.session_id,a.locked_mode from v$locked_object a,dba_objects ...
- 一:Tomcat 服务器 在45秒内未启动成功
myeclipse或者eclipse中 tomcat 启动超时怎么办? 修改文件 找到Eclipse的工作空间\.metadata\.plugins\org.eclipse.wst.s ...
- C#编写的艺术字类方法
代码如下: using System;using System.Collections.Generic;using System.ComponentModel;using System.Drawing ...
- C语言实现快速排序法(分治法)
title: 快速排序法(quick sort) tags: 分治法(divide and conquer method) grammar_cjkRuby: true --- 算法原理 分治法的基本思 ...
- python logging模块+ 个人总结
原文地址:http://www.cnblogs.com/sislcb/archive/2008/11/25/1340627.html 从Python2.3版本中开始引入的logging模块为应用提供了 ...
- javascript第八章--事件
① 事件流 ② 事件处理程序 ③ 事件对象 ④ 事件类型 ⑤ 内存和性能 ⑥ 模拟事件
- nginx-http-concat资源文件合并模块
网页中引入多个CSS和JS的时候,浏览器会发出很多(css个数+js个数)次网络请求,甚至有的网页中有数十个以上的CSS或JS文件,用户体验特别不好,正好可以利用nginx-http-concat n ...
- 微信JS-SDK 选取手机照片并进行上传
项目中遇到需要选取照片上传的需求,因为网页运行在微信的浏览器里面,所以用微信的 js-sdk 提供的选取照片功能,来进行项目开发.实际开发中需要用到微信web开发者工具,详细参考链接:https:// ...
- nginx使用ssl模块配置支持HTTPS访问【解决ssl错误】
默认情况下ssl模块并未被安装,如果要使用该模块则需要在编译nginx时指定–with-http_ssl_module参数. 需求:做一个网站域名为 www.localhost.cn 要求通过http ...