欢迎光临
我们一直在努力

Electron 多进程下的“库引入“全解析:核心模块、Electron API、第三方依赖与 utilityProcess 的依赖处理

很多人写 Electron 时对 require 的认知还停留在"装了包就能 require"。但 Electron 是一个多进程模型,一旦涉及主进程、渲染进程、utilityProcess、再叠加打包后的目录变化,require 能不能成功就变成了两个完全不同维度的问题:

  • 路径维度:这个模块的文件到底在不在我能解析到的地方?(解析问题,可修)
  • 身份维度:这个能力到底属不属于"我这个进程"?(进程边界问题,不可修,只能换进程)

这篇文档把 Electron 里会遇到的五类"库"逐一拆开讲清楚,并结合本 demo 的真实代码,讲透:把这些文件放到安装包之外(比如用户数据目录)后,怎么处理才能让它们跑起来,以及 webpack 打包时必须注意的点。


一、先建立正确的心智模型:三种进程不是"同一个 Node"

Electron 不是"一个 Node 进程里跑了个浏览器"。它是 Chromium 的多进程架构,每个进程内嵌了 Node 运行时(V8 + libuv),但进程身份不同,能拿到的 native 绑定就不同。

进程本质Node 运行时Electron 主进程 API(app/net/session…)
主进程 main Chromium 的 browser process(根进程) ✅ 完整 ✅ 完整
渲染进程 renderer Chromium 渲染进程 ⚠️ 默认关闭,可开启 ⚠️ 受限(主要是 ipcRenderer 等)
utilityProcess Chromium Services 子进程 ✅ 完整 ❌ 几乎只有 process.parentPort

记住一句话贯穿全文:

能不能用 Node 生态 → 看模块在不在能被解析到的 node_modules(路径问题)。 能不能用 Electron 能力 → 看你是不是那个持有 Chromium 子系统的进程(身份问题)。


二、五类库逐一拆解

1. Node.js 核心模块(内置模块)

例子:path fs http https net module crypto os url child_process…

特征:它们被编译进了 Electron 二进制本身,require('path') 根本不碰文件系统,直接从二进制内部的模块表返回。

结论:

  • 在任何进程(main / renderer 开了 nodeIntegration / utilityProcess)里都能用。
  • 不管脚本文件被搬到哪(安装目录、asar、用户数据目录、临时目录),永远解析得到。
  • 它跟 node_modules 没有任何关系,也跟 NODE_PATH 无关。

本 demo 的 utility-server.js 里 require('http')、require('module')、require('path') 之所以"搬到用户目录也能用",就是因为它们是核心模块。

⚠️ 易混点:net 这个名字同时存在两套东西——Node 自带的 require('net')(裸 TCP/IPC socket,核心模块,到处能用)和 Electron 的 require('electron').net(基于 Chromium 网络栈的 HTTP 客户端,主进程专属)。名字一样,性质天差地别,见下一节。


2. Electron 扩展库(主进程专属 API)

例子:app BrowserWindow session net(electron 的) dialog protocol ipcMain Menu Tray globalShortcut…

特征:这些不是普通可被搬运的 JS 库,而是指向"正在运行的 browser process"内部 native 对象的绑定(handle):

  • app 绑定的是这个进程的生命周期和 Chromium 消息循环;
  • net(electron)绑定的是 browser process 里那个唯一的网络服务实例,要走系统代理、复用 session 的 cookie;
  • session / BrowserWindow 绑定的是窗口与会话子系统。

这些对象只在主进程这一个进程里存在。

结论:

  • 只能在主进程里用。
  • 即使在 utilityProcess 里 require('electron'),也拿不到这些 handle —— 因为它本身就不是那个持有这些对象的进程。这不是"包没装",搬库也搬不过来。
  • 在 utilityProcess 里需要这些能力时:让主进程调用,结果通过 process.parentPort 回传。本 demo 的 deep-link 转发就是这个模式——所有 Electron 侧的事(fork、建管道、协议注册)都在主进程,utility 只管业务。

// ❌ 在 utilityProcess 里这样做,net 是 undefined
const { net } = require('electron')

// ✅ utilityProcess 里只能用 Node 自带的网络能力
const http = require('http') // 或 https / net(node)


3. 渲染进程可开启的库(nodeIntegration / contextIsolation)

渲染进程默认是一个纯浏览器环境,没有 require、没有 Node。能否在 renderer 里 require 取决于 BrowserWindow 的 webPreferences:

