DEV Community

Mark
Mark

Posted on

Building Vue3 Component Library from Scratch #6 Gulp Introduce

Preface

With the development of front-end tools such as Webpack, Rollup, and Vite, Gulp seems to have been replaced. However, that's not the case. It has simply moved from the forefront to the background. We can still see it in many projects, such as ElementPlus and Vant. Nowadays, Gulp is more focused on process control.

For example, if we want to put an elephant into a refrigerator, we need to follow a simple process: open the refrigerator door -> put the elephant inside -> close the refrigerator door. Using Gulp, we can define these steps and automate this process.

So we can use Gulp to automate common tasks during project development. For example, when packaging a component library, we might need to remove files, copy files, package styles, package components, execute some commands, and package multiple packages with one click. All of these tasks can be controlled by Gulp through custom workflows, making it very convenient.

This article will mainly introduce some common functionalities of Gulp.

Install Gulp

Firstly, install gulp globally.

npm install --global gulp-cli
Enter fullscreen mode Exit fullscreen mode

Next, we create a new folder called gulpdemo, then run npm init -y to initialize the project. After that, we install Gulp as a local dependency in this project.

npm install gulp -D
Enter fullscreen mode Exit fullscreen mode

At this point, Gulp is installed. Next, we create gulpfile.js file in the root directory. When Gulp runs, it will automatically look for this file.

Create Task

Each Gulp task is an asynchronous JavaScript function. This function can accept a callback as a parameter or return a Promise or other asynchronous operation object. For example, creating a task can be done like this:

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

Or

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

Then, by typing gulp in the terminal, this task will be executed.

Series and Parallel

These two concepts are quite easy to understand. Serial execution means tasks are executed one after another, while parallel execution means all tasks are executed simultaneously. Let's first look at a demonstration of serial execution.

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);
Enter fullscreen mode Exit fullscreen mode

The console output:

Image description

You can see that executing task1 took 5 seconds, and then task2 was executed. Now let's look at parallel execution.

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 = parallel(task1, task2);
Enter fullscreen mode Exit fullscreen mode

Image description

You can see that the two tasks are executed simultaneously.

src() and dest()

src() and dest() are two functions that we often use in our actual projects. src() represents creating a stream to read from the file system, while dest() creates a stream to write to the file system. Let's write a simple example for copying files.

Copy

Before writing the task, let's create a src directory in the root of our project to store the files to be copied. Inside the src directory, create a few files.

Next, we write our copy task in gulpfile.js to copy all files from the src directory to the dist directory.

const { src, dest } = require("gulp");

const copy = () => {
  return src("src/*").pipe(dest("dist/"));
};

exports.default = copy;
Enter fullscreen mode Exit fullscreen mode

Then, run gulp (which by default executes exports.default), and you'll notice that a dist folder has been created in the root directory.

Process Less

Next, let's write a task to process LESS files. First, we need to install gulp-less.

npm i -D gulp-less
Enter fullscreen mode Exit fullscreen mode

Next, create a style directory inside the src folder, and then create an index.less file inside the style directory. Write a piece of LESS syntax style in it. For example:

@color: #fff;
.wrap {
  color: @color;
}
Enter fullscreen mode Exit fullscreen mode

Next, let's write our lessTask in gulpfile.js to parse the LESS files in the style directory into CSS and write them into dist/style.

const { src, dest } = require("gulp");
const less = require("gulp-less");
const lessTask = () => {
  return src("src/style/*.less").pipe(less()).pipe(dest("dist/style"));
};

exports.default = lessTask;
Enter fullscreen mode Exit fullscreen mode

Then, run the gulp command, and you'll find dist/style/index.css.

.wrap {
  color: #fff;
}
Enter fullscreen mode Exit fullscreen mode

We can add prefixes to our CSS.

npm install gulp-autoprefixer -D
Enter fullscreen mode Exit fullscreen mode

Update src/style/index.less to:

@color: #fff;
.wrap {
  color: @color;
  display: flex;
}
Enter fullscreen mode Exit fullscreen mode

Then, use gulp-autoprefixer in gulpfile.js.

const { src, dest } = require("gulp");
const less = require("gulp-less");
const autoprefixer = require("gulp-autoprefixer");
const lessTask = () => {
  return src("src/style/*.less")
    .pipe(less())
    .pipe(
      autoprefixer({
        overrideBrowserslist: ["> 1%", "last 2 versions"],
        cascade: false, 
      })
    )
    .pipe(dest("dist/style"));
};

exports.default = lessTask;
Enter fullscreen mode Exit fullscreen mode

The processed dist/style/index.css will look like this:

.wrap {
  color: #fff;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}
Enter fullscreen mode Exit fullscreen mode

Watch File Changes with browser-sync

Browser-sync is a very useful browser synchronization testing tool. It can set up a static server, monitor file changes, and refresh the page (HMR). Let's take a look at how to use it.

Firstly, you definitely need to install it.

npm i browser-sync -D 
Enter fullscreen mode Exit fullscreen mode

Then, we create index.html in the root directory.

<!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>
</head>
<body>
        hello world
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Then, configure it in the gulpfile.js.

const browserSync = require("browser-sync");
const browserTask = () => {
  browserSync.init({
    server: {
      baseDir: "./",
    },
  });
};

exports.default = browserTask;
Enter fullscreen mode Exit fullscreen mode

At this point, a server will be launched on the default port 3000. Next, let's see how to monitor changes.

Firstly, we need to monitor changes in the file, which can be done using browserSync's watch. After detecting changes in the file, the page is then refreshed.

const { watch } = require("browser-sync");
const browserSync = require("browser-sync");
const { series } = require("gulp");

const reloadTask = () => {
  browserSync.reload();
};

const browserTask = () => {
  browserSync.init({
    server: {
      baseDir: "./",
    },
  });
  watch("./*", series(reloadTask));
};

exports.default = browserTask;
Enter fullscreen mode Exit fullscreen mode

At this point, if you modify a file under 'src', the browser will refresh.

Now we will import the style from 'dist/style/index.css' into 'index.html', and then simulate a simple build flow.

<!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>
    <div class="wrap">hello world</div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

At this point, our process is: compile the less files -> write css into 'dist/style' -> trigger page update.

We can write our 'gulpfile.js' like this:

const { src, dest } = require("gulp");
const { watch } = require("browser-sync");
const browserSync = require("browser-sync");
const { series } = require("gulp");
const less = require("gulp-less");
const autoprefixer = require("gulp-autoprefixer");
const lessTask = () => {
  return src("src/style/*.less")
    .pipe(less())
    .pipe(
      autoprefixer({
        overrideBrowserslist: ["> 1%", "last 2 versions"],
        cascade: false, //  format
      })
    )
    .pipe(dest("dist/style"));
};
//refresh
const reloadTask = () => {
  browserSync.reload();
};

const browserTask = () => {
  browserSync.init({
    server: {
      baseDir: "./",
    },
  });
  watch("./*.html", series(reloadTask));
  //watch to run task
  watch("src/style/*", series(lessTask, reloadTask));
};

exports.default = browserTask;
Enter fullscreen mode Exit fullscreen mode

At this point, whether we change the style or the HTML, it can trigger a page update.

Finally

In the future, I will use gulp to handle the style packaging part of the Vue3 component library that I am currently developing. If you are interested in component library development, you can follow this series. I will implement some commonly used components and present them in the form of blog.

Top comments (0)