vue3企业级组件库封装[五]:gulp的使用

五、前端流程化控制工具gulp的使用

如webpack,rollup,vite的发展,gulp感觉似乎好像被取代了。其实并没有,只不过它从台前退居到
了幕后。我们仍然可以在很多项目中看到它的身影,比如elementplus、vant等。现在gulp更多的是做
流程化的控制。

比如我们要把一个东西放进冰箱里就需要 打开冰箱门->把东西放进冰箱->关上冰箱门,这就是一个简单的流程,使用gulp就可以规定这些流程,将这个流程自动化。

所以我们可以使用它在项目开发过程中自动执行常见任务。比如打包一个组件库,我们可能要移除文
件、copy文件,打包样式、打包组件、执行一些命令还有一键打包多个package等等都可以由gulp进行自定义流程的控制,非常的方便。

1、介绍gulp主要的一些常用功能

首先全局安装gulp的脚手架

npm install --global gulp-cli

然后我们新建文件夹gulpdemo,然后执行 npm init -y,然后在这个项目下安装本地依赖gulp

npm install gulp -D

此时我们gulp便安装好了,接下来我们在根目录下创建gulpfile.js文件,当gulp执行的时候会自动寻找
这个文件。

2、创建一个任务Task

每个gulp任务(task)都是一个异步的JavaScript函数,此函数是一个可以接收callback作为参数的函
数,或者返回一个Promise等异步操作对象,比如创建一个任务 可以这样写

exports.default = (cb) => {
console.log("my task");
cb();
};

或者这样写

exports.default = () => {
console.log("my task");
return Promise.resolve();
};

然后终端输入gulp就会执行我们这个任务。

3、串行(series)和并行(parallel)

这两个其实很好理解,串行就是任务一个一个执行,并行就是所有任务一起执行。下面先看串行演示

const { series, parallel } = require("gulp");
const task1 = () => {
console.log("task1");
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 5000);
});
};
const task2 = () => {
console.log("task2");
return Promise.resolve();
};
exports.default = series(task1, task2);

执行 =》在控制台 输入 gulp
控制台输出结果如下
在这里插入图片描述
可以看出执行task1用了4s,然后再执行task2,再看下并行
在这里插入图片描述
可以看出两个任务是同时执行的

4、src()和dest()

src()和dest()这两个函数在我们实际项目中经常会用到。src()表示创建一个读取文件系统的流,dest()
是创建一个写入到文件系统的流。我们直接写一个copy 的方法

5、复制某个文件流

在写之前我们先在我们项目根目录下新建一个src目录用于存放我们被复制的文件,在src下随便新建几
个文件,如下图
在这里插入图片描述
然后我们在gulpfile.js写下我们的copy任务:将src下的所有文件复制到dist文件夹下:

//我们在这里写copy任务
const {src,dest} = require('gulp');
//src => 读取文件
//dest => 写入文件
const copy = () => {
//pipe => 管道流
return src('src/*').pipe(dest('dist'));
}
exports.default = copy;

然后执行gulp(默认执行exports.default),我们就会发现根目录下多了个dist文件夹

6、写个处理less文件的任务

那么通过上面的认识 =》处理样式=》我这里是less文件。

下面我们写个处理less文件的任务,首先我们先安装gulp-less。

npm i -D gulp-less

然后我们在src下新建一个style/index.less并写下一段less语法样式

index.less
@color: #7f0f0f;
.wukong {
color: @color;
}

然后gulpfile.js写下我们的lessTask:将我们style下的less文件解析成css并写入dist/style中

//现在我们需要处理less文件=>将他们转换成css文件=》写到dist目录下
//读取和写入文件
const { src, dest } = require('gulp');
//引入gulp-less =》将less文件转换成css文件
const less = require('gulp-less');
//引入gulp-clean-css =》压缩css文件(组件库中使用)
//写一个任务
function lessTask() {
return src('src/style/*.less') //读取文件
.pipe(less()) //将less文件转换成css文件
.pipe(dest('./dist/style')) //写入文件
}
exports.default = lessTask; //导出任务

