mirror of
https://github.com/doocs/md.git
synced 2026-08-29 07:31:03 +08:00
chore: build utools plugin (#1037)
This commit is contained in:
@@ -52,3 +52,7 @@ web-ext.config.ts
|
||||
|
||||
# vite-plugin-pwa dev output
|
||||
dev-dist
|
||||
|
||||
# uTools build artifacts
|
||||
apps/utools/dist
|
||||
apps/utools/release
|
||||
|
||||
@@ -121,6 +121,9 @@ pnpm web ext:zip
|
||||
|
||||
# Firefox 扩展打包(how to build Firefox addon)
|
||||
pnpm web firefox:zip # output zip file at in .output/md-{version}-firefox.zip
|
||||
|
||||
# uTools 插件打包
|
||||
pnpm utools:package # output zip file at apps/utools/release/md-utools-v{version}.zip
|
||||
```
|
||||
|
||||
## 🚀 快速搭建私有服务
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# uTools 插件打包指引
|
||||
|
||||
该目录包含将微信 Markdown 编辑器打包为 [uTools](https://u.tools) 插件所需的脚本与配置。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```sh
|
||||
pnpm utools:package
|
||||
```
|
||||
|
||||
该命令将完成以下动作:
|
||||
|
||||
1. 调用 `pnpm --filter @md/web run build:utools` 构建前端资源至 `apps/utools/dist`,该构建将自动使用相对路径,确保在 uTools 的 `file://` 协议下能够正常加载。
|
||||
2. 将仓库根目录的版本号写入 `apps/utools/plugin.json`,保持与主项目同步。
|
||||
3. 从 `public/mpmd/icon-256.png` 拷贝插件图标至 `apps/utools/logo.png`。
|
||||
4. 生成形如 `apps/utools/release/md-utools-vX.Y.Z.zip` 的安装包,可直接导入到 uTools。
|
||||
|
||||
> 注意:命令执行前请确认已安装 pnpm 8+ 与 Node.js 20+,并在仓库根目录执行 `pnpm install` 安装依赖。
|
||||
|
||||
## 手动导入调试
|
||||
|
||||
1. 运行 `pnpm --filter @md/web run build:utools`。
|
||||
2. 打开 uTools,进入插件面板中的「开发者工具」。
|
||||
3. 选择「载入本地插件」,指向 `apps/utools` 目录即可。
|
||||
|
||||
## 目录说明
|
||||
|
||||
- `plugin.json`:uTools 插件的清单文件。
|
||||
- `preload.js`:在 uTools 渲染进程和 Web 前端之间建立通信的脚本,用于处理插件唤起事件。
|
||||
- `dist/`:由 Vite 构建输出的静态资源目录。
|
||||
- `release/`:运行打包命令后生成的插件安装包。
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 257 KiB |
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"pluginName": "微信 Markdown 编辑器",
|
||||
"description": "Markdown 文档自动排版为微信图文,随时在 uTools 中打开使用",
|
||||
"version": "2.0.4",
|
||||
"author": "doocs",
|
||||
"homepage": "https://github.com/doocs/md",
|
||||
"pluginType": "tool",
|
||||
"platform": [
|
||||
"win32",
|
||||
"darwin",
|
||||
"linux"
|
||||
],
|
||||
"logo": "logo.png",
|
||||
"main": "dist/index.html",
|
||||
"preload": "preload.js",
|
||||
"features": [
|
||||
{
|
||||
"code": "wechat-md",
|
||||
"explain": "打开微信 Markdown 编辑器",
|
||||
"cmds": [
|
||||
"微信排版",
|
||||
"Markdown 编辑器",
|
||||
"doocs md"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
(() => {
|
||||
if (typeof window === `undefined`)
|
||||
return
|
||||
|
||||
window.__MD_UTOOLS__ = true
|
||||
|
||||
const enter = (action) => {
|
||||
try {
|
||||
window.utools?.hideMainWindowWhenBlur(false)
|
||||
window.utools?.showMainWindow()
|
||||
window.utools?.setExpendHeight(680)
|
||||
}
|
||||
catch (error) {
|
||||
console.warn(`[md][utools] enter failed`, error)
|
||||
}
|
||||
|
||||
window.postMessage({ type: `utools:enter`, payload: action })
|
||||
}
|
||||
|
||||
const leave = () => {
|
||||
window.postMessage({ type: `utools:leave` })
|
||||
}
|
||||
|
||||
window.utools?.onPluginEnter(enter)
|
||||
window.utools?.onPluginOut(leave)
|
||||
|
||||
window.exports = {
|
||||
'wechat-md': {
|
||||
mode: `none`,
|
||||
args: {
|
||||
enter,
|
||||
leave,
|
||||
},
|
||||
},
|
||||
}
|
||||
})()
|
||||
@@ -9,6 +9,7 @@
|
||||
"build:only": "vite build",
|
||||
"build:h5-netlify": "run-p type-check \"build:h5-netlify:only {@}\" --",
|
||||
"build:h5-netlify:only": "cross-env SERVER_ENV=NETLIFY vite build",
|
||||
"build:utools": "cross-env SERVER_ENV=UTOOLS vite build --outDir ../utools/dist --emptyOutDir",
|
||||
"build:cli": "pnpm run build && npx shx rm -rf packages/md-cli/dist && npx shx rm -rf dist/**/*.map && npx shx cp -r dist packages/md-cli/ && cd packages/md-cli && npm pack",
|
||||
"build:analyze": "cross-env ANALYZE=true vite build",
|
||||
"compile:extension": "pnpm --prefix ./src/extension run compile",
|
||||
|
||||
+44
-34
@@ -12,7 +12,13 @@ import { VitePWA } from 'vite-plugin-pwa'
|
||||
import { VitePluginRadar } from 'vite-plugin-radar'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
const base = process.env.SERVER_ENV === `NETLIFY` ? `/` : `/md/`
|
||||
const isUTools = process.env.SERVER_ENV === `UTOOLS`
|
||||
const base
|
||||
= process.env.SERVER_ENV === `NETLIFY`
|
||||
? `/`
|
||||
: isUTools
|
||||
? `./`
|
||||
: `/md/`
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
@@ -27,39 +33,43 @@ export default defineConfig(({ mode }) => {
|
||||
vueDevTools({
|
||||
launchEditor: env.VITE_LAUNCH_EDITOR ?? `code`,
|
||||
}),
|
||||
VitePWA({
|
||||
registerType: `autoUpdate`,
|
||||
includeAssets: [`favicon.ico`],
|
||||
manifest: {
|
||||
name: `@doocs-md`,
|
||||
short_name: `@doocs-md`,
|
||||
theme_color: `#ffffff`,
|
||||
icons: [
|
||||
{
|
||||
src: `${base}pwa-192x192.png`,
|
||||
sizes: `192x192`,
|
||||
type: `image/png`,
|
||||
},
|
||||
{
|
||||
src: `${base}pwa-512x512.png`,
|
||||
sizes: `512x512`,
|
||||
type: `image/png`,
|
||||
},
|
||||
{
|
||||
src: `${base}pwa-512x512.png`,
|
||||
sizes: `512x512`,
|
||||
type: `image/png`,
|
||||
purpose: `any maskable`,
|
||||
},
|
||||
],
|
||||
},
|
||||
workbox: {
|
||||
maximumFileSizeToCacheInBytes: 6 * 1024 * 1024,
|
||||
},
|
||||
devOptions: {
|
||||
enabled: true,
|
||||
},
|
||||
}),
|
||||
...(!isUTools
|
||||
? [
|
||||
VitePWA({
|
||||
registerType: `autoUpdate`,
|
||||
includeAssets: [`favicon.ico`],
|
||||
manifest: {
|
||||
name: `@doocs-md`,
|
||||
short_name: `@doocs-md`,
|
||||
theme_color: `#ffffff`,
|
||||
icons: [
|
||||
{
|
||||
src: `${base}pwa-192x192.png`,
|
||||
sizes: `192x192`,
|
||||
type: `image/png`,
|
||||
},
|
||||
{
|
||||
src: `${base}pwa-512x512.png`,
|
||||
sizes: `512x512`,
|
||||
type: `image/png`,
|
||||
},
|
||||
{
|
||||
src: `${base}pwa-512x512.png`,
|
||||
sizes: `512x512`,
|
||||
type: `image/png`,
|
||||
purpose: `any maskable`,
|
||||
},
|
||||
],
|
||||
},
|
||||
workbox: {
|
||||
maximumFileSizeToCacheInBytes: 6 * 1024 * 1024,
|
||||
},
|
||||
devOptions: {
|
||||
enabled: true,
|
||||
},
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
nodePolyfills({
|
||||
include: [`path`, `util`, `timers`, `stream`, `fs`],
|
||||
overrides: {
|
||||
|
||||
+3
-1
@@ -21,11 +21,13 @@
|
||||
"lint": "eslint . --fix",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
"postinstall": "simple-git-hooks",
|
||||
"inspector": "pnpx node-modules-inspector"
|
||||
"inspector": "pnpx node-modules-inspector",
|
||||
"utools:package": "node ./scripts/package-utools.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "5.4.1",
|
||||
"@types/node": "^24.6.0",
|
||||
"archiver": "^7.0.1",
|
||||
"cross-env": "^10.1.0",
|
||||
"eslint": "^9.36.0",
|
||||
"eslint-plugin-format": "^1.0.2",
|
||||
|
||||
Generated
+7
-10
@@ -14,6 +14,9 @@ importers:
|
||||
'@types/node':
|
||||
specifier: ^24.6.0
|
||||
version: 24.6.0
|
||||
archiver:
|
||||
specifier: ^7.0.1
|
||||
version: 7.0.1
|
||||
cross-env:
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0
|
||||
@@ -6928,10 +6931,6 @@ packages:
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
lru-cache@11.2.1:
|
||||
resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
lru-cache@11.2.2:
|
||||
resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==}
|
||||
engines: {node: 20 || >=22}
|
||||
@@ -10145,7 +10144,7 @@ snapshots:
|
||||
bidi-js: 1.0.3
|
||||
css-tree: 3.1.0
|
||||
is-potential-custom-element-name: 1.0.1
|
||||
lru-cache: 11.2.1
|
||||
lru-cache: 11.2.2
|
||||
|
||||
'@asamuzakjp/nwsapi@2.3.9': {}
|
||||
|
||||
@@ -17580,15 +17579,13 @@ snapshots:
|
||||
ansi-escapes: 7.0.0
|
||||
cli-cursor: 5.0.0
|
||||
slice-ansi: 7.1.0
|
||||
strip-ansi: 7.1.0
|
||||
strip-ansi: 7.1.2
|
||||
wrap-ansi: 9.0.0
|
||||
|
||||
longest-streak@3.1.0: {}
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
lru-cache@11.2.1: {}
|
||||
|
||||
lru-cache@11.2.2: {}
|
||||
|
||||
lru-cache@5.1.1:
|
||||
@@ -20861,7 +20858,7 @@ snapshots:
|
||||
npm-run-path: 6.0.0
|
||||
picocolors: 1.1.1
|
||||
picomatch: 4.0.3
|
||||
strip-ansi: 7.1.0
|
||||
strip-ansi: 7.1.2
|
||||
tiny-invariant: 1.3.3
|
||||
tinyglobby: 0.2.14
|
||||
vite: 7.1.7(@types/node@24.6.0)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
|
||||
@@ -21485,7 +21482,7 @@ snapshots:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.3
|
||||
string-width: 7.2.0
|
||||
strip-ansi: 7.1.0
|
||||
strip-ansi: 7.1.2
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawn } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import { cp, mkdir, readFile, rm, writeFile, access } from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
import archiver from 'archiver'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const rootDir = path.resolve(__dirname, `..`)
|
||||
const utoolsDir = path.join(rootDir, `apps`, `utools`)
|
||||
const distDir = path.join(utoolsDir, `dist`)
|
||||
const releaseDir = path.join(utoolsDir, `release`)
|
||||
const iconSource = path.join(rootDir, `public`, `mpmd`, `icon-256.png`)
|
||||
const iconTarget = path.join(utoolsDir, `logo.png`)
|
||||
const manifestPath = path.join(utoolsDir, `plugin.json`)
|
||||
|
||||
const command = process.platform === `win32` ? `pnpm.cmd` : `pnpm`
|
||||
|
||||
function run(command, args, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(command, args, { stdio: `inherit`, ...options })
|
||||
child.on(`close`, (code) => {
|
||||
if (code === 0)
|
||||
resolve(code)
|
||||
else
|
||||
reject(new Error(`${[command, ...args].join(` `)} exited with code ${code}`))
|
||||
})
|
||||
child.on(`error`, reject)
|
||||
})
|
||||
}
|
||||
|
||||
async function ensureFileExists(filePath, friendlyName) {
|
||||
try {
|
||||
await access(filePath, fs.constants.F_OK)
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error(`${friendlyName ?? filePath} 不存在,请确认路径是否正确。`)
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const pkg = JSON.parse(await readFile(path.join(rootDir, `package.json`), `utf8`))
|
||||
const version = pkg.version
|
||||
|
||||
console.log(`> 构建 uTools 前端资源(version: ${version})`)
|
||||
await run(command, [`--filter`, `@md/web`, `run`, `build:utools`], { cwd: rootDir })
|
||||
|
||||
await ensureFileExists(distDir, `apps/utools/dist`)
|
||||
await ensureFileExists(manifestPath, `apps/utools/plugin.json`)
|
||||
await ensureFileExists(iconSource, `public/mpmd/icon-256.png`)
|
||||
|
||||
const manifest = JSON.parse(await readFile(manifestPath, `utf8`))
|
||||
manifest.version = version
|
||||
await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + `\n`, `utf8`)
|
||||
|
||||
await cp(iconSource, iconTarget)
|
||||
|
||||
await rm(releaseDir, { recursive: true, force: true })
|
||||
await mkdir(releaseDir, { recursive: true })
|
||||
|
||||
const packageName = `md-utools-v${version}`
|
||||
const packageRoot = path.join(releaseDir, packageName)
|
||||
await rm(packageRoot, { recursive: true, force: true })
|
||||
await mkdir(packageRoot, { recursive: true })
|
||||
|
||||
await cp(distDir, path.join(packageRoot, `dist`), { recursive: true })
|
||||
|
||||
for (const file of [`plugin.json`, `preload.js`, `logo.png`, `README.md`]) {
|
||||
const source = path.join(utoolsDir, file)
|
||||
await ensureFileExists(source, `apps/utools/${file}`)
|
||||
await cp(source, path.join(packageRoot, file), { recursive: true })
|
||||
}
|
||||
|
||||
const zipPath = path.join(releaseDir, `${packageName}.zip`)
|
||||
await new Promise((resolve, reject) => {
|
||||
const output = fs.createWriteStream(zipPath)
|
||||
const archive = archiver(`zip`, { zlib: { level: 9 } })
|
||||
|
||||
output.on(`close`, resolve)
|
||||
archive.on(`error`, reject)
|
||||
|
||||
archive.pipe(output)
|
||||
archive.directory(packageRoot, false)
|
||||
archive.finalize()
|
||||
})
|
||||
|
||||
console.log(`✔ uTools 插件打包完成 => ${path.relative(rootDir, zipPath)}`)
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error)
|
||||
process.exitCode = 1
|
||||
})
|
||||
Reference in New Issue
Block a user