【问题标题】:Persist nedb to disk in Electron renderer process (Webpack/Electron/nedb configuration problem)在 Electron 渲染器进程中持久化 nedb 到磁盘(Webpack/Electron/nedb 配置问题)
【发布时间】:2019-04-08 03:03:36
【问题描述】:

问题

我正在尝试在 Electron 渲染器进程中使用名为 nedb 的纯 JS 数据库。它使用its package.json 中的browser field 来交换基于浏览器的存储系统。这导致我的数据库实际上没有被持久化到文件中。

背景

我使用 Next.js 作为我的视图框架,它的 Webpack 配置为 "target": "electron-renderer" 用于渲染线程。这显然会导致 Webpack 处理这些浏览器指令,即使渲染器进程应该可以访问浏览器和 Node API。这种行为并没有真正记录在案,所以我不知道如何覆盖它。

我尝试过的

我已经确认,如果我手动编辑掉 node_modules/nedb/package.json 本地副本上的 browser 字段,问题就会消失。

作为一种临时解决方法,我已经指出了我自己的 nedb 的分支,它可以做到这一点。但这很不令人满意。

其他研究

奇怪的是,这似乎不是 electron-vue 的问题,其文档 explicitly demonstrate 使用来自渲染器进程的 nedb。该框架确实似乎在its Webpack config 中使用了"target": "electron-renderer"

有没有办法解决这个问题,也许是通过 Webpack 配置?

【问题讨论】:

  • 你有一些代码可以看一下吗?
  • @customcommander 据我所知,如果您创建一个尝试从渲染器进程实例化 nedb 数据存储的 Electron 项目,就会出现问题。我认为问题实际上归结为 Webpack 和 nedb 都没有预见到通过 Node.js 访问文件的浏览器环境的存在。从示例代码的角度来看,关于什么最有帮助的建议?在我看来,一个完整的示例项目似乎有点矫枉过正,因为我们实际上是在谈论分散的配置条目。
  • 很公平。我去看看。

标签: javascript webpack electron next.js nedb


【解决方案1】:

您不需要在渲染器进程上运行数据库,而是可以在主进程上运行您想要的其他数据库,如 sql、sqlite、mongodb 等。

如果您不介意切换数据库,以下是实现此目的的方法。在 Electron 中存在一个名为 ipcMain 和 ipcRenderer 的类,这些类用于使渲染器进程和主进程通信。您可以使用 ipc 发送/接收任何类型的数据。

这是一个例子:

Renderer.js

const btnSave = document.getElementById('btn-save')

// Get any data from forms, etc


btn.addEventListener('click', () => {
     // ipcRender sends the data via 'receive-data-to-save-in-database' channel, you
     // you can send any type of data, and have has many args you want. In this case I 
     // sent a a empty object
     ipcRenderer.send('receive-data-to-save-in-database', {})              
})

Main.js

// ipcMain listens to channel 'receive-data-to-save-in-database'
ipcMain.on('receive-data-to-save-in-database', (event, args) => {
    // Code to save in database
    // The empty object will be received in args parameter
}) 

这不是您想要的,而是一种解决方法。

更多信息,我建议你去:

ipcRenderer Docs ipcMain Docs

【讨论】:

【解决方案2】:

正如您在问题中所述,并且根据 nedb 包上的 Github issue,问题的根本原因是 webpack 的文件解析过程读取了 package.browser 键,以便将特定文件路径别名到不同的位置当target 构建为browser 或其他一些会导致它检查package.browser 属性的值时。

electron-vue 通过将所有 NPM 依赖项视为externalssidestep the webpack bundling issue 显示,这样它们就不会被拉入应用程序包,而是通过其他方式在global 上定义。您可以类似地将 nedb 指定为 webpack 配置中的外部,并通过 script 标签或在 global 上定义对它的引用以其他方式将 Node 版本拉入您的应用程序。

另一种解决方案是创建一个 webpack 解析器插件,以覆盖 "./lib/customUtils.js""./lib/storage.js" 的问题要求如何得到解决,绕过检查 package.browser 以获取这些文件路径的别名的解析步骤。

在你的 Webpack 配置中查看 how to pass a custom resolver plugin 的 webpack 文档。有关how plugins are defined 及其工作原理的更多详细信息,请参阅wepback/enhanced-resolve 文档。

本质上,插件是一个带有apply 方法的对象,它采用resolver 实例并执行文件解析过程的某些步骤。在下面的示例中,我们测试当前正在解析的文件是否在 nedb 包中,以及它是否是两个有问题的浏览器别名之一。如果是这样,我们使用正确的文件路径退出解析过程。否则我们什么也不做,按照正常的解决过程。

// Prevents nedb from substituting browser storage when running from the
// Electron renderer thread.
const fixNedbForElectronRenderer = {
  apply(resolver) {
    resolver
      // Plug in after the description file (package.json) has been
      // identified for the import, which makes sure we're not getting
      // mixed up with a different package.
      .getHook("beforeDescribed-relative")
      .tapAsync(
        "FixNedbForElectronRenderer",
        (request, resolveContext, callback) => {
          // When a require/import matches the target files, we
          // short-circuit the Webpack resolution process by calling the
          // callback with the finalized request object -- meaning that
          // the `path` is pointing at the file that should be imported.
          const isNedbImport = request.descriptionFileData["name"] === "nedb"

          if (isNedbImport && /storage(\.js)?/.test(request.path)) {
            const newRequest = Object.assign({}, request, {
              path: resolver.join(
                request.descriptionFileRoot,
                "lib/storage.js"
              )
            })
            callback(null, newRequest)
          } else if (
            isNedbImport &&
            /customUtils(\.js)?/.test(request.path)
          ) {
            const newRequest = Object.assign({}, request, {
              path: resolver.join(
                request.descriptionFileRoot,
                "lib/customUtils.js"
              )
            })
            callback(null, newRequest)
          } else {
            // Calling `callback` with no parameters proceeds with the
            // normal resolution process.
            return callback()
          }
        }
      )
  }
}

// Register the resolver plugin in the webpack config
const config = {
  resolve: {
    plugins: [fixNedbForElectronRenderer]
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-01
    • 2018-06-13
    • 2013-10-19
    • 2018-05-29
    • 2017-10-14
    • 2019-10-27
    • 2015-12-28
    • 2018-01-05
    相关资源
    最近更新 更多