工具库打包流程
本章主要是打包,把组件库进行打包,使用gulp来控制打包流程,采用rollup打包(由于操作过程比较繁琐,将会省略一些步骤,不会太细化了,但是会讲清楚,代码中会有注释,相关的内容可以去看官方文档)
首先来安装工具gulp
,在根目录下执行命令:pnpm install gulp @types/gulp sucrase -w -D
在根目录下的package.json
中增加build
脚本:gulp -f build/gulpfile.ts
,指定配置文件为build目录下的gulpfile.ts
文件:
根目录下增加build
目录,结构如下:paths.ts
存放定义的公共path,index.ts
放一些公共方法
gulpfile.ts
代码如下:
// 打包方式:串行(series) 并行(parallel)
import { series, parallel } from "gulp";
import { withTaskName,run } from "./utils"
// gulp 不叫打包,做代码转化 vite
/**
* 1. 打包样式
* 2. 打包工具方法
* 3. 打包所有组件
* 4. 打包每个组件
* 5. 生成一个组件库
* 6. 发布组件
*/
export default series(
withTaskName("clean", async () => run('rm -rf ./dist')), // 删除dist目录
);
然后把withTaskName
方法封装在utils/index.ts
,index.ts
的代码如下:
/**
* 子进程
* child_process.spawn(command[, args][, options])
* command <string> 要运行的命令。
* args <string[]> 字符串参数列表。
* options <Object>
* - cwd <string> | <URL> 子进程的当前工作目录
* - stdio <Array> | <string> 子进程的标准输入输出配置。'inherit':通过相应的标准输入输出流传入/传出父进程
* - shell <boolean> | <string> 如果是 true,则在 shell 内运行 command。 在 Unix 上使用 '/bin/sh',在 Windows 上使用 process.env.ComSpec。 可以将不同的 shell 指定为字符串。 请参阅 shell 的要求和默认的 Windows shell。 默认值: false (没有 shell)x
*/
import { spawn } from "child_process";
import { projectRoot } from "./paths";
// 自定义每个task的name
export const withTaskName = <T>(name: string, fn: T) =>
Object.assign(fn, { displayName: name });
// 在node中开启一个子进程来运行脚本
export const run = async (command: string) => {
return new Promise((resolve) => {
// 将命令分割 例如:rm -rf 分割为['rm', '-rf'],进行解构[cmd,...args]
const [cmd, ...args] = command.split(" ");
const app = spawn(cmd, args, {
cwd:projectRoot,
stdio:"inherit",
shell:true // 默认情况下 linux才支持 rm -rf windows安装git bash
});
// 在进程已结束并且子进程的标准输入输出流已关闭之后,则触发 'close' 事件
app.on('close',resolve) //
});
};
接下来测试一下,在根目录新建一个dist
目录,执行npm run build
,看看有没有删除掉,选择vscode下的命令行git bash
,不然在windows下会提示rm不是一个命令
执行完后看到dist
目录已经被成功删掉了
我们要做的是把packages下的三个包components
,theme-chalk
,utils
分别打包,最终生成到根目录下的dist
目录,所以我们要在每个目录下的package.json
下,增加build
脚本,执行build
脚本时,会在当前目录下找gulp
配置文件gulpfile.ts
首先先处理样式文件,在theme-chalk
下增加gulp
配置文件gulpfile.ts
# 安装相关依赖
pnpm install gulp-sass @types/gulp-sass @types/sass gulp-autoprefixer @types/gulp-autoprefixer @types/gulp-clean-css gulp-clean-css -w -D
/**
* 打包样式
* 安装相关依赖
* pnpm install gulp-sass @types/gulp-sass @types/sass gulp-autoprefixer @types/gulp-autoprefixer @types/gulp-clean-css gulp-clean-css -w -D
* gulp-autoprefixer:添加样式前缀 gulp-clean-css:压缩css
*/
import gulpSass from "gulp-sass";
import dartSass from "sass";
import autoprefixer from "gulp-autoprefixer";
import cleanCss from "gulp-clean-css";
import path from "path";
/**
* gulp是类似一个管道的方式执行,从入口开始到出口,中间一步步执行
*/
import { series, src, dest } from "gulp";
/**
* 对sass文件做处理
*/
function compile() {
const sass = gulpSass(dartSass);
// 从src下的scss文件开始=>编译成css=>添加前缀=>压缩=>最终输出到当前目录下dist下的css目录
return src(path.resolve(__dirname, "./src/*.scss"))
.pipe(sass.sync())
.pipe(autoprefixer())
.pipe(cleanCss())
.pipe(dest("./dist/css"));
}
/**
* 处理font文件
*/
function copyfont() {
// 从src下单fonts文件夹下的所有文件开始=>压缩=>最终输出到当前目录下dist下的font目录
return src(path.resolve(__dirname,'./src/fonts/**')).pipe(cleanCss()).pipe(dest("./dist/fonts"))
}
/**
* 把打包好的css输出到根目录的dist
*/
function copyfullstyle(){
const rootDistPath = path.resolve(__dirname,'../../dist/theme-chalk')
return src(path.resolve(__dirname,'./dist/**')).pipe(dest(rootDistPath))
}
export default series(compile, copyfont,copyfullstyle);
处理好样式文件后,我们在当前目录下生成打包目录dist
,并把dist
拷贝到根目录下的dist
,更改名称为theme-chalk
,现在来测试一下,在theme-chalk
下执行npm run build
,依次执行了我们的三个处理方法,compile
、copyfont
、copyfullstyle
,结果如下:
生成的目录如下:
样式文件处理好了,现在我们处理utils
,在utils
下增加gulp
配置文件gulpfile.ts
,并且安装依赖gulp-typescript
来处理ts文件
import { buildPackages } from "../../build/packages"
export default buildPackages(__dirname,'utils')
# 安装依赖
pnpm install gulp-typescript -w -D
由于处理ts
的我们可能会用到多次,所以这里封装一个方法在build
目录下新建文件packages.ts
然后在build/utils/paths
下定义打包输出目录
然后我们要将ts
分别打包为cjs
和esm
两种模块规范,所以我们先定义一个配置文件在build/utils
下新建文件config.ts
,代码如下:
import path from "path";
import { outDir } from "./paths";
export const buildConfig = {
esm: {
module: "ESNext", // tsconfig输出的结果es6模块
format: "esm", // 需要配置格式化化后的模块规范
output: {
name: "es", // 打包到dist目录下的那个目录
path: path.resolve(outDir, "es"),
},
bundle: {
path: "z-plus/es",
},
},
cjs: {
module: "CommonJS",
format: "cjs",
output: {
name: "lib",
path: path.resolve(outDir, "lib"),
},
bundle: {
path: "z-plus/lib",
},
},
};
export type BuildConfig = typeof buildConfig;
最后在刚才定义的packages.ts
中处理
// 专门打包util,指令,hook
import { series, parallel, src, dest } from "gulp";
import { buildConfig } from "./utils/config";
import path from "path";
import { outDir, projectRoot } from "./utils/paths";
import ts from "gulp-typescript";
import { withTaskName } from "./utils";
// 打包处理
export const buildPackages = (dirname: string, name: string) => {
const tasks = Object.entries(buildConfig).map(([module, config]) => {
const output = path.resolve(dirname, config.output.name);
// 安装依赖gulp-typescript
return series(
// 处理ts文件
withTaskName(`build${dirname}`, () => {
const tsConfig = path.resolve(projectRoot, "tsconfig.json"); // ts配置文件路径
const inputs = ["**/*.ts", "!gulpfile.ts", "!node_modules"];
return src(inputs)
.pipe(
ts.createProject(tsConfig, {
declaration: true, // 需要生成声明文件
strict: false, // 关闭严格模式
module: config.module,
})()
)
.pipe(dest(output));
}),
withTaskName(`copy:${dirname}`,() => {
// 将打包好的文件放到 es=>utils 和 lib => utils
// 将utils模块拷贝到dist目录下的es和lib目录
return src(`${output}/**`).pipe(dest(path.resolve(outDir,config.output.name,name)))
})
);
});
return parallel(...tasks);
};
处理好后,测试一下,在utils
下执行npm run build
,结果如下:
可以看到在utils
下生成了两个目录es
和lib
,并且copy
到了根目录下的dist
目录中,目录如下:
现在处理好了theme-chalk
和utils
,但是打包的时候我们需要分别到每个目录下执行build
脚本,太麻烦了,我想在根目录下执行build
后,就让它们各自打包,然后把结果输出到我根目录下的dist
目录,所以在根目录下的gulpfile.ts
中增加一个task
,让它帮我分别执行每个目录下的build
在build/gulpfile.ts
中:增加
...
withTaskName("buildPackages",() => run("pnpm run --filter ./packages --parallel build"))
...
然后我们删除根目录下的dist
,在根目录下执行npm run build
,测试一下:
可以看到分别帮我们执行了每个目录下的build
脚本,最终输出到根目录dist
:
到这里,我们的theme-chalk
和utils
的打包就处理完成了,然后我们来处理组件的打包
后续组件打包,其余代码可去gitee查看