别被题目吓到,哈哈,即便当初vite横空出世,社区光芒四射,两个字很快,然而webpack仍旧宝刀未老,仍然扛起前端工程化的大梁,然而明天我为啥说要拥抱gulp,因为咱们经经常吃一道菜,所以要换个口味,这样才养分平衡。

gulp定义是:用自动化构建工具加强你的工作流程,是一种基于工作文件流形式,你能够在前端写一些自动化脚本,或者降级历史传统我的项目,解放你反复打包,压缩,解压之类的操作。

集体了解gulp是一种命令式编程的体验,更重视构建过程,所有的工作须要你本人手动创立,你会对构建流程会十分分明,这点不像webpackwebpack就是一个开箱即用的申明式形式,webpack是一个模块化打包工具,外部细节暗藏十分之深,你也不需关注细节,你只须要照着提供的API以及引入对应的loaderplugin应用就行。

言归正传,为了饮食平衡,明天一起学习下gulpjs

注释开始...

搭建一个简略的前端利用

相比拟webpack,其实gulp的我的项目构造更偏差传统的利用,只是咱们借助gulp工具解放咱们的一些代码压缩es6编译打包以及在传统我的项目中都能够应用less体验。

gulp目录下新建01-simple-demo

根目录下生成默认package.json

npm init -y

而后在public目录下新建imagescssjsindex.html

文件构造,大略就这样

而后在装置gulp

npm i gulp --save-dev

在根目录下新建gulpfile.js
咱们先在gulpfile.js中写入一点内容,测试一下

const defaultTask = (cb) => {  console.log('hello gulp');  cb();};exports.default = defaultTask;

而后咱们在命令行执行

npx gulp

当咱们执行npx gulp时会默认运行gulpfile.js导出的default,在gulpfile.js导出的工作会注册到gulp工作中

gulp中工作次要分两种,一种是公开工作、另一种是公有工作

公开工作能够间接在命令执行npx gulp xxx调用执行,比方上面的defaultTask就是一个公开工作,只有被导出就是一个公开工作,没有被导出就是一个公有工作。

...exports.default = defaultTask;

私有工作taskJS

// gulpfile.jsconst { src, dest } = require('gulp');const pathDir = (dir) => {  return path.resolve(__dirname, dir);};// todo 执行ts工作,将js目录下的js打包到dist/js目录下const taskJS = () => {  return src(pathDir('public/**/*.js'), { sourcemaps: true }).pipe(dest(pathDir('dist/js')));};exports.taskJS = taskJS;

而后你在命令行执行

npx gulp taskJS



至此你会发现dist目录下就有生成的js

装置 less

npm i less gulp-less --save-dev

css/index.less中写入测试 css 的代码

@bgcolor: yellow;@defaultsize: 20px;body {  background-color: @bgcolor;}h1 {  font-size: @defaultsize;}

gulpfile.js中写入编译less的工作,须要gulp-less

const { src, dest } = require('gulp');const less = require('gulp-less');const pathDir = (dir) => {  return path.resolve(__dirname, dir);}...// todo less工作const taskLess = () => {  // css目录洗的所有.less文件,dest输入到dist/css目录下  return src(pathDir('public/css/*.less')).pipe(less()).pipe(dest(pathDir('dist/css')))}exports.taskLess = taskLess;

命令行运行npx gulp taskLess,后果如下

图片资源

应用一个gulp-image插件对图片进行无损压缩解决

// gulpfile.jsconst { src, dest } = require('gulp');const image = require('gulp-image');const path = require('path');const pathDir = (dir) => {  return path.resolve(__dirname, dir);}...// todo 图片资源const taskImage = () => {  return src(pathDir('public/images/*.*')).pipe(image()).pipe(dest(pathDir('dist/images')))}exports.taskImage = taskImage;

一顿操作发现,最新版本不反对esm,所以还是升高版本版本,这里升高到6.2.1版本

而后运行npx gulp taskImage

图片压缩得不小

在这之前,咱们别离定义了三个不同的工作,gulp导出的工作有
公开工作和公有工作,多个公开工作能够串行组合应用

组合工作 series 与 parallel

因而我能够将之前的介个工作组合在一起

// gulpfile.jsconst { src, dest, series } = require('gulp');const less = require('gulp-less');const image = require('gulp-image');const path = require('path');const pathDir = (dir) => {  return path.resolve(__dirname, dir);}// todo js工作const taskJS = () => {  return src(pathDir('public/**/*.js'), { sourcemaps: true }).pipe(dest(pathDir('dist/js')))}...// series组合多个工作const seriseTask = series(taskJS, taskLess, taskLess, taskImage)exports.seriseTask = seriseTask;

当我在命令行npx gulp seriseTask

曾经在dist生成对应的文件了

编译转换 es6

在咱们index.js,很多时候是写的es6,在gulp中咱们须要一些借助一些插件gulp-babel,另外咱们须要装置另外两个babel外围插件@babel/core,@babel/preset-env

 npm i gulp-babel @babel/core @babel/preset-env

gulpfile.js中咱们须要批改下