然后我们执行gulp命令就会发现dist/style/index.css
dist/style/index.css

.wukong {
color: #7f0f0f;
}

我们还可以给css加前缀 =>来兼容不同的浏览器 =》需要引入插件

npm install gulp-autoprefixer -D

将我们的src/style/index.less改为

@color: #7f0f0f;
.wukong {
color: @color;
display: flex;
}

然后在gulpfile.js中使用gulp-autoprefixer

import {src, dest } from 'gulp'
import less from 'gulp-less'
//引入兼容不同的浏览器前缀
import autoprefixer from 'gulp-autoprefixer'
//写一个任务
function lessTask() {
return src('src/style/*.less') //读取文件
.pipe(less()) //将less文件转换成css文件
.pipe(autoprefixer({
overrideBrowserslist: ["> 1%", "last 2 versions"]
})) //添加前缀
.pipe(dest('./dist/style')) //写入文件
}
export default lessTask; //导出任务

在将packages.json文件中添加

"type": "module"

7、压缩css文件

在前端开发中,优化代码性能是至关重要的一步,尤其是CSS文件,过大的尺寸可能导致页面加载速度变慢。今天,我将向您推荐一个强大的CSS压缩工具—— gulp-clean-css ,它是基于Gulp的任务自动化工具]和Clean CSS库的完美结合。

gulp-clean-css 是一个Gulp插件,用于压缩和清理CSS文件。它利用了Clean CSS库的强大功能,提供了一种简单、高效的途径来减小CSS文件的大小,从而提升网页加载速度。

安装依赖

npm install --save-dev gulp-clean-css

在你的 gulpfile.js 中引入并创建任务:

//现在我们需要处理less文件=>将他们转换成css文件=》写到dist目录下
//读取和写入文件
// const { src, dest } = require('gulp');
// //引入gulp-less =》将less文件转换成css文件
// const less = require('gulp-less');
// const autoprefixer = require("gulp-autoprefixer");
import {src, dest } from 'gulp'
import less from 'gulp-less'
//引入兼容不同的浏览器前缀
import autoprefixer from 'gulp-autoprefixer'
//引入gulp-clean-css =》压缩css文件(组件库中使用)
import cleanCSS from 'gulp-clean-css'
//写一个任务
function lessTask() {
return src('src/style/*.less') //读取文件
.pipe(less()) //将less文件转换成css文件
.pipe(autoprefixer({
overrideBrowserslist: ["> 1%", "last 2 versions"]
})) //添加前缀
.pipe(cleanCSS()) //压缩css文件
.pipe(dest('./dist/style')) //写入文件
}
// exports.default = lessTask; //导出任务
export default lessTask; //导出任务

处理后的dist/style/index.css就变成了

