别被题目吓到,哈哈,即便当初 vite
横空出世,社区光芒四射,两个字很快,然而 webpack
仍旧宝刀未老,仍然扛起前端工程化的大梁,然而明天我为啥说要拥抱gulp
,因为咱们经经常吃一道菜,所以要换个口味,这样才养分平衡。
gulp
定义是:用 自动化构建工具
加强你的 工作流程
, 是一种基于工作 文件流
形式, 你能够在前端写一些自动化脚本,或者降级历史传统我的项目,解放你反复打包,压缩,解压之类的操作。
集体了解 gulp
是一种 命令式编程
的体验,更重视构建过程,所有的工作须要你本人手动创立,你会对构建流程会十分分明,这点不像 webpack
,webpack
就是一个开箱即用的 申明式
形式,webpack
是一个模块化打包工具,外部细节暗藏十分之深,你也不需关注细节,你只须要照着提供的 API
以及引入对应的 loader
和plugin
应用就行。
言归正传,为了 饮食平衡
,明天一起学习下gulpjs
注释开始 …
搭建一个简略的前端利用
相比拟 webpack
,其实gulp
的我的项目构造更偏差传统的利用,只是咱们借助 gulp
工具解放咱们的一些 代码压缩
、es6 编译
、 打包
以及在传统我的项目中都能够应用 less
体验。
在 gulp
目录下新建01-simple-demo
根目录下生成默认package.json
npm init -y
而后在 public
目录下新建images
、css
、js
、index.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.js
const {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.js
const {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.js
const {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 html
const 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.js
const 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.js
const {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.js
const {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, 比方src
、dest
、series
, 以及browser-sync
实现本地服务,更多 api 参考官网文档。 - 即便我的项目工夫再多,也不要用
gulp
搭建前端利用,因为webpack
生态很弱小了,看gulp
的最近更新还是 2 年前,然而写个自动化脚本,还算能够,毕竟gulp
的理念就是用自动化构建工具加强你工作流程
,兴许当你接盘传统我的项目时,一些打包,拷贝,压缩文件之类的,能够尝试用用这个。 - 本文示例 code-example
欢送关注公众号:Web 技术学苑
好好学习,天天向上!