9012教你如何使用gulp4开发项目脚手架

本文将会介绍如何使用gulp4来搭建项目脚手架,如果您还在使用gulp3或更老的版本,您也以通过本文的一些思想将之前的项目进行完善,更新。如果gulp不是你们团队的重点,也可以移步我的另一篇文章:

用 webpack 4.0 撸单页/多页脚手架 (jquery, react, vue, typescript)

前言

由于本文重点是介绍gulp4.0搭建脚手架的思路,相关插件的用法以及项目结构的设计,由于gulp的基本用法很简单,如果不熟悉可以移步官网自行研究学习。该脚手架的设计思路和功能如下:

同时为了提高开发环境的效率,这里我们参考webpack的配置,区分开发环境和生产环境,在接下来将会具体介绍。

脚手架用到的第三方插件介绍

  • gulp-jshint ——js语法检测
  • gulp-util ——终端控制台打印自定义错误信息
  • http-proxy-middleware ——设置代理,配合gulp-connect使用
  • gulp-less ——将less编译成css
  • gulp-file-include ——用于文件模块化导入,如用include的方式导入公共部分
  • gulp-connect ——用于启动本地服务器
  • gulp-clean ——清理目录
  • gulp-uglify --压缩js
  • gulp-minify-css ——压缩css
  • gulp-autoprefixer ——自动添加浏览器前缀
  • imagemin-pngquant ——png图片压缩
  • gulp-imagemin ——图压缩
  • gulp-cache ——设置gulp打包的缓存,一般用于img
  • gulp-md5-plus ——将文件名进行md5处理便于打包更新

当然gulp还有很多常用的插件可以更好的为我们的项目服务,大家也可以整合自己的插件让项目更加完善。

项目目录设计

1.src目录,即我们开发项目时的源目录,具体结构如下:

我们定义views是我们视图层,即页面文件的目录,js目录为业务逻辑的脚本文件,lib存放第三方框架,include目录为公共部分的存放目录,我们可以用gulp-file-include来导入到html中,images和css大家都比较清楚,分别时存放image和css文件的目录。

2. dist目录,即输出的目录,具体结构如下:

可以看到我们会看到src打包后的目录对应static目录,为什么我们会加一层static呢?我的设计是如果项目使用node等服务层框架,我们可以用gulp一并打包放入dist下,这样dist就是一个完整的包括前后端服务的项目目录了,当然大家也可以直接将src打包后的文件和文件夹直接放到dist下,根具业务需求灵活设计吧。

在这里我要说一点,由于笔者亲测gulp-md5-plus有时候打包不稳定,可能不会给html自动添加对应的md5后缀,所以笔者在这块做了特殊的处理,如果大家在工作中有更好的方案,可以及时和笔者沟通交流。

3. gulpfile文件配置

由于我们要区分开发环境和生产环境,所以这里我们使用两个不同的配置文件,根据NODE_ENV来区分用哪个文件。

我们将配置文件统一放到build目录下,config为公共配置文件,gulp.dev.js和gulp.prod.js分别为开发和生产环境配置文件。我们整体的目录结构如下:

脚手架完整源码(部分插件和配置会给出详细注释)

  1. config.js
module.exports = {dist: './dist/static',  // 配置构建目录
}
复制代码
  1. gulp.dev.js
