用 unplugin-starter 写一个系统推送打包结果通知的插件,顺便蹭了个PR等待打包的过程总是漫长又无聊,如果
前言
等待打包的过程总是漫长又无聊,如果你也想在打包的时候摸摸鱼又不想一直盯着CLI惦记着打包好了没,那你可以试试unplugin-build-notifier (github.com) 这款跨平台的插件, 它能提供系统推送通知,让你第一时间知道打包结果,在一定程度缓解了等待打包过程的无聊和焦虑,以下是Windows系统的通知推送截图
特点
- 💚 跨平台的系统通知,由 node-notifier 提供支持
- ✨ 自动获取项目名称
- 📂 自动打开文件资源管理器
- 🔧 可配置的消息和点击行为
- 🚀 获取构建时间
- ⚡️ 支持 Vite、Webpack、Rspack、Vue CLI、Rollup、esbuild 等,由 unplugin 提供支持
- 🦾 完全支持 TypeScript
安装
npm i unplugin-build-notifier -D
yarn add unplugin-build-notifier -D
pnpm add unplugin-build-notifier -D
使用示例
Vite// vite.config.ts
import BuildNotifier from 'unplugin-build-notifier/vite'
export default defineConfig({
plugins: [
BuildNotifier({ /* options */ }),
],
})
Example: playground/
// rollup.config.js
import BuildNotifier from 'unplugin-build-notifier/rollup'
export default {
plugins: [
BuildNotifier({ /* options */ }),
],
}
Webpack
// webpack.config.js
module.exports = {
/* ... */
plugins: [
require('unplugin-build-notifier/webpack')({ /* options */ })
]
}
Nuxt
// nuxt.config.js
export default defineNuxtConfig({
modules: [
['unplugin-build-notifier/nuxt', { /* options */ }],
],
})
Vue CLIThis module works for both Nuxt 2 and Nuxt Vite
// vue.config.js
module.exports = {
configureWebpack: {
plugins: [
require('unplugin-build-notifier/webpack')({ /* options */ }),
],
},
}
esbuild
// esbuild.config.js
import { build } from 'esbuild'
import BuildNotifier from 'unplugin-build-notifier/esbuild'
build({
plugins: [BuildNotifier()],
})
核心代码
该项目基于unplugin的起始模板 unplugin-starter(github.com) 进行开发,已经开源 github 并发布npm包,核心代码都在src/index.ts
中,下面简单介绍一下代码实现
1.路径处理
首先需要获取到项目根路径,用于展示项目名称和项目路径(用于区分同名项目),以及启动该目录下的文件资源管理器。
项目根路径主要通过import.meta.url
获取到安装依赖后的路径,然后向上查找node_modules
目录来确定。
这里有个小细节是如果使用pnpm安装依赖,那么依赖会被安装在.pnpm
目录下,再通过软连接的方式放到node_modules主目录中,所以获取到的实际目录是在.pnpm下,这里可能会有很多层node_modules,我们可以直接返回到.pnpm目录后再向上查找到真正的项目根目录
import { dirname, join, sep } from 'node:path'
import { fileURLToPath } from 'node:url'
// 依赖包当前路径
const __dirname = dirname(fileURLToPath(import.meta.url))
// 项目根路径
const rootPath = findNodeModules(__dirname)
function findNodeModules(dir: string): string {
const pathArr = dir.split(sep)
const pnpmIndex = pathArr.lastIndexOf('.pnpm')
const nodeModuleIndex = pathArr.lastIndexOf('node_modules', pnpmIndex)
return join(...pathArr.slice(0, nodeModuleIndex))
}
2.跨平台打开项目文件夹
根据不同的操作系统,使用相关命令来打开根目录文件夹
-
对于 macOS('darwin'),使用
'open'
。 -
对于 Windows('win32'),使用
'start'
。 -
对于其他平台(主要是 Linux),使用
'xdg-open'
。
import { exec } from 'node:child_process'
import { platform } from 'node:os'
// 获取当前系统指令
function getOpenCommand() {
switch (platform()) {
case 'darwin':
return 'open'
case 'win32':
return 'start'
default:
return 'xdg-open'
}
}
// 打开项目根目录
function startdir() {
exec(`${getOpenCommand()} "" "${rootPath}"`, (error, stdout, stderr) => {
if (error) {
console.error(
`exec error: ${error}\nstdout: ${stdout}\nstderr: ${stderr}`,
)
}
})
}
3.编写推送通知功能
推送通知功能主要由node-notifier
实现,该库本身具有跨平台简单易用的特点所以非常合适,这里我们对Options进行定义和一些默认配置。
types.ts
export interface Options {
message?: string
iconPath?: string
click?: () => void
timeout?: () => void
}
index.ts
import { basename } from 'node:path'
import notifier from 'node-notifier'
import type { Options } from './types'
function nodeNotifier({
message = '',
iconPath = '',
click = startdir,
timeout = startdir,
}: Options = {}) {
notifier.notify({
title: `✨ ${basename(rootPath)}`,
message: `${message}\n${rootPath}`,
icon: iconPath || join(__dirname, './SpongeBob.jpg'),
})
notifier.on('click', click)
notifier.on('timeout', timeout)
}
tsup.config.ts
引入图片目录需要在tsup.config中声明,否则不会打包进去,本示例将图片放置于/src/public
中
export default <Options>{
publicDir: './src/public',
}
4.插件定义
这里展示的消息会默认显示打包时长,当然,你可以自定义你的消息和交互行为
export const unpluginFactory: UnpluginFactory<Options | undefined> = (
options,
) => {
let buildStart: number
return {
name: 'unplugin-build-notifier',
buildStart() {
buildStart = performance.now()
},
writeBundle() {
const buildTime = ((performance.now() - buildStart) / 1000).toFixed(2)
nodeNotifier({
message: `🎉 build success!\n🚀 built in ${buildTime}s`,
...options,
})
},
}
}
5.打包测试(蹭PR)
直接 pnpm build 打包后在playground中引入测试即可,测试完vite项目后以为一切顺利,可是当测试vue-cli也就是webpack构建的cjs项目时出现以下报错,也可以直接查看Pull Request #28(github.com)的相关描述
const { defineConfig } = require('@vue/cli-service')
const Unplugin = require('../../dist/webpack.cjs')
console.log({ Unplugin })
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
plugins: [
Unplugin(),
],
},
})
看了console.log和ERROR后,发现我导入的Unplugin是一个具有default属性的对象而不是一个函数,于是我就去看了打包产物webpack.cjs
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var webpack_exports = {};
__export(webpack_exports, {
default: () => webpack_default
});
module.exports = __toCommonJS(webpack_exports);
...
var webpack_default = (0, import_unplugin2.createWebpackPlugin)(unpluginFactory);
可以看到webpack_default
是我需要默认导出的函数,而这里的默认导出实际就等于module.exports = { default: () => webpack_default }
,所以我需要require('../../dist/webpack.cjs').default才能拿到我正在的Unplugin函数,可这不是我想要的,于是就去tsup
的github中翻到这条issues#572(github.com),解决方案就是在tsup.config中添加以下配置,于是就顺便的蹭了unplugin-starter 一个 PR
export default <Options>{
+ cjsInterop: true,
+ splitting: true,
...,
}
- 发布npm包
直接使用 unplugin-starter 默认的指令 pnpm release 即可自动发布更新npm包,该项目集成了CI且使用bumpp进行交互式的自动版本号更新,生成git提交等,体验相当好
"release": "bumpp && npm publish"
总结
unplugin-build-notifier (github.com)是一个增加开发体验的简单插件,能够通过系统推送打包结果通知,在一定程度缓解了等待打包过程的无聊和焦虑,如果对你有帮助的话,麻烦点个赞或stars吧~
转载自:https://juejin.cn/post/7374308419073884169