update at 2025-10-10 17:00:09

This commit is contained in:
douboer
2025-10-10 17:00:09 +08:00
parent 1309caddc3
commit 86c3beea49
14 changed files with 1248 additions and 81 deletions

View File

@@ -95,8 +95,6 @@
检查样式无误后,点击**复制**按钮,然后到公众号粘贴即可。 检查样式无误后,点击**复制**按钮,然后到公众号粘贴即可。
![](images/20240630221748.jpg)
**★ 公众号** **★ 公众号**
插件支持多公众号,在下拉菜单中进行不同公众号的切换。该功能需要订阅才能使用。 插件支持多公众号,在下拉菜单中进行不同公众号的切换。该功能需要订阅才能使用。
@@ -158,6 +156,15 @@ c=+-sqrt(a^2+b^2)
数学公式的渲染效果可以看这篇文章:[公众号文章里的数学公式排版秘籍](https://mp.weixin.qq.com/s/-kpT2U1gT_5W3TsDCAVgsw)👈️ 数学公式的渲染效果可以看这篇文章:[公众号文章里的数学公式排版秘籍](https://mp.weixin.qq.com/s/-kpT2U1gT_5W3TsDCAVgsw)👈️
### 自定义CSS使用指南 ### 自定义CSS使用指南
## 开发与构建
本仓库的构建脚本分为“未混淆”和“启用混淆”两个版本:
- `npm run build`:生成未混淆的 `main.js`,便于调试。
- `npm run build:obf`:在生产模式下启用 `javascript-obfuscator`,生成混淆后的 `main.js`。
- `./build.sh`:执行默认(未混淆)构建并同步到本地 Obsidian 插件目录。
- `./build.sh obf`:执行混淆构建后再进行同步。
如需自定义混淆行为,可在执行命令时设置环境变量(例如 `OBFUSCATE=1 npm run build:bundle`),详细参数见 `esbuild.config.mjs`。
新建一篇笔记,例如**自定义样式**,直接将如下内容粘贴进笔记: 新建一篇笔记,例如**自定义样式**,直接将如下内容粘贴进笔记:
````CSS ````CSS
@@ -356,7 +363,7 @@ NoteToMP插件支持该语法。
- 你想要把所有标记为 `篆刻` 的文章筛选出来,批量上传到公众号草稿箱并逐条完善后发布。 - 你想要把所有标记为 `篆刻` 的文章筛选出来,批量上传到公众号草稿箱并逐条完善后发布。
- 按文件夹 `content/post` 筛选并批量发布该文件夹下的近期文章。 - 按文件夹 `content/post` 筛选并批量发布该文件夹下的近期文章。
### 详细使用指南(一步步) ### 使用指南
1. 打开模态 1. 打开模态
- 命令面板Ctrl/Cmd+P→ 输入“批量发布文章”,回车打开模态窗口。 - 命令面板Ctrl/Cmd+P→ 输入“批量发布文章”,回车打开模态窗口。
@@ -537,13 +544,6 @@ https://www.bilibili.com/video/BV15XWVeEEJa/
--- ---
``` ```
视频教程https://www.bilibili.com/video/BV15XWVeEEmA/
## 4、反馈交流群
**微信群:**
加微信:**Genius35Plus**,备注:**NoteToMP**
## 附:批量发布 - 快速交互速览与截图占位 ## 附:批量发布 - 快速交互速览与截图占位
如果你想把功能教学放到 README 中,这里是推荐的简短速览(已在模态中实现): 如果你想把功能教学放到 README 中,这里是推荐的简短速览(已在模态中实现):
@@ -559,3 +559,6 @@ https://www.bilibili.com/video/BV15XWVeEEJa/
2. 在 README 中替换占位为图片预览并附带关键交互标注说明。 2. 在 README 中替换占位为图片预览并附带关键交互标注说明。
如果你更愿意手动截屏我也可以把一个标注模板SVG 或说明)发给你,方便手动粘贴到 `images/` 目录。 如果你更愿意手动截屏我也可以把一个标注模板SVG 或说明)发给你,方便手动粘贴到 `images/` 目录。

View File