配置效果安全性
nodeIntegration: false(默认) renderer 里没有 require/process/Buffer ✅ 安全,推荐
nodeIntegration: true renderer 里可直接 require('fs') 等 ❌ 危险,加载远程内容时等于把 Node 暴露给网页
contextIsolation: true(默认) preload 与页面 JS 隔离上下文 ✅ 安全,推荐

推荐做法(也是 Electron 官方方向):renderer 不开 nodeIntegration,需要的 Node/Electron 能力通过 preload + contextBridge 白名单暴露,或走 ipcRenderer → ipcMain 让主进程代劳。

// preload.js —— 只把需要的能力按白名单暴露给渲染层
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('api', {
handleProtocol: url => ipcRenderer.invoke('protocol:handle', url)
})

关键认知:renderer 的"业务依赖"(Vue、axios 等)不是靠运行时 require('node_modules') 来的,而是 webpack 在构建时直接打进了 renderer bundle。所以 renderer 反而最"自包含",它不依赖 NODE_PATH,依赖的是资源路径对不对(见第四节)。


4. 第三方库(npm 依赖,住在 node_modules)

例子:本 demo 的 express axios vue。

特征:它们是真实存在于 node_modules 里的文件,require('express') 走 Node 的文件系统解析算法:从脚本所在目录开始,逐级向上找 node_modules/express。

结论:

  • 这是纯路径问题。脚本旁边能向上找到 node_modules/express 就成功,找不到就报 Cannot find module 'express'。
  • 打包后这个目录关系经常被破坏(asar、用户目录热更新等),需要手动修复解析路径,见第三、四节。

但这里有个分叉,取决于 webpack 怎么处理它(见第五节):

  • 如果 webpack 把第三方库打进 bundle(renderer 通常如此)→ 运行时根本不 require,无所谓 node_modules。
  • 如果 webpack 把它列为 external(本 demo 主进程/utility 如此)→ 产物里保留了运行时 require('express'),那就必须保证运行时能解析到 node_modules。

5. utilityProcess 进程里的库

utilityProcess 是被主进程 utilityProcess.fork(scriptPath, args, options) 拉起的轻量 Node 子进程。它的依赖能力等于:

Node 核心模块(永远有) + 能被解析到的 node_modules 里的第三方库(要修路径) + 几乎为零的 Electron API(只有 parentPort)

本 demo 的 utility-server.js 是一个独立打包入口,它要用 express,于是问题就来了:当这个脚本被放到用户数据目录后,它旁边没有 node_modules,怎么 require('express')?

答案就是下一节的核心。


三、把文件放到"安装包之外"后,怎么让它跑起来

本 demo 已经实现了 utility-server 脚本的"用户目录优先 + 热更新"。核心代码在 src/main/index.js。拆开看它解决了两件事。

3.1 文件本身:脚本放哪、优先用哪个

utilityProcess.fork() 要的是一个真实可访问的 JS 文件路径。demo 的策略是"用户目录有就用用户目录的,否则用包内的":

function resolveUserInstallUtilityServerPath() {
// %APPDATA%/electron-demo/utility-process/utility-server.js
return path.join(app.getPath('userData'), 'utility-process', 'utility-server.js')
}

function resolveUtilityServerStartPath(bundledServicePath) {
const userServicePath = resolveUserInstallUtilityServerPath()
if (fs.existsSync(userServicePath)) {
return userServicePath // 用户目录热更新脚本优先
}
return bundledServicePath // 回落到安装包内 dist/electron/server/utility-server.js
}

包内脚本也要多路径兜底,因为开发态、–dir、asar 后的 __dirname 不一样:

function resolveBundledUtilityServerPath() {
const candidates = [
path.resolve(__dirname, UTILITY_SERVER_BUNDLE),
path.resolve(__dirname, '..', UTILITY_SERVER_BUNDLE),
path.resolve(app.getAppPath(), 'dist', 'electron', UTILITY_SERVER_BUNDLE),
path.resolve(app.getAppPath(), UTILITY_SERVER_BUNDLE)
]
const servicePath = candidates.find(c => fs.existsSync(c))
if (!servicePath) throw new Error(`utility server bundle not found…`)
return servicePath
}

3.2 依赖解析:用户目录脚本怎么找到包内的 node_modules

这是整个方案最关键、最容易踩坑的地方。脚本搬到用户目录后,它旁边没有 node_modules,但当前安装包里有(通常在 app.asar/node_modules)。主进程要把这个路径注入给子进程。

