gulp api 中的 watch()
方法。
利用文件系统(fs)的监控程序(file system watcher),将要打包的内容中,发生的更改,与 gulp 任务执行进行关联。
demo-project\22_gulp-gulp的基本使用\gulpfile.js
const { src, dest, watch } = require('gulp')
const babel = require('gulp-babel')
const terser = require('gulp-terser')
const jsTask = () => {
return src("./src/**/*.js")
.pipe(babel())
.pipe(terser({ mangle: { toplevel: true } }))
.pipe(dest("./dist"))
}
// watch 函数监听打包内容的改变
watch("./src/**/*.js", jsTask)
module.exports = {
jsTask
}
使用 gulp,编写一个案例,来开启本地服务和打包:
更多 gulp 插件见官方文档;
1.打包 html 文件;
安装 gulp-htmlmin 插件;
pnpm add gulp-htmlmin -D
2.打包 js 文件;
安装 gulp-babel 插件(同时还要安装 @babel/core, @babel/preset-env);
pnpm add gulp-babel @babel/core @babel/preset-env -D
3.安装 gulp-terser 插件;
pnpm add gulp-terser -D
4.打包 less 文件;
安装 gulp-less 插件;
pnpm add gulp-less -D
5.将打包好的资源,注入到 html 模板文件中
安装 gulp-inject 插件;
pnpm add gulp-inject -D
要在 html 模板文件中,使用特殊注释标识。
demo-project\23_gulp-gulp的项目构建\src\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 Projecct</title>
<!-- inject:css -->
<!-- endinject -->
</head>
<body>
<!-- inject:js -->
<!-- endinject -->
</body>
</html>
注入时,设置相对路径 { relative: true }
。
6.组合任务,
7.开启本地服务器
安装 browser-sync 插件(非 gulp 专用的插件,可在别的地方使用);
pnpm add browser-sync -D
8.环境分离:
- 创建打包任务
buildTask
。 - 创建开发任务
serveTask
,监听文件。
demo-project\23_gulp-gulp的项目构建\gulpfile.js
const { src, dest, parallel, series, watch } = require("gulp");
const htmlmin = require("gulp-htmlmin");
const babel = require('gulp-babel')
const terser = require('gulp-terser')
const less = require('gulp-less')
const inject = require('gulp-inject')
const browserSync = require('browser-sync')
// 1.对 html 进行打包
const htmlTask = () => {
return src("./src/**/*.html")
.pipe(htmlmin({ collapseWhitespace: true }))
.pipe(dest("./dist"));
};
// 2.对 JavaScript 进行打包
const jsTask = () => {
return src("./src/**/*.js")
.pipe(babel({ presets: ["@babel/preset-env"] }))
.pipe(terser({ toplevel: true }))
.pipe(dest('./dist'))
};
// 3.对 less 进行打包
const lessTask = () => {
return src("./src/**/*.less")
.pipe(less())
.pipe(dest("./dist"))
}
// 4.在 html 中注入 js 和 css
const injectTask = () => {
return src('./dist/**/*.html')
.pipe(inject(src(['./dist/**/*.js', './dist/**/*.css']), { relative: true }))
.pipe(dest('./dist'))
}
// 创建项目构建的任务
const buildTask = series(parallel(htmlTask, jsTask, lessTask), injectTask)
// 5.开启一个本地服务器
const bs = browserSync.create()
const serve = () => {
watch("./src/**", buildTask)
bs.init({
port: 8080,
open: true,
files: './dist/*',
server: {
baseDir: './dist'
}
})
}
const serveTask = series(buildTask, serve)
// webpack 搭建本地 webpack-dev-server
module.exports = {
buildTask,
serveTask
};
官方对 rollup 的定义:
- “Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex, such as a library or application”.
- Rollup 是一个 JS 的模块化打包工具,可以将小的代码片段,编译到一个大的、复杂的代码中(模块化的概念),比如一个库或者一个应用程序;
rollup 通常作为库打包工具。
我们发现 Rollup 的定义、定位,与 webpack 非常相似:
打包模块化的区别:
- rollup 也是一个模块化的打包工具,但 Rollup 主要针对 ESModule 模块化规范进行打包;
- webpack 默认支持对各种模块化规范,进行打包。
打包文件的区别:
- rollup 更专注于处理 JS 代码(当然也可以处理 css、font、vue 等文件);
- webpack 可以通过 loader,处理各种各样的文件,以及处理它们的依赖关系;
思想理念的区别:
- rollup 的配置和理念,相对于 webpack 来说,更简洁、容易理解;
适用场景的区别:
- rollup 通常用于对库文件进行打包。
- 比如 vue、react、dayjs 源码,都是基于 rollup 打包的;
- 比如 Vite 底层基于 rollup 打包;
- webpack 通常用于实际的项目开发中;
- 比如 react、angular 的脚手架,都是基于 webpack 的);
- 早期 webpack 不支持 tree shaking 时,rollup 具备更强的优势;
安装 rollup:
pnpm add rollup -D
使用 rollup 命令,进行打包,要指定打包文件,应用的环境,比如:
打包后的文件,要用于 node 环境,就要支持 CommonJS;配置参数 -f cjs
:
# 打包 CommonJS 的库
npx rollup ./src/main.js -f cjs -o dist/bundle.js
打包后的文件,要用于浏览器环境,就要有全局对象,配置参数 -f iife
,最好使用 --name
指定名字。
- 比如:jQuery 中,就是
$
; - 比如:dayjs 中,就是
dayjs
。
# 打包浏览器的库
npx rollup ./src/main.js -f iife --name mathUtil -o dist/bundle.js
打包后的文件,要用于 AMD 环境,配置参数 -f amd
。
# 打包AMD的库
npx rollup ./src/main.js -f amd -o dist/bundle.js
打包后的文件,要在所有环境适配,配置参数 -f umd
,还要 --name
指定名字。
# 打包通用的库(必须跟上 name)
npx rollup ./src/main.js -f umd --name mathUtil -o dist/bundle.js
rollup 的配置文件名称为:rollup.config.js
:
在配置文件中,进行配置,打包出,在不同环境下使用的库文件(用户可以根据不同的需求来引入):
demo-project\24_rollup-rollup的库打包\rollup.config.js
module.exports = {
// 入口
input: "./lib/index.js",
// 出口,可以是数组,也可以是对象
output: [
{
format: "umd",
name: "zztUtils",
file: "./build/bundle.umd.js"
},
{
format: "amd",
file: "./build/bundle.amd.js"
},
{
format: "cjs",
file: "./build/bundle.cjs.js"
},
{
format: "iife",
name: "zztUtils",
file: "./build/bundle.browser.js"
}
]
}
执行命令,根据配置文件打包:
npx rollup -c
比如,当代码中使用了 loadash 库时,该库没有被打包进源代码;
- 因为 lodash 使用 commonjs 模块化规范;
- rollup 默认情况下,只会处理 ESModule 模块化规范的代码;
要解决类似于使用 commonjs 引入模块无法打包的问题,详见官方文档。
解决办法如下:
安装 @rollup/plugin-commonjs 库:
pnpm add @rollup/plugin-commonjs -D
lodash 不仅使用的是 commonjs 规范,还需要从 node_modules 中引入。
所以仍然不会被打包,
要解决项目中,从 node_modules 中,引入第三方依赖,无法打包的问题:
还需要安装 @rollup/plugin-node-resolve 库:
pnpm add @rollup/plugin-node-resolve -D
在配置文件中,配置相应的插件:
demo-project\24_rollup-rollup的库打包\rollup.config.js
// 默认 lodash 没有被打包,是因为它使用 commonjs;
// rollup 默认情况下,只会处理 ESModule
const commonjs = require('@rollup/plugin-commonjs')
const nodeResolve = require('@rollup/plugin-node-resolve')
module.exports = {
// 入口
input: "./lib/index.js",
// 出口
output: {
format: "umd",
name: "zztUtils",
file: "./build/bundle.umd.js",
// 指定全局变量 _ 表示 lodash
globals: {
lodash: "_"
}
},
plugins: [
commonjs(),
nodeResolve()
]
}
执行打包命令。
npx rollup -c
事实上,作为一个给用户使用的第三方库,并不需要打包 lodash 的代码,而是要让用户自己安装 lodash;
在配置文件中配置:打包时,排除 lodash。
demo-project\24_rollup-rollup的库打包\rollup.config.js
// 默认 lodash 没有被打包是因为它使用 commonjs, rollup 默认情况下只会处理 es module
const commonjs = require('@rollup/plugin-commonjs')
const nodeResolve = require('@rollup/plugin-node-resolve')
module.exports = {
// 入口
input: "./lib/index.js",
// 出口
output: {
format: "umd",
name: "zztUtils",
file: "./build/bundle.umd.js",
globals: {
lodash: "_"
}
},
external: ["lodash"], // 打包时,排除 lodash
plugins: [
commonjs(),
nodeResolve(),
]
}
rollup 中,最核心的概念,就是插件,更多插件参考官方文档
在 rollup 中,将 ES6+ 转成 ES5 代码,使用 babel。
安装 rollup 的 babel 插件 @rollup/plugin-babel,并安装 @babel/core、@babel/preset-env:
pnpm add @rollup/plugin-babel @babel/core @babel/preset-env -D
配置 babel.config.js
文件;
demo-project\24_rollup-rollup的库打包\babel.config.js
module.exports = {
presets: [
["@babel/preset-env"]
]
}
在 rollup.config.js
的 babel
插件配置中:配置 babelHelpers
,用于添加 polyfill。
demo-project\24_rollup-rollup的库打包\rollup.config.js
// 默认 lodash 没有被打包是因为它使用 commonjs, rollup 默认情况下只会处理 es module
const commonjs = require('@rollup/plugin-commonjs')
const nodeResolve = require('@rollup/plugin-node-resolve')
// 使用代码转换和压缩
const { babel } = require('@rollup/plugin-babel')
module.exports = {
// 入口
input: "./lib/index.js",
// 出口
output: {
format: "umd",
name: "zztUtils",
file: "./build/bundle.umd.js",
globals: {
lodash: "_"
}
},
external: ["lodash"],
plugins: [
commonjs(),
nodeResolve(),
babel({
babelHelpers: "bundled",
exclude: /node_modules/ // 排除对 node_modules 中代码的转换。
}),
]
}
在 rollup 中,对代码进行压缩,安装 @rollup/plugin-terser:
npm install @rollup/plugin-terser -D
在 rollup.config.js
中,进行配置:
// 默认lodash没有被打包是因为它使用commonjs, rollup默认情况下只会处理es module
const commonjs = require('@rollup/plugin-commonjs')
const nodeResolve = require('@rollup/plugin-node-resolve')
// 使用代码转换和压缩
const { babel } = require('@rollup/plugin-babel')
const terser = require('@rollup/plugin-terser')
module.exports = {
// 入口
input: "./lib/index.js",
// 出口
output: {
format: "umd",
name: "zztUtils",
file: "./build/bundle.umd.js",
globals: {
lodash: "_"
}
},
external: ["lodash"],
plugins: [
commonjs(),
nodeResolve(),
babel({
babelHelpers: "bundled",
exclude: /node_modules/
}),
terser()
]
}