const gulp = require('gulp');
// js
const Jshint = require("gulp-jshint");          //js检查
const Gutil = require('gulp-util');
const Proxy = require('http-proxy-middleware');
// const Webpack = require('webpack');
// const WebpackConfig = require('./webpack.config.js');// css
const Less = require('gulp-less');              // 编译less// html
const FileInclude = require('gulp-file-include'); // 文件模块化// server
const Connect = require('gulp-connect');        //引入gulp-connect模块 const Clean = require('gulp-clean');            // 清理目录// 配置文件
const config = require('./config');
const { dist } = config;// html
async function html() {return gulp.src('src/views/*.html').pipe(FileInclude({ // HTML模板替换,具体用法见下文prefix: '##',basepath: '@file'})).on('error', function(err) {console.error('Task:copy-html,', err.message);this.end();}).pipe(gulp.dest(dist)) // 拷贝 .pipe(Connect.reload())
}// css
async function css() {return await gulp.src('src/css/*.less').pipe(Less())       //编译less.pipe(gulp.dest(dist + '/css')) //当前对应css文件.pipe(Connect.reload());//更新
}// js
// const compilerJS = Webpack(WebpackConfig);async function js() {return await gulp.src('src/js/**').pipe(Jshint())//检查代码// .pipe(Babel({//     presets: ['es2015']// })).on('error', function(err) {Gutil.log(Gutil.colors.red('[Error]'), err.toString());}).pipe(gulp.dest(dist + '/js')) // 拷贝.pipe(Connect.reload()); //更新// 使用es6+可以单独配置// compilerJS.run(function(err, stats) {//     if(err) throw new Gutil.PluginError("webpack:js", err);//     Gutil.log("[webpack]", stats.toString({//         colors: true//     }));//     cb()// });
}// image
async function image() {return await gulp.src('src/images/*').pipe(gulp.dest(dist + '/images'));
}// clean dir
async function clean() {// 不设置allowEmpty: true会报File not found with singular globreturn await gulp.src(dist, {allowEmpty: true}).pipe(Clean());
}// 服务器函数
async function server() {Connect.server({root:dist, //根目录// ip:'192.168.11.62',//默认localhost:8080livereload:true, //自动更新port:9909, //端口middleware: function(connect, opt) {return [Proxy('/api', {target: 'http://localhost:8080',changeOrigin:true}),Proxy('/otherServer', {target: 'http://IP:Port',changeOrigin:true})]}})
}module.exports = {html,css,js,image,clean,server
}
复制代码
  1. gulp.prod.js
const gulp = require('gulp');
// const Rename = require('gulp-rename');          // 重命名
// js
const Uglify = require('gulp-uglify');          // 压缩js
// const Babel = require('gulp-babel');
// css
const Minifycss = require('gulp-minify-css');   // 压缩css
const Less = require('gulp-less');              // 编译less
const Autoprefixer = require('gulp-autoprefixer');  // 浏览器前缀
// html
const MinifyHtml = require("gulp-minify-html"); //压缩html
const FileInclude = require('gulp-file-include'); // 文件模块化
// image
const Imagemin = require('gulp-imagemin');
const Pngquant = require('imagemin-pngquant');  //png图片压缩插件
const Cache = require('gulp-cache'); const Clean = require('gulp-clean');            // 清理目录// md5 发版本的时候为了避免浏览器读取了旧的缓存文件,需要为其添加md5戳
const md5 = require("gulp-md5-plus");const config = require('./config');
const { dist } = config;
// html
async function html() {return gulp.src('src/views/*.html').pipe(FileInclude({ // HTML模板替换,具体用法见下文prefix: '##',basepath: '@file'}))// .pipe(MinifyHtml()).on('error', function(err) {console.error('Task:copy-html,', err.message);this.end();}).pipe(gulp.dest(dist)) // 拷贝 
}// css
async function css() {return await gulp.src('src/css/**').pipe(Less())       //编译less.pipe(Autoprefixer({cascade: true, //是否美化属性值 默认:true 像这样://-webkit-transform: rotate(45deg);//        transform: rotate(45deg);remove: true //是否去掉不必要的前缀 默认:true})).pipe(Minifycss({   // 压缩css//类型:Boolean 默认:true [是否开启高级优化(合并选择器等)]advanced: true,//保留ie7及以下兼容写法 类型:String 默认:''or'*' [启用兼容模式; 'ie7':IE7兼容模式,'ie8':IE8兼容模式,'*':IE9+兼容模式]compatibility: '',//类型:Boolean 默认:false [是否保留换行]keepBreaks: false,//保留所有特殊前缀 当你用autoprefixer生成的浏览器前缀,如果不加这个参数,有可能将会删除你的部分前缀        keepSpecialComments: '*'})).pipe(gulp.dest(dist + '/css')).pipe(md5(10, dist + '/*.html', {mappingFile: 'manifest.json',connector: '.' // 文件名和hash的连接符})).pipe(gulp.dest(dist + '/css')) //当前对应css文件
}// js
async function js() {return await gulp.src('src/js/**')// .pipe(Babel({//     presets: ['es2015']// })).pipe(Uglify()) // 压缩js.pipe(gulp.dest(dist + '/js')).pipe(md5(10, dist + '/*.html', {mappingFile: 'manifest.json',connector: '.'})).pipe(gulp.dest(dist + '/js')) // 拷贝
}// image
async function image() {return await gulp.src('src/images/*').pipe(Cache(Imagemin({optimizationLevel: 5, //类型:Number  默认:3  取值范围:0-7(优化等级)progressive: true, //类型:Boolean 默认:false 无损压缩jpg图片interlaced: true, //类型:Boolean 默认:false 隔行扫描gif进行渲染multipass: true, //类型:Boolean 默认:false 多次优化svg直到完全优化svgoPlugins: [{removeViewBox: false}],//不要移除svg的viewbox属性use: [Pngquant()] //使用pngquant深度压缩png图片的imagemin插件}))).pipe(gulp.dest(dist + '/images'));
}// clean dir
async function clean() {// 不设置allowEmpty: true会报File not found with singular globreturn await gulp.src(dist, {allowEmpty: true}).pipe(Clean());
}module.exports = {html,css,js,image,clean
}
复制代码
  1. gulpfile.js
const gulp = require('gulp');// 根据环境引入不同的配置文件
let buildConfig;
if(process.env.NODE_ENV === 'dev') {buildConfig = require('./build/gulp.dev');gulp.task('server', buildConfig.server);  // 本地服务} else {buildConfig = require('./build/gulp.prod');// gulp.task('md5', gulp.series(buildConfig.md5Css, buildConfig.md5Js));gulp.task('clean', buildConfig.clean);    // 清理目录   
}gulp.task('html', buildConfig.html);      // 打包html
gulp.task('js', buildConfig.js);          // 打包js
gulp.task('css', buildConfig.css);        // 打包css
gulp.task('images', buildConfig.image);   // 打包image
gulp.task('sources', gulp.series('html', gulp.parallel('js', 'css', 'images')));// 监听文件变化
gulp.task('watch', async () => {gulp.watch('src/views/*', gulp.series('html')); // 监听HTML变化gulp.watch('src/js/**', gulp.series('js')); // 监听js变化gulp.watch('src/css/*', gulp.series('css')); // 监听css变化gulp.watch('src/images/*', gulp.series('images')); // 监听image变化
});// build
if(process.env.NODE_ENV === 'dev') {gulp.task('dev', gulp.series('sources', 'server', 'watch'));
} else {gulp.task('build', gulp.series('sources'));
}复制代码
  1. package.json
{"dependencies": {"@babel/core": "^7.4.5","babel-preset-es2015": "^6.24.1","gulp": "^4.0.2","gulp-autoprefixer": "^6.1.0","gulp-babel": "^8.0.0","gulp-cache": "^1.1.2","gulp-clean": "^0.4.0","gulp-connect": "^5.7.0","gulp-file-include": "^2.0.1","gulp-imagemin": "^6.0.0","gulp-jshint": "^2.1.0","gulp-less": "^4.0.1","gulp-md5-plus": "^1.0.3","gulp-minify-css": "^1.2.4","gulp-minify-html": "^1.0.6","gulp-rename": "^1.4.0","gulp-uglify": "^3.0.2","gulp-util": "^3.0.8","http-proxy-middleware": "^0.19.1","http-server": "^0.11.1","imagemin-pngquant": "^8.0.0","jshint": "^2.10.2","jsonfile": "^5.0.0","webpack": "^4.35.2"},"scripts": {"start": "NODE_ENV=dev gulp dev","build": "NODE_ENV=prod gulp clean && gulp build","serve": "http-server dist/static -p 3000"},"devDependencies": {}
}复制代码

要想获取项目完整源码和demo,请移步gulp4_multi_pages。

最后

该脚手架任然有需要完善的地方,比如如何兼容uglify和babel,md5需要使用两次的情况,如果更好的解决方案,欢迎随时交流。在脚手架选型上,也不一定非要用gulp,webpack,一般的经验是传统型的静态网站适合用gulp,由于不需要编译es6,所以有更小的体积,当然也可以用webpack,本文主要是给大家提供一使用gulp4搭建个脚手架的思路,希望能有所收获。

更多推荐

  • 如何用不到200行代码写一款属于自己的js类库)
  • 让你瞬间提高工作效率的常用js函数汇总(持续更新)
  • 一张图教你快速玩转vue-cli3
  • 3分钟教你用原生js实现具有进度监听的文件上传预览组件
  • 3分钟教你用原生js实现具有进度监听的文件上传预览组件
  • 使用Angular8和百度地图api开发《旅游清单》
  • js基本搜索算法实现与170万条数据下的性能测试
  • 《前端算法系列》如何让前端代码速度提高60倍
  • 《前端算法系列》数组去重
  • vue高级进阶系列——用typescript玩转vue和vuex
  • 前端三年,谈谈最值得读的5本书籍

欢迎关注下方公众号,获取更多前端知识精粹学习社群

在公众号点击进群,可以加入vue学习小组,一起学习前端技术;

回复学习路径,将获取笔者多年从业经验的前端学习路径的思维导图

转载于:https://juejin.im/post/5d2180e5e51d4577614761b7

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nodejs模块

nodejs模块遵循commonJS规范,但并不是完全实现规范,主要使用require引入模块、使用exports导出模块。 导出属性或方法 使用exports mouduleA.js: var say function(world){console.info("say: "world); }var sing function(wo…

Array.prototype.slice.call(arguments)

Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组,除了IE下的节点集合(因为ie下的dom对象是以com对象的形式实现的,js对象与com对象不能进行转换)如:1 var a{length:2,0:first,1:second}; 2 Ar…

动态内存分配导致内存泄漏之处

摘要:举了几个动态内存分配过程中,发生内存泄漏的例子 1. 分配了内存,却没有及时删除,导致泄漏 1: void doSomething() 2: { 3: int *pnValue new int; 4: } 2. 为指针变量分配了一个内存,然后又让指针变量指向其他的值,导致…

nodejs常用模块-url

URL nodejs中针对url的常用方法。 node下打印url,结果: 引入url模块 var url require(url) 1、parse方法 将url解析成对象,parse方法原型: url.parse(urlStr[, parseQueryString][, slashesDenoteHost]) 可传递三个参数…

常用的javascript设计模式

请坚持 什么是设计模式 百度百科: 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式…

express项目创建

1、安装项目生成器 cnpm i express-generator -g express4.0以后,express与express-generator包分离,全局使用express命令生成项目骨架时应该安装express-generator包。 2、生成项目骨架 express server 默认使用的是jade模板,使用ejs模…

设置Jexus开机启动

把jexus做成系统服务,就像windows服务一样,可以设置开机启动就可以了。 第一、进入目录 /lib/systemd/system/ 第二、新建文件 vi jexus.service 文件内容 [Unit] Descriptionjexus Afternetwork.target[Service] Typeforking ExecStart/usr/jexus/jw…

iOS警告-This block declaration is not a prototype

关于警告 我们定义一个不带参数的block,通常是如下的方式 1typedefvoid (^UpdateSwichBtnBlock)();在xcode9中会提示一个警告 12This block declaration is not a prototypeInsert ‘void解决方式可以是如下的几种 1typedefvoid (^UpdateSwichBtnBlock)(void);但是这样,很多第三…

mac环境mongodb安装与配置

一、安装 MAC环境安装mongodb有两种方式,一种方式是通过下载安装包,另一种方式是通过homebrew。 1、安装包方式 从mongodb官网可以下载MAC安装包:https://www.mongodb.com/download-center#community 或者使用curl下载 # 进入 /usr/loca…

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型...

以下为借鉴 var stack1 [], stack2[]; function push(node){stack1.push(node);}function pop(){if(stack2.length){return stack2.pop();}else{if(stack1.length){var len stack1.length;for(var i0;i<len;i){stack2.push(stack1.pop());}return stack2.pop()}else{retur…

使用CocoaPods导入百度地图SDK所遇到的坑

执行pod install遇到的问题:解决方安:百度了下,发现pod install命令被墙了,换成pod install --verbose --no-repo-update

NSTimer不准确与GCDTimer详解

NSTimer不准&#xff0c;scheduleTimer放在runloop里面&#xff0c;受runloop模式影响会不准// [NSTimer scheduledTimerWithTimeInterval:<#(NSTimeInterval)#> target:<#(nonnull id)#> selector:<#(nonnull SEL)#> userInfo:<#(nullable id)#> r…

flex的12个属性

容器&#xff08;父元素&#xff09;的属性&#xff1a; flex-direction属性决定主轴的方向 flex-wrap 属性决定项目在一行排不下的情况下是否换行 flex-flow flex-flow属性是flex-direction属性和flex-wrap属性的简写形式&#xff0c;默认值为row nowrap。 jstify-content …

vue图片懒加载插件vue-lazyload

插件地址&#xff1a;https://github.com/hilongjw/vue-lazyload demo&#xff1a;http://hilongjw.github.io/vue-lazyload/ 1、安装 cnpm i vue-lazyload -S 2、使用 main.js import VueLazyLoad from vue-lazyloadVue.use(VueLazyLoad, {error:/static/error.png,loadin…

IT需求过程管理

IT部门就是为其他业务、内勤部门提供信息化手段的&#xff0c;所以在实施信息化系统的时候首先要做的就是需求调研&#xff0c;但是针对于绝大多数业务部门的人员而言&#xff0c;信息系统是很不熟悉的&#xff0c;我们会经常听到这样的回复“这个应该很快就可以实现吧”、“当…

maskView与CAGradientLayer详解

#maskView基本原理 - png图片透明像素的原理 - maskView可类比于多张png图片的叠加遮罩&#xff0c;原理类似 - maskView是iOS8以上才有的&#xff0c;如果要考虑兼容低版本&#xff0c;用maskLayer替代 //使用maskView的情况 property (nonatomic, strong)UIImageView *addIma…

nodejs的启动方式

1、原始node命令 直接命令行中使用node命令 node xxx.js 或者安装nodemon&#xff0c;使用nodemon启动方便在开发阶段热部署代码改动 npm i nodemon -G nodemon xxx.js 2、webstorm方式 webstorm中&#xff0c;需要执行的文件的上&#xff0c;右键->run&#xff0c;右…

win7rc 序列号- 10/21之前

安装介绍&#xff1a;http://www.microsoft.com/china/windows/windows-7/download.aspx 注册获得序列号&#xff1a;http://technet.microsoft.com/zh-cn/evalcenter/dd353205.aspx?ITPIDmscomsc在 2009 年 10 月 21 日之前&#xff0c;您仍可以通过注册来获取产品密钥或查找…

maskView与CAGradientLayer那回事儿

maskView基本原理 png图片透明像素的原理maskView可类比于多张png图片的叠加遮罩&#xff0c;原理类似maskView是iOS8以上才有的&#xff0c;如果要考虑兼容低版本&#xff0c;用maskLayer替代 //使用maskView的情况 property (nonatomic, strong)UIImageView *addImageView;…

mongoose操作mongodb

http://mongoosejs.com/docs/api.html#index-js mongoose是nodejs环境下操作mongodb的模块封装&#xff0c;使用mongoose之后&#xff0c;实际上只需要在mongodb中创建好数据库与用户&#xff0c;集合的定义、创建、操作等直接使用mongoose即可。 一、连接二、重要概念三、基本…