在电子渲染器过程中将nedb坚持到磁盘(Webpack / Electron / nedb配置问题)

acj*_*jay 5 javascript webpack nedb electron next.js

问题

我正在尝试在Electron渲染器过程中使用名为nedb的纯JS数据库。它使用browser领域package.json要交换基于浏览器的存储系统。这导致我的数据库实际上未持久保存到文件中。

背景

我使用Next.js作为我的视图框架,并且"target": "electron-renderer"为渲染线程配置了它的Webpack 。即使渲染器进程应有权访问浏览器和Node API,这显然也会导致Webpack处理那些浏览器指令。此行为并未真正记录,因此我不知道如何覆盖它。

我尝试过的

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

作为临时的解决方法,我已经指出了自己的能力nedb。但这是非常不令人满意的。

其他研究

奇怪的是,这似乎对电子战来说不是问题,电子战的文档明确演示nedb了渲染过程中对电子战的使用。实际上,该框架似乎确实"target": "electron-renderer"其Webpack config中使用

是否可以通过Webpack配置解决此问题?

小智 2

As you stated in your question and per this Github issue on the nedb package the root cause of your issue is that webpack's file resolution process reads the package.browser key in order to alias specific file paths to a different location when the target build is browser or some other value that will cause it to inspect the package.browser property.

electron-vue appears to sidestep the webpack bundling issue by treating all NPM dependencies as externals so that they don't get pulled into the application bundle and instead are expected to be defined on global by some other means. You could similarly designate nedb as an external in your webpack config and pull the Node version into your application via script tag or defining a reference to it on global some other way.

Another solution would be to create a webpack resolver plugin to override how the problematic requires for "./lib/customUtils.js" and "./lib/storage.js" get resolved, bypassing the resolution step that inspects package.browser for aliases for those file paths.

See the webpack documentation for how to pass a custom resolver plugin in your Webpack config. See the wepback/enhanced-resolve documentation for additional details on how plugins are defined and how they work.

Essentially, a plugin is an object with an apply method that takes a resolver instance and performs some step of the file resolution process. In the example below, we test to see whether the current file being resolved is in the nedb package and whether it's one of the two problematic browser aliases. If so, we exit the resolution process with the correct paths to the files. Otherwise we do nothing and defer to the normal resolution process.

// 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]
  }
}
Run Code Online (Sandbox Code Playgroud)