...const babel = require('gulp-babel');// todo js工作// 用babel转换es6语法糖const taskJS = () => {  return src(pathDir('public/**/*.js'), { sourcemaps: true }).pipe(babel({    presets: ['@babel/preset-env']  })).pipe(dest(pathDir('dist/js')))}

当咱们在js/index.js写入一段测试代码

js / index.js;const appDom = document.getElementById('app');appDom.innerHTML = 'hello gulp';const fn = () => {  console.log('公众号:Web技术学苑,好好学习,天天向上');};fn();

运行npx gulp seriseTask

箭头函数和const申明的变量就变成了es5

通常状况下,个别打包后的dist下的css或者js都会被压缩,在gulp中也是须要借助插件来实现

压缩 js 与 css

压缩js

...const teser = require('gulp-terser');// todo js工作const taskJS = () => {  return src(pathDir('public/**/*.js'), { sourcemaps: true }).pipe(babel({    presets: ['@babel/preset-env']  })).pipe(teser({    mangle: {      toplevel: true // 混同代码    }  })).pipe(dest(pathDir('dist/js')))}...

压缩css

...const uglifycss = require('gulp-uglifycss');// todo less工作const taskLess = () => {  return src(pathDir('public/css/*.less')).pipe(less()).pipe(uglifycss()).pipe(dest(pathDir('dist/css')))}...

在这之前咱们在输入dest时候咱们都执向了一个具体的文件目录,在src这个api中是创立流,从文件中读取vunyl对象,自身也提供了一个base属性,因而你能够像上面这样写

const { src, dest, series } = require('gulp');const less = require('gulp-less');const image = require('gulp-image');const babel = require('gulp-babel');const teser = require('gulp-terser');const uglifycss = require('gulp-uglifycss');const path = require('path');const pathDir = (dir) => {  return path.resolve(__dirname, dir);};// 设置base,当输入文件指标dist文件时,会主动拷贝以后文件夹到目标目录const basePath = {  base: './public'};// todo js工作const taskJS = () => {  return src(pathDir('public/**/*.js', basePath))    .pipe(      babel({        presets: ['@babel/preset-env']      })    )    .pipe(      teser({        mangle: {          toplevel: true // 混同代码        }      })    )    .pipe(dest(pathDir('dist')));};// todo less工作const taskLess = () => {  return src(pathDir('public/css/*.less'), basePath)    .pipe(less())    .pipe(uglifycss())    .pipe(dest(pathDir('dist')));};// todo 图片资源,有压缩,并输入到对应的dist/images文件夹下const taskImage = () => {  return src(pathDir('public/images/*.*'), basePath)    .pipe(image())    .pipe(dest(pathDir('dist')));};// todo htmlconst taskHtml = () => {  return src(pathDir('public/index.html'), basePath).pipe(dest(pathDir('dist')));};const defaultTask = (cb) => {  console.log('hello gulp');  cb();};// series组合多个工作const seriseTask = series(taskHtml, taskJS, taskLess, taskLess, taskImage);exports.default = defaultTask;exports.taskJS = taskJS;exports.taskLess = taskLess;exports.taskImage = taskImage;exports.seriseTask = seriseTask;

将资源注入 html 中

gulp中,工作之间的依赖关系须要咱们本人手动写一些执行工作流,当初一些打包后的dist的文件并不会主动注入html中。

参考gulp-inject

...const inject = require('gulp-inject');...// 将css,js插入html中const injectHtml = () => {  // 指标资源  const targetSources = src(['./dist/**/*.js', './dist/**/*.css'], { read: false });  // 指标html  const targetHtml = src('./dist/*.html')  // 把指标资源插入指标html中,同时输入到dist文件下  const result = targetHtml.pipe(inject(targetSources)).pipe(dest('dist'));  return result}// series串行组合多个工作const seriseTask = series(taskHtml, taskJS, taskLess, taskLess, taskImage, injectHtml)exports.seriseTask = seriseTask;

留神一个执行程序,必须是等后面工作执行完了,再注入,所以在series工作的最初才执行injectHtml操作

并且在public/index.html下,还须要退出一段正文

<!DOCTYPE html><html lang="en">  <head>    <meta charset="UTF-8" />    <meta http-equiv="X-UA-Compatible" content="IE=edge" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <title>gulp</title>    <!-- inject:css -->    <!-- endinject -->  </head>  <body>    <div id="app"></div>    <!-- inject:js -->    <!-- endinject -->  </body></html>

当咱们运行npx gulp seriseTask

创立本地服务

参考browser-sync

const { src, dest, series, watch } = require('gulp');const browserSync = require('browser-sync');...const taskBuild = seriseTask;// 本地服务const taskDevServer = () => {  // 监听public所有目录下,只有文件产生扭转,就从新加载  watch(pathDir('public'), taskBuild);  // 创立服务  const server = browserSync.create();  // 调用init开启端口拜访  server.init({    port: '8081', //设置端口    open: true,  // 主动关上浏览器    files: './dist/*', // dist文件    server: {      baseDir: './dist'    }  })}exports.taskDevServer = taskDevServer;