.wukong{color:#7f0f0f;display:-webkit-box;display:-ms-flexbox;display:flex}

8、监听文件更改browser-sync

browser-sync是一个十分好用的浏览器同步测试工具,它可以搭建静态服务器,监听文件更改,并刷
新页面(HMR),下面来看下它的使用

首先肯定要先安装

npm i browser-sync -D

然后我们在根目录下新建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>Document</title>
<link rel="stylesheet" href="./dist/style/index.css" />
</head>
<body>
hello world
</body>
</html>

然后在gulpfile.js中进行配置 将之前的gulpfile.js变成gulpfile1.js 保留内容

//写一个任务 监听文件变化
import browserSync from "browser-sync";
const browserTask = () => {
browserSync.init({
server: {
baseDir: './' // 从这个项目的根目录提供文件
}
});
}
export default browserTask;

这时候就会启动一个默认3000端口的页面. 下面我们看如何监听页面变化。

首先我们要监听文件的改变,可以使用browserSync的watch,监听到文件改变后再刷新页面

此时改动src下的文件浏览器便会刷新。

下面我们将index.html引入dist/style/index.css的样式,然后来模拟一个简单的构建流

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./dist/style/index.css" />
</head>
<body>
<div class="wukong">
悟空前端
</div>
</body>
</html>

此时我们的流程是 编译less文件->将css写入dist/style->触发页面更新
我们gulpfile.js可以这样写

import {src, dest } from 'gulp'
import less from 'gulp-less'
import autoprefixer from 'gulp-autoprefixer'
import cleanCSS from 'gulp-clean-css'
//写一个任务 监听文件变化
import browserSync from "browser-sync";
import {watch} from 'browser-sync'
//watch =>作用:监听文件变化
import {series} from 'gulp'
//series =>作用:串行执行任务
//引入需要监听的任务less
function lessTask() {
return src('src/style/*.less') //读取文件
.pipe(less()) //将less文件转换成css文件
.pipe(autoprefixer({
overrideBrowserslist: ["> 1%", "last 2 versions"]
})) //添加前缀
.pipe(cleanCSS()) //压缩css文件
.pipe(dest('./dist/style')) //写入文件
}
//监听页面刷新
const reload = (done) => {
browserSync.reload(); //刷新页面
}
const browserTask = () => {
browserSync.init({
server: {
baseDir: './' // 从这个项目的根目录提供文件
}
});
watch('./*.html', series(reload)); //HTML文件发生变化时,执行reload任务
watch('src/style/*', series(lessTask,reload))
}
export default browserTask;

此时无论我们更改的是样式还是html都可以触发页面更新。

六、使用gulp打包组件库并实现按需加载

使用 Vite 库模式打包的时候,vite 会将样式文件全部打包到同一个文件中,这样的话我们每次都要全量引
入所有样式文件做不到按需引入的效果。所以打包的时候我们可以不让 vite 打包样式文件,样式文件将
使用 gulp 进行打包 ,

将介绍如何使用 gulp 打包样式文件,以及如何按需加载样式文件。

1、自动按需引入插件

现在很多组件库的按需引入都是借助插件来解决的,比如 ElementPlus 是使用 unplugin-vue- components 和 unplugin-auto-import ,这两个插件可以实现
比如

import { Button } from "wukongui";
//相当于
import "wukongui/es/src/button/style/index.css";
import "wukongui/es/src/button/index.mjs";

2、删除打包文件

我们都知道,在打包之前是需要将前面打包的文件删除的,所以需要先写一个删除函数。在此之前,我们先在 components 新建一个 script 文件夹用于存放我们的脚本相关内容,script 下的 build 文件夹里的内
容则是本篇文章要介绍的打包相关内容。

在 script/utils 中新建 paths.ts 用于维护组件库路径,记得先安装

pnpm add @types/node -D -w
import { resolve } from "path";
//组件根目录
export const componentPath = resolve(__dirname, "../../");
//打包组件的根目录
export const pkgPath = resolve(__dirname, "../../../");

删除打包目录函数可以放在 bulid/utils 中的 delpath.ts,注意这里因为打包后的 wukongui 包是我们最
终要发布的包,所以我们需要将 package.json 和 README.md 保留下来

import fs from "fs"; //作用:读取文件
import { resolve } from "path"; //作用:解析路径
import { pkgPath } from "./path";
//需要保留的文件
const keepFiles = ["package.json", "README.md"];
//需要删除的文件
const deleteFiles = async (path: string) => {
let files: string[] = [];
if (fs.existsSync(path)) {
//判断文件是否存在
files = fs.readdirSync(path); //读取文件夹下的文件
files.forEach(async (file) => {
const curPath = resolve(path, file); //拼接路径
if (fs.statSync(curPath).isDirectory()) {
//判断是否是文件夹
if (file != "node_modules") await deleteFiles(curPath);
} else {
if (!keepFiles.includes(file)) {
//判断是否是需要保留的文件
fs.unlinkSync(curPath); //删除文件
}
}
});
if (path !== pkgPath) {
fs.rmdirSync(path); //删除文件夹
}
}
};
export default deleteFiles;

3、使用gulp

我们需要使用 ts 以及新的 es6 语法,而 gulp 是不支持的,所以我们需要安装一些依赖使得 gulp 支持
这些,其中 sucras 让我们执行 gulp 可以使用最新语法并且支持 ts

pnpm i gulp @types/gulp sucrase -D -w

在 build/index.ts 来执行删除流程

import delPath from "../utils/delpath";
import { series, parallel } from "gulp";
import { pkgPath } from "../utils/paths";
//删除dist目录
export const removeDist = () => {
return delPath(`${pkgPath}/wukongui`);
};
export default series(async () => removeDist());

在根目录wukongui/package.json 添加脚本

"scripts": {
"build:wukong": "gulp -f packages/components/script/build/index.ts"
},

根目录下执行`pnpm run build:wukong就会发现 dist 下的文件被删除了

4、gulp打包样式

因为我们用的是 less 写的样式,所以需要安装 gulp-less ,同时在安装一个自动补全 css 前缀插件 gulpautoprefixer 以及它们对应的上面文件

pnpm add gulp-less @types/gulp-less gulp-autoprefixer @types/gulp-autoprefixer -
D -w
export const buildStyle = () => {
return src(`${componentPath}/src/**/style/**.less`)
.pipe(less())
.pipe(autoprefixer())
.pipe(dest(`${pkgPath}/dist/lib/src`))
.pipe(dest(`${pkgPath}/dist/es/src`));
}

5、打包组件

最后再写一个打包组件的函数,这里需要写一个执行命令的工具函数,在 utils/run.ts

import { spawn } from "child_process";//nodejs内置模块,用于执行命令
export default async (command: string, path: string) => {
//cmd表示命令,args代表参数,如 rm -rf rm就是命令,-rf就为参数
const [cmd, ...args] = command.split(" ");
return new Promise((resolve, reject) => {
const app = spawn(cmd, args, {
cwd: path, //执行命令的路径
stdio: "inherit", //输出共享给父进程
shell: true, //mac不需要开启,windows下git base需要开启支持
});
//执行完毕关闭并resolve
app.on("close", resolve);
});
};

然后引入 run 函数

export const buildComponent = async () => {
run("pnpm run build", componentPath);
};

因为打包样式和打包组件可以并行,所以最后 build/index.ts 为

import deleteFiles from "../utils/delpath";
import { series, src, dest, parallel } from "gulp";
import { pkgPath, componentPath } from "../utils/path";
import less from "gulp-less";
import autoprefixer from "gulp-autoprefixer";
import run from "../utils/run";
//使用gulp打包样式
export const buildStyle = () => {
return src(`${componentPath}/src/**/style/**.less`)
.pipe(less())
.pipe(autoprefixer())
.pipe(dest(`${pkgPath}/dist/lib/src`))
.pipe(dest(`${pkgPath}/dist/es/src`));
};
export const removeDist = () => { //删除dist目录
return deleteFiles(`${pkgPath}/dist`);
};
//打包组件
export const buildComponent = async () => {
run("pnpm run build", componentPath); //执行命令
};
export default series(
async () => removeDist(),
parallel( //并行执行
async () => buildStyle(), //打包样式
async () => buildComponent()//
)
);

最后 vite 打包的时候忽略 less 文件,components/vite.config.ts

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import dts from "vite-plugin-dts";
import DefineOptions from "unplugin-vue-define-options/vite";
export default defineConfig({
build: {
//打包文件目录
outDir: "es",
//压缩
//minify: false,
rollupOptions: {
//忽略打包vue和.less文件
external: ["vue", /\.less/],
...
}
});

打包效果图 =>根目录执行 pnpm run build ,即可完成打包
在这里插入图片描述

下一节见https://blog.csdn.net/fageaaa/article/details/154339692

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

太阳与星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值