Mac电脑:Get笔记 Obsidian 插件 Playwright 模块加载 Bug 修复记录
日期:2026-05-27
插件:get-to-obsidian (Get笔记 Importer) v3.7.1
环境:macOS Apple Silicon + Obsidian 1.12.7
一、问题现象
Get笔记 Obsidian 插件的 Playwright 自动登录功能报错:
Cannot find module 'playwright'
请确保开发目录下或系统全局已执行 'npm install playwright' 且正确下载了浏览器包。
手动 ZIP 导入功能正常,但点击"发送验证码"时始终失败。
二、根因分析
2.1 问题定位
查看插件 main.js 源码,定位到两个关键函数:
initModulePaths()(约 16637 行)和 getPlaywright()(约 16671 行)。
这两个函数负责在运行时动态加载 playwright 模块。逻辑是:
- 先尝试标准
require("playwright") - 如果失败,fallback 到绝对路径加载
- 绝对路径的候选列表中包含一个硬编码的 Windows 路径
2.2 真正的根因
// main.js 第 16655 行 & 第 16683 行(原始代码)
const buildDevDir = typeof process !== "undefined"
? "E:\\GitHub\\get-to-obsidian-main\\get-to-obsidian-enhance"
: null;
这个路径是插件作者本机 Windows 开发目录,在 macOS 上完全不存在。虽然代码也尝试了基于 __dirname 的 fallback(__dirname/node_modules/playwright),但因为:
- 插件目录下没有安装 playwright 的
node_modules - Obsidian 的 Electron 环境可能对
require有限制,eval("require")获取的require函数在 fallback 时也无法正常加载
最终所有候选路径全部失败,抛出 "Cannot find module 'playwright'"。
2.3 为什么其他用户也遇到
这个 hardcoded 路径只对插件作者本人有效。任何其他用户(无论 Windows 还是 macOS)安装插件后,这个路径都不存在。GitHub Issue #1 中有 3 位用户报告了同样的问题。
三、修复步骤
步骤 1:在插件目录安装 playwright
cd "<vault>/.obsidian/plugins/get-importer-sync/"
npm init -y
npm install playwright@1.43.1
这创建了 node_modules/playwright,使得 __dirname/node_modules/playwright 路径生效。
浏览器二进制文件(Chromium)之前已通过 npx playwright@1.43.1 install 下载到 ~/Library/Caches/ms-playwright/chromium-1112/。
步骤 2:全局安装 playwright(双重保险)
npm install -g playwright@1.43.1
全局安装到 ~/.npm-global/lib/node_modules/playwright。
步骤 3:在 Vault 根目录创建 node_modules 软链接
ln -sf "<vault>/.obsidian/plugins/get-importer-sync/node_modules" "<vault>/node_modules"
这样 Node.js 模块解析沿目录树向上查找时也能找到。
步骤 4:修改 initModulePaths() 函数
原始代码问题:硬编码 Windows 路径,且没有全局 npm 路径。
修改内容:
- 移除
buildDevDir2硬编码 Windows 路径逻辑 - 添加全局 npm 安装路径:
/Users/yuyue/.npm-global/lib/node_modules
// 修改后
const globalNodeModules = "/Users/yuyue/.npm-global/lib/node_modules";
if (!modulePaths.includes(globalNodeModules)) {
modulePaths.push(globalNodeModules);
}
步骤 5:修改 getPlaywright() 函数
原始代码问题:
- 使用
eval("require")获取 require 函数,可能在 Electron 沙箱中行为异常 - 硬编码 Windows 路径
- fallback 失败时静默,无调试信息
修改内容:
- 用直接
require(绝对路径)替代eval("require") - 添加全局 npm 路径作为额外候选
- 每个候选路径加载失败时输出详细日志(之前是空 catch 块)
// 修改后的核心逻辑
var candidates = [];
if (typeof __dirname !== "undefined") {
candidates.push(path.join(__dirname, "node_modules", "playwright"));
candidates.push(path.join(__dirname, "..", "node_modules", "playwright"));
candidates.push(path.join(__dirname, "..", "..", "node_modules", "playwright"));
}
candidates.push("/Users/yuyue/.npm-global/lib/node_modules/playwright");
for (var i = 0; i < candidates.length; i++) {
try {
console.log("[ModuleLoader] Attempting fallback load from: " + candidates[i]);
playwrightModule = require(candidates[i]);
console.log("[ModuleLoader] Success! Loaded playwright from: " + candidates[i]);
break;
} catch (err2) {
console.log("[ModuleLoader] Failed: " + candidates[i] + " - " + (err2.message || err2));
}
}
四、当前状态
所有修改已应用到 vault 的插件文件。需要重启 Obsidian 才能生效。
如果重启后仍然失败,打开 Obsidian 开发者控制台(Cmd+Opt+I),查看 [ModuleLoader] 日志,可以看到每个候选路径的加载结果,精确定位失败原因。
五、经验总结
-
永远不要在发布代码中硬编码本机路径。这是一个典型的"在我机器上能跑"问题。应该使用
__dirname、环境变量或配置项来动态获取路径。 -
catch 块不要吞掉错误。原始代码中 fallback 循环的 catch 块完全为空,导致无法排查具体是哪个路径、什么原因导致的失败。添加日志是调试的第一步。
-
了解运行环境的限制。Obsidian 插件运行在 Electron 的沙箱化渲染进程中,
require的能力可能与标准 Node.js 不同。eval("require")这类技巧在某些环境下可能失效。 -
双重通道设计是好架构。这个插件提供了 Playwright(浏览器自动化)和 OpenAPI(REST API)两种同步通道。当 Playwright 通道不可用时,用户可以降级到 OpenAPI 通道,不影响核心功能。
文章来源:dqtx.cc 远程技术支持:742112.xyz

浙公网安备 33010602011771号