Сохранение nedb на диск в процессе электронной визуализации (проблема с конфигурацией Webpack / Electron / nedb)

#javascript #webpack #electron #next.js #nedb

#javascript #веб-пакет #electron #next.js #nedb #webpack

Вопрос:

Проблема

Я пытаюсь использовать базу данных на чистом JS под названием nedb в процессе электронной визуализации. Он использует browser поле в its package.json для подкачки в браузерной системе хранения. Это приводит к тому, что моя база данных фактически не сохраняется в файле.

Предыстория

Я использую Next.js как моя платформа просмотра, и ее веб-пакет настроен для "target": "electron-renderer" потока рендеринга. Что, по-видимому, заставляет Webpack обрабатывать эти директивы браузера, хотя процессы визуализации должны иметь доступ как к API браузера, так и к API узла. Это поведение на самом деле не задокументировано, поэтому я не знаю, как его переопределить.

Что я пробовал

Я подтвердил, что если я вручную отредактирую browser поле в локальной копии node_modules/nedb/package.json , проблема исчезнет.

В качестве временного обходного пути я указал на свой собственный форк nedb , который делает это. Но это довольно неудовлетворительно.

Другие исследования

Любопытно, что это, похоже, не является проблемой для electron-vue, чьи документы явно демонстрируют использование nedb процесса рендеринга. Этот фреймворк, действительно, используется "target": "electron-renderer" в конфигурации Webpack.

Есть ли решение этой проблемы, возможно, с помощью конфигурации Webpack?

Комментарии:

1. У вас есть какой-нибудь код, на который мы можем посмотреть?

2. @customcommander Насколько я могу судить, проблема возникает, если вы создаете проект Electron, который пытается создать хранилище данных nedb из процесса рендеринга. Я думаю, проблема действительно сводится к тому, что ни Webpack, ни nedb не предвидели существование среды браузера с доступом к файлам через Node. Есть предложения о том, что было бы наиболее полезным с точки зрения примера кода? На мой взгляд, весь пример проекта кажется излишним, потому что на самом деле мы говорим о разрозненных записях конфигурации.

3. Достаточно справедливо. Я посмотрю.

Ответ №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
Документы ipcMain

Комментарии:

1. Спасибо за мысли! Я понимаю, что на самом деле не так уж хорошо запускать такие вещи, как базы данных, в основном процессе (см. medium.freecodecamp.org /… и github.com/louischatriot/nedb/issues/531#issuecomment-477769752 ). Я также стремлюсь упростить задачу с точки зрения отладки, оставаясь в одном потоке во время разработки моего прототипа. Наконец, я предпочитаю nedb , потому что это чистый JS.

Ответ №2:

Как вы указали в своем вопросе и в соответствии с этой проблемой Github в nedb пакете, основная причина вашей проблемы заключается в том, что процесс разрешения файлов webpack считывает package.browser ключ, чтобы присвоить псевдоним определенным путям к файлам в другое местоположение при target сборке browser , или какое-либо другое значение, которое заставит его проверять package.browser свойство.

electron-vue похоже, что это позволяет обойти проблему связывания webpack, рассматривая все зависимости NPM как externals , чтобы они не попадали в пакет приложений, а вместо этого, как ожидается, определялись на global некоторыми другими средствами. Вы могли бы аналогичным образом обозначить nedb как внешний в своей конфигурации webpack и перенести версию узла в свое приложение с помощью тега script или определить ссылку на него global каким-либо другим способом.

Другим решением было бы создать плагин webpack resolver для переопределения того, как проблема требует "./lib/customUtils.js" и "./lib/storage.js" решается, минуя этап разрешения, который проверяет package.browser на наличие псевдонимов для этих путей к файлам.

Смотрите документацию webpack о том, как передать пользовательский плагин распознавателя в вашей конфигурации Webpack. Смотрите 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 amp;amp; /storage(.js)?/.test(request.path)) {
            const newRequest = Object.assign({}, request, {
              path: resolver.join(
                request.descriptionFileRoot,
                "lib/storage.js"
              )
            })
            callback(null, newRequest)
          } else if (
            isNedbImport amp;amp;
            /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]
  }
}