添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
跳转到主内容

Electron中的 ES 模块 (ESM)

ECMAScript 模块(ESM) 格式是 加载JavaScript 软件包的标准方式

Chromium 和 Node.js 有自己实现的 ESM 规格,Electron 根据上下文选择使用哪个模块加载器。

本文档旨在概述Electron中ESM的局限性,以及Electron中的 ESM与Node.js和Chromium中的ESM之间的差异。

info

此功能已添加到 [email protected] 中。

摘要:ESM支持矩阵表

本表概述了什么是支持ESM的地方以及使用什么是ESM加载器。

流程 ESM 加载器 预加载的 ESM 加载器 适用的要求
首页 Node.js N/A
渲染进程(沙盒化) Chromium 不支持
渲染进程(非沙盒化 & 上下文隔离) Chromium Node.js
  • [非沙盒化 ESM 预加载脚本将在没有内容的页面加载后运行](#unsandboxed-esm-preload-scripts-will -run-dun-page-load--with-no-content)
  • [ESM 预加载脚本必须有 . mjs 扩展](#esm-preload-scripts-must have-the-mjs-extension)
渲染进程(非沙盒化 & 非上下文隔离) Chromium Node.js
  • [非沙盒化 ESM 预加载脚本将在没有内容的页面加载后运行](#unsandboxed-esm-preload-scripts-will -run-dun-page-load--with-no-content)
  • ESM 预加载脚本必须有 . mjs 扩展名
  • [ESM 预加载 脚本必须是隔离上下文中才能使用动态Node.js ESM 导入](#esm-preload-scripts-must be separated-context to use-dynamic-nodejs-esm-imports)

主进程

Electron的主进程在 Node.js 环境中运行并使用其ESM 加载器。 使用方法参考 Node's ESM 文档 。 若要在主进程中的文件中启用 ESM ,必须满足以下条件:

  • 文件以 .mjs 扩展名结尾
  • 最近的 package.json 有"type": "module"" 设置
  • 更多详情请参阅 Node 文档 模块系统

    注意事项

    您必须在应用程序的 ready 事件之前使用 await

    ES模块加载是 异步 的 。 这意味着只有主进程入口的导入会在 "准备" 事件之前执行副效果。

    This is important because certain Electron APIs (e.g. app.setPath ) need to be called before the app's ready event is emitted.

    在 Node.js ESM 中使用顶层 await ,请确保所有 Promise 在 app 的 ready 事件之前完成。 否则,您的应用可能会在代码执行之前`ready'。

    这对于动态导入语句(静态导入不受影响) 来说尤为重要。 例如,如果 index.mjs 在顶层执行 import('./set-up-paths.mjs') , 应用会在动态导入解析完成后触发 ready 事件。

    index.mjs (Main Process)
    // 在 app `ready` 之前 set-up-paths 完成
    import('./set-up-paths.mjs')

    app.whenReady().then(() => {
    console.log('This code may execute before the above import')
    })
    转译器转换

    在 Node.js 支持 ESM 导入之前, JavaScript 编译器 (如Babel, TypeScript) 支持 ESM模块语法, 是将这些导入转换到CommonJS require 调用。

    示例:@babel/plugin-transform-modules-commonjs

    @babel/plugin-transform-modules-commonjs 插件将把 ESM导入转换为 CommonJS require 调用'。 确切的语法将取决于 importInterop 设置

    @babel/plugin-transform-modules-commonjs
    import foo from "foo";
    import { bar } from "bar";
    foo;
    bar;

    // 配置 "importInterop: node", 编译为 ...

    "use strict";

    var _foo = require("foo");
    var _bar = require("bar");

    _foo;
    _bar.bar;

    这些CommonJS加载模块代码是同步进行的。 如果您正在迁移到 CJS 代码到原生ESM,请注意CJS 和 ESM 加载时机之间的差异。

    渲染器进程

    Electron的渲染进程在Chromium上运行,将使用 Chromium 的 ESM 加载器。 实际上,这意味着 `import' 语句:

  • 将无法访问Node.js内置模块
  • 无法从 "node_modules" 加载 npm 软件包
  • <script type="module">
    import { exists } from 'node:fs' // ❌ 无效
    </script>

    如果您想要通过 npm 直接将JavaScript 包加载到渲染进程中, 我们建议生成客户端时使用诸如webpack 或 Vite 之类的打包工具来编译您的代码。

    Preload 脚本

    渲染进程的预加载脚本将使用 Node.js ESM loader ,如果可用。 ESM 的可用性将取决于渲染器的 sandbox contextIsolation 配置项的值, 并且由于ESM加载的异步性质,还有其他一些注意事项。

    注意事项

    ESM 预加载脚本必须有 .mjs 扩展

    预加载脚本将忽略 "type": "module"" 字段,所以你_必须_ 在你的 ESM 预加载脚本中使用 .mjs` 文件扩展。

    沙盒化的预加载脚本不能使用 ESM 导入

    沙盒化的预加载脚本作为普通JavaScript运行,没有ESM 环境。 如果您需要使用外部模块,我们建议使用打包工具打包预加载代码。 加载 electron API 仍然通过 require('electron') 完成。

    For more information on sandboxing, see the Process Sandboxing docs.

    非沙箱化的 ESM 预加载脚本将在没有内容的页面加载后运行

    如果渲染器加载页面的响应正文为空(例如: Content-Leng:0 ),其预加载脚本不会阻止页面加载,这可能导致竞态条件。