@@ -2,8 +2,17 @@
set -e # 出错立即退出 set -e # 出错立即退出
# 1. 构建 # 1. 构建
echo "🏗️ 开始构建..." MODE="$1"
if npm run build; then BUILD_CMD=(npm run build)
if [[ "$MODE" == "obf" ]]; then
BUILD_CMD=(npm run build:obf)
echo "🏗️ 开始构建(启用混淆)..."
else
echo "🏗️ 开始构建(不启用混淆)..."
fi
if "${BUILD_CMD[@]}"; then
echo "✅ 构建成功" echo "✅ 构建成功"
echo echo
else else

View File

@@ -75,14 +75,17 @@ git checkout -b release/v1.3.0
### 4. 构建项目 ### 4. 构建项目
构建项目生成生产版本文件 构建项目生成发布所需的产物
```bash ```bash
# 执行项目构建 # 执行未混淆构建(推荐用于验证与调试)
npm run build npm run build
# 检查构建输出 # 检查构建输出
ls -la main.js manifest.json ls -la main.js manifest.json
# 如需生成混淆后的发布包,可执行:
npm run build:obf
``` ```
### 5. 创建归档目录 ### 5. 创建归档目录

View File

@@ -1,6 +1,7 @@
import esbuild from "esbuild"; import esbuild from "esbuild";
import process from "process"; import process from "process";
import builtins from "builtin-modules"; import builtins from "builtin-modules";
import javascriptObfuscatorPlugin from "./tools/esbuild-obfuscator-plugin.mjs";
const banner = const banner =
`/* `/*
@@ -10,6 +11,25 @@ if you want to view the source, please visit the github repository of this plugi
`; `;
const prod = (process.argv[2] === "production"); const prod = (process.argv[2] === "production");
const obfuscate = prod && process.env.OBFUSCATE === "1";
const plugins = [];
if (obfuscate) {
plugins.push(javascriptObfuscatorPlugin({
compact: false,
controlFlowFlattening: false,
deadCodeInjection: false,
debugProtection: false,
disableConsoleOutput: true,
identifierNamesGenerator: "hexadecimal",
log: false,
renameGlobals: false,
simplify: true,
splitStrings: false,
transformObjectKeys: true,
}));
}
const context = await esbuild.context({ const context = await esbuild.context({
banner: { banner: {
@@ -38,6 +58,7 @@ const context = await esbuild.context({
sourcemap: prod ? false : "inline", sourcemap: prod ? false : "inline",
treeShaking: true, treeShaking: true,
outfile: "main.js", outfile: "main.js",
plugins,
}); });
if (prod) { if (prod) {

1020
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,9 @@
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
"dev": "node esbuild.config.mjs", "dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", "build": "npm run build:bundle --",
"build:obf": "OBFUSCATE=1 npm run build:bundle --",
"build:bundle": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"download": "node tools/download.mjs", "download": "node tools/download.mjs",
"version": "node version-bump.mjs && git add manifest.json versions.json" "version": "node version-bump.mjs && git add manifest.json versions.json"
}, },
@@ -18,6 +20,7 @@
"@typescript-eslint/parser": "5.29.0", "@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0", "builtin-modules": "3.3.0",
"esbuild": "0.17.3", "esbuild": "0.17.3",
"javascript-obfuscator": "^4.1.1",
"obsidian": "latest", "obsidian": "latest",
"tslib": "2.4.0", "tslib": "2.4.0",
"typescript": "4.7.4" "typescript": "4.7.4"

View File

@@ -19,6 +19,17 @@ export interface PlatformChooserOptions {
onPlatformChange?: (platform: PlatformType) => Promise<void>; onPlatformChange?: (platform: PlatformType) => Promise<void>;
} }
export interface PlatformActionLabels {
refresh: string;
publish: string;
}
export interface PlatformChooserActions {
onRefresh?: () => void | Promise<void>;
onPublish?: () => void | Promise<void>;
getLabels?: (platform: PlatformType) => PlatformActionLabels;
}
/** /**
* 平台信息接口 * 平台信息接口
*/ */
@@ -48,8 +59,11 @@ const SUPPORTED_PLATFORMS: PlatformInfo[] = [
export class PlatformChooser { export class PlatformChooser {
private container: HTMLElement; private container: HTMLElement;
private selectElement: HTMLSelectElement | null = null; private selectElement: HTMLSelectElement | null = null;
private refreshButton: HTMLButtonElement | null = null;
private publishButton: HTMLButtonElement | null = null;
private currentPlatform: PlatformType; private currentPlatform: PlatformType;
private onChange?: (platform: PlatformType) => void; private onChange?: (platform: PlatformType) => void;
private actions: PlatformChooserActions | null = null;
constructor(container: HTMLElement, options: PlatformChooserOptions = {}) { constructor(container: HTMLElement, options: PlatformChooserOptions = {}) {
this.container = container; this.container = container;
@@ -101,6 +115,16 @@ export class PlatformChooser {
const newPlatform = platformSelect.value as PlatformType; const newPlatform = platformSelect.value as PlatformType;
this.switchPlatformInternal(newPlatform); this.switchPlatformInternal(newPlatform);
}; };
// 刷新按钮
this.refreshButton = this.container.createEl('button', { cls: 'toolbar-button purple-gradient' });
this.refreshButton.onclick = () => this.handleRefreshClick();
// 发布按钮
this.publishButton = this.container.createEl('button', { cls: 'toolbar-button' });
this.publishButton.onclick = () => this.handlePublishClick();
this.updateActionLabels();
} }
/** /**
@@ -123,6 +147,8 @@ export class PlatformChooser {
console.error('[PlatformChooser] 平台切换失败:', error); console.error('[PlatformChooser] 平台切换失败:', error);
} }
} }
this.updateActionLabels();
} }
/** /**
@@ -133,6 +159,7 @@ export class PlatformChooser {
if (this.selectElement) { if (this.selectElement) {
this.selectElement.value = platform; this.selectElement.value = platform;
} }
this.updateActionLabels();
} }
/** /**
@@ -160,5 +187,45 @@ export class PlatformChooser {
this.selectElement.onchange = null; this.selectElement.onchange = null;
this.selectElement = null; this.selectElement = null;
} }
if (this.refreshButton) {
this.refreshButton.onclick = null;
this.refreshButton = null;
}
if (this.publishButton) {
this.publishButton.onclick = null;
this.publishButton = null;
}
}
/**
* 设置通用操作按钮
*/
setActions(actions: PlatformChooserActions): void {
this.actions = actions;
this.updateActionLabels();
}
private handleRefreshClick(): void {
if (!this.actions?.onRefresh) return;
Promise.resolve(this.actions.onRefresh()).catch((error) => {
console.error('[PlatformChooser] 刷新操作失败:', error);
});
}
private handlePublishClick(): void {
if (!this.actions?.onPublish) return;
Promise.resolve(this.actions.onPublish()).catch((error) => {
console.error('[PlatformChooser] 发布操作失败:', error);
});
}
private updateActionLabels(): void {
if (!this.refreshButton || !this.publishButton) return;
const labels = this.actions?.getLabels?.(this.currentPlatform) ?? {
refresh: '🔄 刷新',
publish: '📤 发布',
};
this.refreshButton.innerText = labels.refresh;
this.publishButton.innerText = labels.publish;
} }
} }

