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

徐小夕 等级 291 0 0

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

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

前言

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

9012教你如何使用gulp4开发项目脚手架 同时为了提高开发环境的效率,这里我们参考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目录,即我们开发项目时的源目录,具体结构如下:

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

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

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

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

3. gulpfile文件配置

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

9012教你如何使用gulp4开发项目脚手架 我们将配置文件统一放到build目录下,config为公共配置文件,gulp.dev.js和gulp.prod.js分别为开发和生产环境配置文件。我们整体的目录结构如下:

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

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

  1. config.js

    module.exports = {
     dist: './dist/static',  // 配置构建目录
    }
  2. 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 glob return await gulp.src(dist, {allowEmpty: true}).pipe(Clean()); }

// 服务器函数 async function server() { Connect.server({ root:dist, //根目录 // ip:'192.168.11.62',//默认localhost:8080 livereload: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 }


3. gulp.prod.js
``` 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 glob
    return 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')); }


5. package.json
``` js
{
  "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搭建个脚手架的思路,希望能有所收获。

更多推荐

欢迎关注趣谈前端,获取更多前端知识精粹学习社群

收藏
评论区

相关推荐

9012教你如何使用gulp4开发项目脚手架
本文将会介绍如何使用gulp4来搭建项目脚手架,如果您还在使用gulp3或更老的版本,您也以通过本文的一些思想将之前的项目进行完善,更新。如果gulp不是你们团队
《前端实战总结》之使用解释器模式实现获取元素Xpath路径的算法
前端领域里基于javascript的设计模式和算法有很多,在很多复杂应用中也扮演着很重要的角色,接下来就介绍一下javascript设计模式中的解释器模式,并用它来实现一个获取元素Xpath路径的算法。 上期回顾 《前端实战总结》之迭代器模式的N1种应用场景(https://juejin.im/post/6844904008616771591)
JavaScript设计模式之英雄联盟
作者:黄梵高 原文: https://juejin.cn/post/6844904165982879758 构造函数模式 简介 在Jav
问题 first path segment in URL cannot contain colon 的解决方案
目录问题解决 问题使用Golang开发流媒体服务器处理Post请求时,遇到了这个报错信息:2020/12/14 07:21:01 callback post failed2020/12/14 07:21:01 error::8080/api/callback: first path segment in URL cannot contain col
ES6环境搭建及react-router学习
一、起因 ES6新纳入了很多振奋人心的新特性,真的很让人忍不住去尝试一下。不过,由于现在大部分的浏览器对ES6的支持程度都不是很好。所以如果想要放心地使用一些新特性,还需要用一些工具,将ES6或者ES7的代码转为ES5的代码。今天,就配置了一下环境
Webpack 5.0 初体验
<p style"textalign: center;"<img class"rich_pages" dataratio"0.66640625" datas"300,640" src"https://usergoldcdn.xitu.io/2020/4/12/1716ebf44174dac8?w1080&h720&fjpeg&s
Webpack 打包资源篇
<section datatools"新媒体排版" dataid"13439" datastyletype"9" style"visibility: visible;"<p style"maxwidth: 100%; visibility: visible;"<br mpafromtpl"t" style"visibility
开发 vue3 + ts + vite / webpack 的管理系统
cooladmin 地址 演示 账户:admin 密码:123456 介绍 由来cooladmin自 2018 年初以来,一直本着快速通用开发为理念,同时看重每个页面的设计,无论在代码上还是 UI 设计上都受到广大开发者的喜爱。cool是酷的意思,admin一般的认知是
Android如何解析json字符串
前言上一篇文章介绍了服务器用Golang如何解析json字符串,今天我们来看看Android客户端是如何解析json字符串的。 正文Golang如何解析post请求中的json字符串(https://www.helloworld.net/p/O917HGeiALU2D)使用java语句如何正确解析json字符串呢?举一个例子,假如我们想从rtc_i
Webpack学习整理集锦【从最基础的demo入手,自己实现一个脚手架 】
前言本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。开源网址https://github.com/maomi
webpack 基本配置
概念本 质上,webpack是一个现代 JavaScript 应用程序的 静态模块打包器(module bundler) 。当 webpack处理应用程序时,它会递归地构建一个 依 赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle 。 安装确保安装了nodejs 项目文件环境cd
https://cloud.tencent.com/developer/article/write/1830331
一、目标今天的目标是这个sign和appcode 二、步骤 Jadx没法上了app加了某梆的企业版,Jadx表示无能为力了。 FRIDADEXDumpDexDump出来,木有找到有效的信息。 Wallbreaker葫芦娃的Wallbreaker可以做些带壳分析,不过这个样本,用Frida的Spawn模式可以载入,Attach模式会失败。而直接用Objecti
Next.js 11 的 一些新特性
作者: ✏️在6 月 15 日举行的上,来自世界各地的开发者,共同见证了 Vercel 团队最新版本的发布。Next.js 11 中包含的更新和新功能对已经流行的库进行了重大改进。在本文中,我们将深入研究其中一些对用户和开发人员体验都产生影响的更新。让我们开始吧!一致性就其核心而言,一致性是一组原则或编码指南,它将一些决策责任从开发人员手中夺走。通过设置默认
vscode+vue简单安装教程
1、安装vscode、node.js。2、打开vscode终端,全局安装vuecli:npm install g vuecli用于构建项目。3、继续安装webpack(打包工具):npm install g webpack。4、安装完成创建一个文件夹用于存放项目,比如myvue,cd到该文件夹,使用项目创建命令:vue init webpack myvue。
Vue 从安装到创建项目
1.安装Node可以直接在官网中下载安装默认自动安装Node和NPM(Node Package Manager) 完成后检查安装版本:node v npm v2.安装webpack webpack全局安装npm install webpack g3.安装vue脚手架 全局安装脚手架3npm install @vue/cli g 备注