第一步,主进程多路径找到当前安装包的 node_modules:

function resolveUtilityServerNodePath() {
const candidates = [
path.resolve(app.getAppPath(), 'node_modules'), // 开发态 / app 解包
path.resolve(process.resourcesPath || '', 'app.asar', 'node_modules'),// 打包后 asar
path.resolve(process.resourcesPath || '', 'app', 'node_modules'), // asar 解包
path.resolve(__dirname, '..', '..', 'node_modules'),
path.resolve(__dirname, '..', 'node_modules')
]
return candidates.find(c => c && fs.existsSync(c))
}

第二步,fork 时通过 env 自定义变量把这个路径传给子进程(注意 cwd 也指到脚本目录):

const nodePath = resolveUtilityServerNodePath()
if (!nodePath) {
throw new Error(`utility server node_modules path not found…`)
}

protocolServiceProcess = utilityProcess.fork(servicePath, [PIPE_NAME], {
cwd: path.dirname(servicePath),
env: {
process.env,
UTILITY_SERVER_NODE_PATH: nodePath // ⭐ 业务自定义变量,不是直接塞 NODE_PATH
},
stdio: 'pipe'
})

第三步,子进程脚本在 require 第三方库之前,用 Node 核心模块 module 把这个路径注册进解析算法:

// dist/electron/server/utility-server.js 开头
const Module = require('module') // 核心模块,一定找得到
const path = require('path')

const utilityServerNodePath = process.env.UTILITY_SERVER_NODE_PATH
if (utilityServerNodePath) {
process.env.NODE_PATH = utilityServerNodePath
Module._initPaths() // ⭐ 重新初始化解析路径
}

const express = require('express') // 必须在 _initPaths 之后!
const http = require('http')