View File

@@ -93,6 +93,18 @@ export class PreviewManager {
// 构建 UI // 构建 UI
this.platformChooser.render(); this.platformChooser.render();
// 共享操作按钮
this.platformChooser.setActions({
onRefresh: () => this.refresh(),
onPublish: () => this.publishCurrentPlatform(),
getLabels: (platform) => {
if (platform === 'wechat') {
return { refresh: '🔄 刷新', publish: '📝 发布' };
}
return { refresh: '🔄 刷新', publish: '📤 发布' };
},
});
} }
/** /**
@@ -125,6 +137,22 @@ export class PreviewManager {
this.wechatPreview.build(); this.wechatPreview.build();
} }
private async publishCurrentPlatform(): Promise<void> {
if (this.currentPlatform === 'wechat') {
if (!this.wechatPreview) {
new Notice('微信预览未初始化');
return;
}
await this.wechatPreview.publish();
} else if (this.currentPlatform === 'xiaohongshu') {
if (!this.xhsPreview) {
new Notice('小红书预览未初始化');
return;
}
await this.xhsPreview.publish();
}
}
/** /**
* 创建小红书预览组件 * 创建小红书预览组件
*/ */

View File

@@ -3,7 +3,7 @@
* 作用:通用工具函数集合(事件、版本、字符串处理等)。 * 作用:通用工具函数集合(事件、版本、字符串处理等)。
*/ */
import { App, sanitizeHTMLToDom, requestUrl, Platform } from "obsidian"; import { App, sanitizeHTMLToDom, Platform } from "obsidian";
import * as postcss from "./postcss/postcss"; // 内置 PostCSS runtime解析主题 CSS 用于内联样式 import * as postcss from "./postcss/postcss"; // 内置 PostCSS runtime解析主题 CSS 用于内联样式
let PluginVersion = "0.0.0"; let PluginVersion = "0.0.0";
@@ -185,10 +185,7 @@ export function applyCSS(html: string, css: string) {
} }
export function uevent(name: string) { export function uevent(name: string) {
const url = `https://u.sunboshi.tech/event?name=${name}&platform=${PlugPlatform}&v=${PluginVersion}`; console.debug(`[uevent] ${name} @${PlugPlatform} v${PluginVersion}`);
requestUrl(url).then().catch(error => {
console.error("Failed to send event: " + url, error);
});
} }
/** /**

View File

@@ -134,19 +134,13 @@ export class WechatPreview {
} }
// 操作按钮(直接平铺在 Grid 中) // 操作按钮(直接平铺在 Grid 中)
const refreshBtn = parent.createEl('button', { text: '🔄 刷新', cls: 'toolbar-button purple-gradient' });
refreshBtn.onclick = async () => { if (this.onRefreshCallback) await this.onRefreshCallback(); };
const postBtn = parent.createEl('button', { text: '📝 发布', cls: 'toolbar-button' });
postBtn.onclick = async () => await this.postArticle();
if (Platform.isDesktop && this.settings.isAuthKeyVaild()) { if (Platform.isDesktop && this.settings.isAuthKeyVaild()) {
const htmlBtn = parent.createEl('button', { text: '💾 导出HTML', cls: 'toolbar-button' }); const htmlBtn = parent.createEl('button', { text: '💾 导出HTML', cls: 'toolbar-button' });
htmlBtn.onclick = async () => await this.exportHTML(); htmlBtn.onclick = async () => await this.exportHTML();
} }
// 封面选择 // 封面选择
this.buildCoverSelector(parent); //this.buildCoverSelector(parent);
// 样式选择(如果启用) // 样式选择(如果启用)
if (this.settings.showStyleUI) { if (this.settings.showStyleUI) {
@@ -387,6 +381,16 @@ export class WechatPreview {
/** 对外:发布草稿(供外层菜单调用) */ /** 对外:发布草稿(供外层菜单调用) */
async postDraft() { await this.postArticle(); } async postDraft() { await this.postArticle(); }
async publish(): Promise<void> {
await this.postDraft();
}
async refresh(): Promise<void> {
if (this.onRefreshCallback) {
await this.onRefreshCallback();
}
}
/** 由上层在切换/渲染时注入当前文件 */ /** 由上层在切换/渲染时注入当前文件 */
setFile(file: TFile | null) { this.currentFile = file; } setFile(file: TFile | null) { this.currentFile = file; }
} }