当咱们运行npx gulp taskDevServer时,浏览器会默认关上http://localhost:8081

咱们应用了一个watch监听public目录下的所有文件,如果文件有变动时,会执行taskBuild工作会在dist目录下生成对应的文件,而后会启动一个本地服务,关上一个8081的端口就能够拜访利用了。

至此一个一个用gulp搭建的前端利用终于能够了。

从新组织 gulpfile

最初咱们能够再从新组织一下gulpfile.js,因为多个工作写在一个文件里貌似不太那么好保护,随着业务迭代,会越来越多,因而,有必要将工作合成一下

在根目录新建task,咱们把所有的工作如下

common.js

// task/common.jsconst path = require('path');const pathDir = (dir) => {  return path.join(__dirname, '../', dir);};const rootDir = path.resolve(__dirname, '../');const basePath = {  base: './public'};const targetDest = 'dist';module.exports = {  rootDir,  pathDir,  basePath,  targetDest};

injectHtml.js

// task/injectHtml.jsconst { src, dest } = require('gulp');const inject = require('gulp-inject');const { targetDest, rootDir } = require('./common.js');// 将css,js插入html中const injectHtml = () => {  // 指标资源  const targetSources = src([`${rootDir}/${targetDest}/**/*.js`, `${rootDir}/${targetDest}/**/*.css`]);  // 指标html  const targetHtml = src(`${rootDir}/${targetDest}/*.html`);  // 把指标资源插入指标html中,同时输入到dist文件下  const result = targetHtml.pipe(inject(targetSources, { relative: true })).pipe(dest(targetDest));  return result;};module.exports = injectHtml;

taskDevServer.js

const { watch } = require('gulp');const path = require('path');const browserSync = require('browser-sync');const { pathDir, targetDest, rootDir } = require('./common.js');const taskDevServer = (taskBuild) => {  return (options = {}) => {    const defaultOption = {      port: '8081', //设置端口      open: true, // 主动关上浏览器      files: `${rootDir}/${targetDest}/*`, // 当dist文件下有改变时,会主动刷新页面      server: {        baseDir: `${rootDir}/${targetDest}` // 基于以后dist目录      },      ...options    };    // 监听public所有目录下,只有文件产生扭转,就从新加载    watch(pathDir('public'), taskBuild);    const server = browserSync.create();    server.init(defaultOption);  };};module.exports = taskDevServer;

...

task/index.js

const injectHtml = require('./injectHtml.js');const taskDevServer = require('./taskDevServer.js');const taskHtml = require('./taskHtml.js');const taskImage = require('./taskImage.js');const taskJS = require('./taskJS.js');const taskLess = require('./taskLess.js');module.exports = {  injectHtml,  taskDevServer,  taskHtml,  taskImage,  taskJS,  taskLess};

gulpfile.js中,咱们批改下

// gulpfile.jsconst { series } = require('gulp');const { injectHtml, taskDevServer, taskHtml, taskImage, taskJS, taskLess } = require('./task/index.js');// series组合多个工作const seriseTask = series(taskHtml, taskJS, taskLess, taskLess, taskImage, injectHtml);// 本地服务const devServer = taskDevServer(seriseTask);// 启动服务const server = () => {  devServer({    port: 9000  });};const taskBuild = seriseTask;const defaultTask = (cb) => {  console.log('hello gulp');  cb();};exports.default = defaultTask;exports.server = server;exports.build = taskBuild;

咱们在package.json中新增命令

  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1",    "server": "gulp server",    "build": "gulp build"  },

npm run build

在启动server之前,咱们先执行npm run build,而后再执行上面命令,保障browserSync创立的服务文件夹存在,不然页面关上就404谬误

npm run server

至此gulp搭建一个简略的应该就曾经齐全 ok 了

页面背景貌似有点黄

总结

  • gulpjs开发是一个工作流的开发方式,它的核心思想就是用自动化构建工具加强你的工作流,所有的自动化工作流操作都牢牢的把握在本人手上,你能够用gulp写一些自动化脚本,比方,文件上传,打包,压缩,或者革新传统的前端利用。
  • gulp写了一个简略的利用,然而发现中途须要找好多gulp插件,gulp的生态还算能够,3w多个 star,生态绝对丰盛,然而有些插件长年不更新,或者版本更新不反对,比方gulp-image,当你依照官网文档应用最新的包时,不反对 esm,你必须升高版本6.2.1,改用cjs才行
  • 应用gulp的一些罕用的 api,比方srcdestseries,以及browser-sync实现本地服务,更多api参考官网文档。
  • 即便我的项目工夫再多,也不要用gulp搭建前端利用,因为webpack生态很弱小了,看gulp的最近更新还是 2 年前,然而写个自动化脚本,还算能够,毕竟gulp的理念就是用自动化构建工具加强你工作流程,兴许当你接盘传统我的项目时,一些打包,拷贝,压缩文件之类的,能够尝试用用这个。
  • 本文示例code-example

欢送关注公众号:Web技术学苑
好好学习,天天向上!