为什么这么绕?三个细节:

  • 顺序不能反:require('express') 必须在 Module._initPaths() 之后。webpack 产物里这段是手写在最前面、独立于 webpack 模块系统的引导代码,确保解析路径先就位。
  • 不要只在 env 里直接传 NODE_PATH。实测发现,对"用户目录脚本"这个场景,fork 时直接给 env 设 NODE_PATH 并不可靠,子进程启动后 require('express') 仍可能找不到 app.asar/node_modules。更稳的是传一个业务自定义变量(UTILITY_SERVER_NODE_PATH),进程内自己 process.env.NODE_PATH = … + Module._initPaths(),时机完全可控。
  • express 等依赖在 asar 里能被 require。Electron 给 Node 的 fs/模块解析打了补丁,app.asar 会被当成虚拟目录,所以 app.asar/node_modules/express 是能正常 require 的,不需要把依赖解包。
  • 3.3 验证:用 /health 自证从哪启动、依赖路径是什么

    排查这类问题,光看"能不能跑"不够,要让服务自己报告它的处境。demo 的 /health 返回了关键字段:

    app.get('/health', (req, res) => {
    res.json({
    startedFrom: __filename, // 证明从用户目录还是包内启动
    cwd: process.cwd(), // 证明 fork 的工作目录
    utilityServerNodePath: process.env.UTILITY_SERVER_NODE_PATH || '' // 证明注入的依赖路径
    })
    })

    • 用户目录热更新生效时,startedFrom 应指向 %APPDATA%/electron-demo/utility-process/utility-server.js。
    • utilityServerNodePath 应指向当前安装包的 app.asar/node_modules。

    3.4 渲染进程放到安装包之外,处理方式完全不同

    注意:renderer 的"用户目录优先/热更新"和 utility-server 不是一回事。

    • utility-server 是被 fork 当 Node 脚本跑的 → 要解决"依赖在哪"(NODE_PATH)。
    • renderer 是被主进程 win.loadFile(…) 加载进 BrowserWindow 的页面 → 它的业务依赖已被 webpack 打进 bundle,不需要 node_modules;要解决的是"资源相对路径/协议对不对"。

    所以 renderer 的热更新形态是:把构建好的 renderer 目录放用户目录 → 主进程检测到就 loadFile(用户目录/index.html),否则 loadFile(包内/index.html)。两者结构同构(用户目录优先),但触发机制不同(fork vs loadFile),要解决的根因也不同(依赖解析 vs 资源路径)。并且无论哪种,utilityProcess 只能由主进程启动,renderer 不能自己 fork,主进程都绕不开。


    四、一张表收口:遇到 require 报错该往哪查

    报错/现象属于哪类根因怎么修
    Cannot find module 'path'/'http' 核心模块 几乎不可能,除非进程类型不对 检查是不是在浏览器纯环境里跑
    utilityProcess 里 electron.net 是 undefined Electron 扩展库 进程身份问题,utility 不是主进程 改用 Node 的 http/net,或主进程代劳 + parentPort
    renderer 里 require is not defined 渲染进程库 nodeIntegration 没开(且不该开) 用 preload + contextBridge / ipc
    用户目录脚本 Cannot find module 'express' 第三方库 旁边没有 node_modules,解析失败 注入 NODE_PATH + Module._initPaths()
    打包后 utility server bundle not found 文件路径 asar 后 __dirname 变了 多 candidate 路径兜底 fs.existsSync

    五、webpack 打包时的注意事项

    本 demo 主进程和 utility 用 .electron-vue/configs/webpack.main.config.js 打包,几个点必须注意。

    5.1 utility 脚本要作为独立入口打包

    utilityProcess.fork() 需要一个真实文件。开发态直接指向 src/main/utility-server.js 可能能跑,但生产包目录结构变化后极易找不到。所以把它配成独立 entry,输出到固定子目录:

    entry: {
    main: path.join(__dirname, '../../src/main/index.js'),
    'utility-server': path.join(__dirname, '../../src/main/utility-server.js')
    },
    output: {
    filename: pathData => {
    if (pathData.chunk?.name === utilityServerBundle.entryName) {
    return utilityServerBundle.relativeOutputPath // server/utility-server.js
    }
    return '[name].js'
    },
    library: { type: 'commonjs2' }, // 产物是 CommonJS,能被 fork 当 Node 脚本跑
    path: electronDistDir
    }

    入口路径还通过 DefinePlugin 注入成常量 __UTILITY_SERVER_BUNDLE__,主进程用它来定位脚本,避免硬编码字符串。

    5.2 第三方依赖列为 externals,不要打进 bundle

    这是主进程/utility 打包与 renderer 最大的区别:

    const { dependencies } = require('../../package.json')

    externals: [
    Object.keys(dependencies || {}) // express / axios / vue 全部 external
    ],

    含义:webpack 不把 express 打进 bundle,产物里保留运行时 require('express')(你能在产物里看到 module.exports = require("express") 这样的 external 包装)。

    • 好处:bundle 小、原生模块(.node)不会被 webpack 破坏、依赖走 Node 真实解析。
    • 代价:运行时必须能解析到 node_modules —— 这正是第三节 NODE_PATH 方案存在的原因。
    • 推论:凡是列进 dependencies 的,运行时都得在 node_modules 里真实存在;凡是只在构建期用的,放 devDependencies,不会进 externals。本 demo 里 express/axios/vue/vue-electron 在 dependencies,所以会随安装包进 app.asar/node_modules。

    5.3 target 要选对

    target: 'electron-main' // 主进程/utility 用这个

    • 主进程 / utility:electron-main,webpack 会把 Node 核心模块和 electron 当外部依赖,不去 polyfill。
    • 渲染进程:electron-renderer 或 web,并把 Vue 等依赖打进 bundle(renderer 不用 externals 那套),所以 renderer 产物自包含,依赖的是资源路径而非 node_modules。

    5.4 原生模块 / .node 文件

    module: { rules: [{ test: /\\.node$/, use: 'node-loader' }] }

    涉及原生 .node 的依赖更要走 externals + node-loader,绝不能让 webpack 试图把二进制打进 bundle。

    5.5 electron-builder 的 files 要包含产物

    "build": {
    "files": ["dist/electron/**/*"] // 确保 server/utility-server.js 被打进安装包
    }

    否则 fork 时 resolveBundledUtilityServerPath() 在包内根本找不到脚本。


    六、渲染进程"放哪都能用"的真正条件

    经常有人得出这样一个结论:

    “渲染进程开启了 node 集成、上下文不隔离、Vue 又打进了 renderer,那这个 renderer 放哪都能用。”

    这个因果是错配的。 让 renderer 自包含/可搬运的,只有"打进 bundle"这一件事,跟 nodeIntegration、contextIsolation 没有任何关系。

    条件跟"放哪都能用"有关吗
    开启 node 集成 ❌ 无关,甚至有反作用(见下)
    上下文不隔离 ❌ 无关,纯安全设置
    Vue 等打进 renderer bundle ✅ 这才是自包含的唯一原因

    Vue 能用,是因为 webpack 在构建时把它的代码直接塞进了 renderer 的 JS bundle,运行时根本不发生 require('vue')、不碰 node_modules。这件事在 nodeIntegration 关闭时一样成立。

    6.1 nodeIntegration 开启反而是新的"不可搬运"风险

    很反直觉但很关键:开 node 集成的意义是"让页面能 require",而一旦你真的去 require 一个没被打进 bundle 的第三方 node 库,你就立刻把第四类库的"路径解析问题"引回了 renderer。

    // renderer 里开了 nodeIntegration 后:
    const fs = require('fs') // ✅ 核心模块,在二进制里,搬哪都行
    const express = require('express') // ⚠️ 运行时解析!旁边没有 node_modules 就炸

    • 只 require Node 核心模块 → 还能搬。
    • 运行时 require 外部 npm 库(没打进 bundle 的)→ 又回到"必须能解析到 node_modules",反而变得不可搬运。

    所以真正可搬运的 renderer,是"什么都打进 bundle、运行时不做任何外部 require"的 renderer——这种情况下你压根不需要开 node 集成。开了又去用外部库,是在给自己制造搬运障碍;何况 contextIsolation:false + nodeIntegration:true 是公认的安全反模式,加载任何不完全可信的内容时等于把 Node 暴露给页面。

    6.2 即便 bundle 自包含,"放哪都行"还有两个边界

  • renderer 不能自己跑。 它不是可执行程序,是一张要被 BrowserWindow 加载的页面。无论放哪,都必须由主进程 win.loadFile(那个路径) 指过去。"放在用户目录"只改了文件位置,加载动作仍由主进程发起——主进程绕不开。
  • 资源相对路径 / publicPath 要对。 通过 file:// 加载时,HTML 引用的 JS/CSS/图片/字体路径必须仍能解析到。如果 webpack 用了绝对 publicPath 或假设了固定 base,换目录就会白屏/404。这才是 renderer 搬到包外真正要处理的问题——资源路径,不是依赖解析。
  • 准确表述:renderer 的可搬运性 = “依赖打没打进 bundle”(构建期决定)+ “资源路径对不对”(加载期决定),跟"进程身份/node 集成"是两套维度。


    七、都打进 bundle,会不会包体大、影响性能

    会让安装包变大,但"包体大"和"性能差"在 Electron 里不是同一件事,也不像网页那样强相关。关键差异:Electron 的 renderer 从本地磁盘走 file:// 加载,没有网络下载这一环。

    成本受 bundle 大小影响吗在 Electron 里严重吗
    网络下载耗时 网页里很关键 ❌ 几乎不存在,本地磁盘读取
    安装包 / 磁盘体积 ✅ 直接变大 ⚠️ 影响分发体积,不影响运行性能
    JS 解析+编译+执行耗时 ✅ 真正影响启动 ✅ 这才是要管的

    7.1 不打进 bundle ≠ 更快

    容易误以为"把 Vue 留在 node_modules、不打进 bundle"更轻,其实不是:

    • 那些代码该被解析执行一行都不会少,只是文件换了位置。
    • node_modules 是几百上千个小文件,运行时一堆 fs 查找 + asar 解析,往往比一个打好的 bundle 更慢。
    • 打进 bundle 还能吃到 tree-shaking + 压缩混淆,external 的 node_modules 这两样都享受不到。

    所以 renderer 这边"打进 bundle"通常是更优选择。external 那套是 utility-server 为了可解析/可热更才用的,不是为了性能。

    7.2 体积/启动真的大了,正确解法是"延迟执行"而非"踢出 bundle"

  • 代码分割 + 路由懒加载(最主要的杠杆):动态 import() 把非首屏页面/组件拆成独立 chunk,首屏只留必需,V8 启动要解析的 JS 就小了。
  • production 模式构建:minify + scope hoisting + 去掉 dev 警告,Vue 2 运行时本身就只有几十 KB(gzip)。
  • vendor 拆分:第三方库单独成 chunk,便于磁盘缓存 / V8 code cache 复用。
  • V8 code cache / 快照(进阶):缓存"解析编译"结果,二次启动更快。
  • 落到本 demo:renderer 依赖就是 vue@2 + axios,体量很小,打进去完全无所谓。这类担忧通常在依赖树很重(大型 UI 库、地图、富文本、ECharts 全量)时才需要认真对待。


    八、本 demo 的最优选择:第三方包直接打进 utility-server,省掉 NODE_PATH

    第三节为了通用性讲了 UTILITY_SERVER_NODE_PATH + Module._initPaths() 的完整方案。但针对当前这个 demo,有更简单的路子:utility-server 运行时唯一的第三方 require 就是 express(http/module/path 都是核心模块)。只要把 express 打进 utility-server 的 bundle,运行时不再发生 require('express'),这个脚本就是单文件自包含——丢用户目录也好、丢哪都好,不依赖任何 node_modules,于是整套 NODE_PATH 机制可以全删掉。

    对热更新反而更友好:用户目录里的脚本自带 express,不用再"复用当前安装包的 node_modules",少一个出错点。

    8.1 具体改三处

  • webpack 让 express 不再 external(webpack.main.config.js):
  • externals: [
    Object.keys(dependencies || {}).filter(d => d !== 'express')
    ],

    main 进程没 import express,所以只有 utility-server 入口会把它打进去,main 不受影响。

  • 删掉 src/main/utility-server.js 顶部的引导块(改源文件,不是 dist):
  • // 这一整段可以删了
    const Module = require('module')
    if (utilityServerNodePath) {
    process.env.NODE_PATH = utilityServerNodePath
    Module._initPaths()
    }

    直接 const express = require('express') 即可,webpack 会把它替换成内联代码。

  • 删掉主进程的路径注入(src/main/index.js):resolveUtilityServerNodePath()、那个 if (!nodePath) throw、fork 时 env 里的 UTILITY_SERVER_NODE_PATH 都不需要了,/health 里的 utilityServerNodePath 字段也可一并去掉。
  • 8.2 唯一要记住的边界

    这条路只对"纯 JS 依赖"成立。express、axios 都是纯 JS,能干净打包。但如果 utility-server 引入了带原生 .node 二进制的依赖(如 better-sqlite3、serialport),webpack 没法把二进制打进 bundle,那就得退回 external + node_modules + NODE_PATH 那套。

    纯 JS 依赖 → 打进 bundle,最省心;含原生模块 → 必须 external + 传 node 路径。

    当前 demo 全是纯 JS,直接打进去即可。


    九、总结

    把 Electron 的"库引入"想成两条独立的判断线,绝大多数 require 问题都能秒定位:

  • 这是 Electron 能力还是 Node/第三方能力?
    • Electron 主进程 API(app/net/session…)→ 身份问题,只有主进程有,utility/renderer 拿不到,改路径无效,只能换进程或让主进程代劳。
  • 如果是 Node/第三方能力,文件解析得到吗?
    • 核心模块(path/http/net…)→ 在二进制里,永远 OK。
    • 第三方(express…)→ 看 webpack 是打进 bundle 还是 external;若 external,运行时必须能解析到 node_modules,搬到安装包外时用 UTILITY_SERVER_NODE_PATH + Module._initPaths() 修复。
  • renderer 特殊:它默认没有 Node,业务依赖靠 webpack 打进 bundle,搬到包外要解决的是资源路径而非依赖解析,且必须由主进程 loadFile 加载。renderer 的可搬运性来自"打进 bundle",跟 nodeIntegration / contextIsolation 无关——后者用错了反而引回依赖解析问题,还是安全反模式。
  • 两条工程取舍:

    • 打不打进 bundle? 纯 JS 依赖优先打进 bundle(更快、可 tree-shaking、自包含、可搬运);只有含原生 .node 的依赖才必须 external + 传 node 路径。包体大主要影响安装包体积,不等于性能差,启动慢用懒加载/压缩治理,而不是踢出 bundle。
    • 本 demo 落地:utility-server 只依赖纯 JS 的 express,直接打进它的 bundle 即可,UTILITY_SERVER_NODE_PATH + Module._initPaths() 整套都能删掉(见第八节)。

    一句话收尾:utilityProcess 复用的是 Node 生态和 app.asar 的 node_modules,但拿不到任何"主进程专属"的 Electron 能力;主进程才是那个持有全部 Chromium 子系统的根进程。


    相关文档:

    • Electron utilityProcess 承载 deep-link 服务
    • utilityProcess 脚本热更新、用户目录优先启动与 asar 依赖解析
    赞(0)
    未经允许不得转载:171主机测评 » Electron 多进程下的“库引入“全解析:核心模块、Electron API、第三方依赖与 utilityProcess 的依赖处理
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址