View File

@@ -88,16 +88,8 @@ export class XiaohongshuPreview {
option.text = name; option.text = name;
}); });
const refreshCard = this.createGridCard(board, 'xhs-area-refresh');
const refreshBtn = refreshCard.createEl('button', { text: '🔄 刷新', cls: 'toolbar-button purple-gradient' });
refreshBtn.onclick = () => this.onRefresh();
const publishCard = this.createGridCard(board, 'xhs-area-publish');
const publishBtn = publishCard.createEl('button', { text: '📤 发布', cls: 'toolbar-button' });
publishBtn.onclick = () => this.onPublish();
const previewCard = this.createGridCard(board, 'xhs-area-preview'); const previewCard = this.createGridCard(board, 'xhs-area-preview');
const previewLabel = previewCard.createDiv({ cls: 'xhs-label', text: '预览宽度' }); const previewLabel = previewCard.createDiv({ cls: 'xhs-label', text: '宽度' });
this.previewWidthSelect = previewCard.createEl('select', { cls: 'xhs-select' }); this.previewWidthSelect = previewCard.createEl('select', { cls: 'xhs-select' });
const currentPreviewWidth = this.settings.xhsPreviewWidth || XHS_PREVIEW_DEFAULT_WIDTH; const currentPreviewWidth = this.settings.xhsPreviewWidth || XHS_PREVIEW_DEFAULT_WIDTH;
XHS_PREVIEW_WIDTH_OPTIONS.forEach(value => { XHS_PREVIEW_WIDTH_OPTIONS.forEach(value => {
@@ -121,9 +113,8 @@ export class XiaohongshuPreview {
}; };
const fontCard = this.createGridCard(board, 'xhs-area-font'); const fontCard = this.createGridCard(board, 'xhs-area-font');
fontCard.createDiv({ cls: 'xhs-label', text: '字号' }); //fontCard.createDiv({ cls: 'xhs-label', text: '字号' });
const fontSizeGroup = fontCard.createDiv({ cls: 'font-size-group' }); const fontSizeGroup = fontCard.createDiv({ cls: 'font-size-group' });
const decreaseBtn = fontSizeGroup.createEl('button', { text: '', cls: 'font-size-btn' }); const decreaseBtn = fontSizeGroup.createEl('button', { text: '', cls: 'font-size-btn' });
decreaseBtn.onclick = () => this.changeFontSize(-1); decreaseBtn.onclick = () => this.changeFontSize(-1);
@@ -174,10 +165,10 @@ export class XiaohongshuPreview {
nextBtn.onclick = () => this.nextPage(); nextBtn.onclick = () => this.nextPage();
const sliceCard = this.createGridCard(board, 'xhs-area-slice'); const sliceCard = this.createGridCard(board, 'xhs-area-slice');
const sliceCurrentBtn = sliceCard.createEl('button', { text: '当前页切图', cls: 'xhs-slice-btn' }); const sliceCurrentBtn = sliceCard.createEl('button', { text: '当前页切图', cls: 'xhs-slice-btn' });
sliceCurrentBtn.onclick = () => this.sliceCurrentPage(); sliceCurrentBtn.onclick = () => this.sliceCurrentPage();
const sliceAllBtn = sliceCard.createEl('button', { text: '全部页切图', cls: 'xhs-slice-btn secondary' }); const sliceAllBtn = sliceCard.createEl('button', { text: '全部页切图', cls: 'xhs-slice-btn secondary' });
sliceAllBtn.onclick = () => this.sliceAllPages(); sliceAllBtn.onclick = () => this.sliceAllPages();
} }
@@ -424,6 +415,14 @@ export class XiaohongshuPreview {
} }
} }
async refresh(): Promise<void> {
await this.onRefresh();
}
async publish(): Promise<void> {
await this.onPublish();
}
/** /**
* 全部页切图 * 全部页切图
*/ */

