gulp 基础入门
gulp 是基于 nodejs 的用自动化构建工具,可以通过 gulp 和各种插件实现前端的开发自动化工作流程。
gulp 4.0 已经发布,当前文章是 gulp@3.9.1 的版本的代码。
快速入门
第一步: 全局安装 gulp:
# 安装 gulp 的控制台辅助工具。
$ npm install --global gulp-cli
$ npm install --global gulp@3.9.1
第二步: 作为项目的开发依赖(devDependencies)安装
# 由于 gulp4.0.0 发布后不兼容之前的 api,所以本文以下所有的代码实例都是以 3.9.1 版本编写,请注意!
$ npm install --save-dev gulp@3.9.1
由于 gulp 4.0.0 发布后不兼容之前的 api,所以本文以下所有的代码实例都是以 3.9.1 版本编写,请注意!
第三步:
在项目根目录下创建一个名为 gulpfile.js 的文件:
var gulp = require('gulp');
gulp.task('default', function() {
// 将你的默认的任务代码放在这
});
第四步: 运行 gulp:
$ gulp
默认的名为 default 的任务(task)将会被运行,在这里,这个任务并未做任何事情。 想要单独执行特定的任务(task),请输入 gulp 。
gulp API 文档
gulp 一共就 4 个 api, src
、 dest
、 task
、 watch
。
具体细节请参考 官方文档
适合初学者的 gulp+requirejs 的项目模板
虽然, webpack
已经大行其道。作为初学者,gulp 依然是最快的入门学习前端工作流的工具。本项目本着为中小型团队打造一个基于:gulp+sass+requirejs+es6+eslint+arttemplate 的基本的项目模板。
项目模板 在线 github 地址
gulp 相关应用
- js(用 requirejs 管理模块)
- 压缩
- 转码
- 版本号
- 自动修改注入 requirejs 的 paths
- es6 转码
- eslint 检测
- 添加版本信息
- style
- sass
- 合并
- 压缩
- 加前缀
- 打版本
- sourcemap(开发)
- 图片压缩优化
- html
- 压缩
- 修改 url 地址
- 打包前清理
- 打包后拷贝目录
编辑器的一致性
- .editorconfig 文件控制编辑器的一致性
- eslint 校验一致性,并配置 vscode 自动修改符合 eslint 校验,可以安装 eslint 插件。
本地测试和代理配置
- 运行本地测试
$ npm run dev
本地启动服务器地址: http://localhost:8000
打包
$ npm run build
# 会把最终结果输出到 dist 目录
项目的目录结构
.
├── gulpfile.js
├── package.json
├── readme.md
├── src
│ ├── app.js
│ ├── asset
│ │ └── img
│ │ └── a.jpg
│ ├── controller
│ │ └── student
│ │ └── listController.js
│ ├── index.html
│ ├── js
│ │ ├── E.js
│ │ ├── index.js
│ │ ├── rev-manifest.json
│ │ └── tmpl
│ │ ├── header.js // 自动生成
│ │ ├── student.js // 自动生成
│ │ └── user.js
│ ├── lib
│ │ ├── arttemplate
│ │ │ ├── es5-sham.min.js
│ │ │ ├── es5-shim.min.js
│ │ │ ├── json3.min.js
│ │ │ └── template-web.js
│ │ └── require.js
│ ├── service
│ │ └── index.js // 所有的服务
│ ├── style
│ │ ├── a.css
│ │ ├── main.css
│ │ ├── rev-manifest.json
│ │ └── scss
│ │ ├── b.scss
│ │ └── index.scss
│ ├── template // art-template 模板
│ │ ├── header
│ │ │ └── header.html
│ │ ├── student
│ │ │ ├── stuList.html
│ │ │ ├── t.html
│ │ │ └── userList.html
│ │ └── user
│ │ └── footer.html
│ └── view
│ ├── about.html
│ └── student
│ └── list.html
└── yarn.lock
gulpfile 细节
'use strict';
const fs = require('fs');
const path = require('path');
// 引入 gulp 包, nodejs 代码
const gulp = require('gulp'),
// 引入 gulp-sass 包
sass = require('gulp-sass'),
// gulp 版本定义
rev = require('gulp-rev'),
concat = require('gulp-concat'), // 合并文件 --合并只是放一起--压缩才会真正合并相同样式
rename = require('gulp-rename'), // 设置压缩后的文件名
// 替换版本 url
revCollector = require('gulp-rev-collector'),
// css 压缩
cleanCss = require('gulp-clean-css'),
// 兼容处理 css3
autoprefixer = require('gulp-autoprefixer'),
// css 代码 map
sourcemaps = require('gulp-sourcemaps'),
// js 压缩
uglify = require('gulp-uglify'),
// img 压缩
imgagemin = require('gulp-imagemin'),
// 清理文件夹
clean = require('gulp-clean'),
// 顺序执行
runSequence = require('gulp-run-sequence'),
// 给 js 文件替换文件路径
configRevReplace = require('gulp-requirejs-rev-replace'),
// 过滤
filter = require('gulp-filter'),
// js 校验
eslint = require('gulp-eslint'),
// babel 转换 es6
babel = require('gulp-babel'),
// 本地的测试服务器
connect = require('gulp-connect'),
// 本地测试服务器中间件
proxy = require('http-proxy-middleware'),
// 服务器的代理插件
modRewrite = require('connect-modrewrite'),
// 打开浏览器
open = require('gulp-open'),
// html 压缩
htmlmin = require('gulp-htmlmin'),
replace = require('gulp-replace'),
// 自动编译 artTemplate 模板成 js 文件
tmodjs = require('gulp-tmod');
// minifyHtml = require('gulp-minify-html'); 样式处理工作流:编译 sass → 添加 css3 前缀 → 合并 →
// 压缩 css →添加版本号
gulp.task('style', function(e) {
// 过滤非 sass 文件
var sassFilter = filter(['**/*.scss'], { restore: true });
return gulp
.src(['./src/style/**/*.{scss,css}', '!./src/style/main.css']) // 读取 sass 文件
.pipe(sassFilter)
.pipe(sass()) // 编译 sass
.pipe(sassFilter.restore)
.pipe(
autoprefixer({
// 兼容 css3
browsers: ['last 2 versions'], // 浏览器版本
cascade: true, // 美化属性,默认 true
add: true, // 是否添加前缀,默认 true
remove: true, // 删除过时前缀,默认 true
flexbox: true // 为 flexbox 属性添加前缀,默认 true
})
)
.pipe(concat('main.css')) // 合并 css
.pipe(
cleanCss({
// 压缩 css
compatibility: 'ie8',
// 保留所有特殊前缀 当你用 autoprefixer 生成的浏览器前缀,如果不加这个参数,有可能将会删除你的部分前缀
keepSpecialComments: '*'
})
)
.pipe(rev()) // 文件名加 MD5 后缀
.pipe(gulp.dest('./dist/style/')) // 输出目标文件到 dist 目录
.pipe(rev.manifest()) // 生成一个 rev-manifest.json
.pipe(gulp.dest('./src/style/')); // 将 rev-manifest.json 保存到 src 目录
});
// 替换目标 html 文件中的 css 版本文件名,js 版本的文件名,html 压缩
gulp.task('html', function(e) {
return gulp
.src(['./src/**/*.json', './src/**/*.html', '!./src/template/**']) // - 读取 rev-manifest.json 文件以及需要进行 css 名替换的文件
.pipe(revCollector({ replaceReved: true })) // - 执行 html 文件内 css 文件名的替换和 js 文件名替换
.pipe(
htmlmin({
removeComments: true, // 清除 HTML 注释
collapseWhitespace: true, // 压缩 HTML
// collapseBooleanAttributes: true, //省略布尔属性的值 <input checked="true"/> ==> <input />
removeEmptyAttributes: true, // 删除所有空格作属性值 <input id="" /> ==> <input />
removeScriptTypeAttributes: true, // 删除<script>的 type="text/javascript"
removeStyleLinkTypeAttributes: true, // 删除<style>和<link>的 type="text/css"
minifyJS: true, // 压缩页面 JS
minifyCSS: true // 压缩页面 CSS
})
)
.pipe(gulp.dest('./dist/')); // - 替换后的文件输出的目录
});
// 图片压缩
gulp.task('imgmin', function(e) {
return gulp
.src('./src/asset/**/*.{png,jpg,gif,ico}')
.pipe(
imgagemin({
optimizationLevel: 5, // 类型:Number 默认:3 取值范围:0-7(优化等级)
progressive: true, // 类型:Boolean 默认:false 无损压缩 jpg 图片
interlaced: true,
// 类型:Boolean 默认:false 隔行扫描 gif 进行渲染
multipass: true // 类型:Boolean
// 默认:false 多次优化 svg 直到完全优化
})
)
.pipe(gulp.dest('./dist/asset'));
});
// js 压缩添加版本
gulp.task('js', function(e) {
return gulp
.src(['./src/**/*.js', '!./src/lib/**'])
.pipe(eslint())
.pipe(
eslint.results(results => {
// Called once for all ESLint results.
console.log(`JS 总校验文件: ${results.length}`);
console.log(`JS 警告个数:: ${results.warningCount}`);
console.log(`JS 错误个数: ${results.errorCount}`);
})
)
.pipe(eslint.format())
.pipe(eslint.failAfterError())
.pipe(babel({ presets: ['env'] }))
.pipe(uglify())
.pipe(rev())
.pipe(gulp.dest('./dist'))
.pipe(rev.manifest())
.pipe(gulp.dest('./src/js/'));
});
// 给 requirejs 引用的文件修改版本号的路径
gulp.task('revjs', function() {
return gulp
.src('./dist/*.js')
.pipe(
configRevReplace({
manifest: gulp.src('./src/js/rev-manifest.json')
})
)
.pipe(uglify())
.pipe(gulp.dest('dist/'));
});
// 打包要复制的路径 2
var copyPathArr = ['./src/lib/**/*', './src/asset/**/*', './src/*.ico'];
// 拷贝 gulp 文件
gulp.task('copy', function(e) {
return gulp.src(copyPathArr, { base: './src' }).pipe(gulp.dest('./dist/'));
});
// 清理 dist 目录下的历史文件
gulp.task('cleanDist', function() {
gulp
.src(['dist/style/**', 'dist/js/**', 'dist/*.js'], { read: false })
.pipe(clean());
});
gulp.task('dist', [], function() {
runSequence(
'cleanDist',
'tpl',
'style',
'js',
'revjs',
'html',
'copy',
'imgmin'
);
});
gulp.task('tpl', function() {
// 拿到所有的路径
let basePath = path.join(__dirname, 'src/template');
let files = fs.readdirSync(basePath);
files.forEach((val, index) => {
let dirPath = path.join(basePath, val);
let stat = fs.statSync(dirPath);
if (!stat.isDirectory()) {
return;
}
var fileter = 'src/template/' + val + '/**/*.html';
console.log(fileter);
gulp
.src('src/template/' + val + '/**/*.html')
.pipe(
tmodjs({
templateBase: 'src/template/' + val,
runtime: val + '.js',
compress: false
})
)
// 自动生成的模板文件,进行 babel 转换,会报错,此转换插件已经停更,所以间接改这个 bug
// 参考 bug: https://github.com/aui/tmodjs/issues/112 主要是 this → window
.pipe(replace('var String = this.String;', 'var String = window.String;'))
.pipe(gulp.dest('src/js/tmpl/'));
});
});
// ============= 开发样式处理
gulp.task('style:dev', function(e) {
var sassFilter = filter(['**/*.scss'], { restore: true });
return gulp
.src(['./src/style/**/*.{scss,css}', '!./src/style/main.css']) // 读取 sass 文件
.pipe(sourcemaps.init())
.pipe(sassFilter)
.pipe(sass()) // 编译 sass
.pipe(sassFilter.restore)
.pipe(concat('main.css'))
.pipe(sourcemaps.write())
.pipe(gulp.dest('./src/style/'));
});
// 开发监控 sass 文件变化编译 sass 到 css 文件 可以增加 es6 的编译,jslint
gulp.task('dev', ['open'], function() {
gulp.watch('src/style/**', ['style:dev']);
gulp.watch('src/template/**', ['tpl']);
});
// 配置测试服务器
gulp.task('devServer', function() {
connect.server({
root: ['./src'], // 网站根目录
port: 38900, // 端口
livereload: true,
middleware: function(connect, opt) {
return [
modRewrite([
// 设置代理
'^/api/(.*)$ http://192.168.0.102:8080/mockjsdata/1/api/ $1 [P]'
])
];
}
});
});
// 启动浏览器打开地址
gulp.task('open', ['devServer'], function() {
gulp.src(__filename).pipe(open({ uri: 'http://localhost:38900/index.html' }));
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: JS 的加密库简介
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论