View File

@@ -337,7 +337,7 @@ label:hover { color: var(--c-primary); }
/* 平台选择容器:单层 Grid 排列 */ /* 平台选择容器:单层 Grid 排列 */
.platform-chooser-container.platform-chooser-grid { .platform-chooser-container.platform-chooser-grid {
display: grid; display: grid;
grid-auto-flow: column; grid-template-columns: auto minmax(160px, 1fr) auto auto;
align-items: center; align-items: center;
gap: 12px; gap: 12px;
padding: 8px 12px; padding: 8px 12px;
@@ -347,6 +347,16 @@ label:hover { color: var(--c-primary); }
box-shadow: var(--shadow-sm); box-shadow: var(--shadow-sm);
} }
.platform-chooser-container .toolbar-button {
justify-self: start;
}
@media (max-width: 720px) {
.platform-chooser-container.platform-chooser-grid {
grid-template-columns: repeat(auto-fit, minmax(140px, max-content));
}
}
/* =========================================================== */ /* =========================================================== */
/* 平台选择器样式 */ /* 平台选择器样式 */
/* =========================================================== */ /* =========================================================== */
@@ -467,14 +477,14 @@ label:hover { color: var(--c-primary); }
.xhs-board { .xhs-board {
display: grid; display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr)); grid-template-columns: repeat(6, minmax(0, 1fr));
grid-template-rows: auto auto auto 1fr auto; grid-template-rows: auto auto auto 1fr auto;
grid-template-areas: grid-template-areas:
"platform platform platform refresh publish" "template template preview preview font font"
"template template preview preview font" "content content content content content content"
"content content content content content" "content content content content content content"
"content content content content content" "content content content content content content"
"pagination pagination slice slice slice"; "pagination pagination pagination slice slice slice";
gap: 12px; gap: 12px;
width: 100%; width: 100%;
background: var(--grad-xhs-bg); background: var(--grad-xhs-bg);
@@ -509,6 +519,7 @@ label:hover { color: var(--c-primary); }
background: white; background: white;
font-size: 13px; font-size: 13px;
cursor: pointer; cursor: pointer;
max-width: 100px;
transition: border-color 0.2s ease; transition: border-color 0.2s ease;
} }
@@ -546,7 +557,7 @@ label:hover { color: var(--c-primary); }
.font-size-btn:hover { background: #eaf1fe; } .font-size-btn:hover { background: #eaf1fe; }
.font-size-input { .font-size-input {
width: 60px; width: 35px;
border: none; border: none;
background: transparent; background: transparent;
text-align: center; text-align: center;
@@ -556,17 +567,12 @@ label:hover { color: var(--c-primary); }
.font-size-input:focus { outline: none; } .font-size-input:focus { outline: none; }
.xhs-area-platform,
.xhs-board .platform-chooser-container,
.xhs-board .platform-selector-line {
grid-area: platform;
}
.xhs-area-template { grid-area: template; } .xhs-area-template { grid-area: template; }
.xhs-area-preview { grid-area: preview; } .xhs-area-preview { grid-area: preview; }
.xhs-area-refresh { grid-area: refresh; justify-content: center; } .xhs-area-font {
.xhs-area-publish { grid-area: publish; justify-content: center; } grid-area: font;
.xhs-area-font { grid-area: font; flex-wrap: wrap; } flex-wrap: nowrap;
}
.xhs-area-pagination { grid-area: pagination; justify-content: center; gap: 16px; } .xhs-area-pagination { grid-area: pagination; justify-content: center; gap: 16px; }
.xhs-area-slice { grid-area: slice; justify-content: center; gap: 16px; } .xhs-area-slice { grid-area: slice; justify-content: center; gap: 16px; }
@@ -641,7 +647,7 @@ label:hover { color: var(--c-primary); }
} }
.xhs-page-number-input { .xhs-page-number-input {
width: 56px; width: 35px;
padding: 4px 6px; padding: 4px 6px;
text-align: center; text-align: center;
border: 1px solid var(--c-border); border: 1px solid var(--c-border);

View File

@@ -126,3 +126,4 @@ SOLVEobsidian控制台打印信息定位在哪里阻塞AI修复。
自己写布局demo原型让codex参考布局修改(原来元素美化的css可保留)。 自己写布局demo原型让codex参考布局修改(原来元素美化的css可保留)。
demo原型可以手绘后拍照让chatgpt生成在此基础上自己修改。 demo原型可以手绘后拍照让chatgpt生成在此基础上自己修改。

View File

@@ -0,0 +1,48 @@
import { promises as fs } from "fs";
// Esbuild plugin that optionally obfuscates the emitted bundle with javascript-obfuscator.
export default function javascriptObfuscatorPlugin(obfuscatorOptions = {}) {
let obfuscatorPromise;
const loadObfuscator = async () => {
if (!obfuscatorPromise) {
obfuscatorPromise = import("javascript-obfuscator")
.then((module) => module.default ?? module)
.catch((error) => {
console.warn("[esbuild] javascript-obfuscator unavailable, skipping obfuscation.", error);
return null;
});
}
return obfuscatorPromise;
};
// Default to preserving line breaks unless explicitly overridden.
if (typeof obfuscatorOptions.compact === "undefined") {
obfuscatorOptions.compact = false;
}
return {
name: "javascript-obfuscator",
setup(build) {
build.onEnd(async (result) => {
if (result.errors.length) return;
const outfile = build.initialOptions.outfile;
if (!outfile) return;
try {
const obfuscator = await loadObfuscator();
if (!obfuscator?.obfuscate) return;
const source = await fs.readFile(outfile, "utf8");
const obfuscatedCode = obfuscator
.obfuscate(source, obfuscatorOptions)
.getObfuscatedCode();
await fs.writeFile(outfile, obfuscatedCode, "utf8");
} catch (error) {
console.warn("[esbuild] javascript-obfuscator plugin failed, continuing without obfuscation.", error);
}
});
},
};
}