获取 ReferenceError:在传递 contextIsolation 时未定义要求:带有预加载脚本的 true

分享于2022年07月17日 electron javascript next.js reactjs webpack 问答
【问题标题】:获取 ReferenceError:在传递 contextIsolation 时未定义要求:带有预加载脚本的 true(Getting ReferenceError: require is not defined when passing contextIsolation: true with preload script)
【发布时间】:2021-12-09 10:17:52
【问题描述】:

我正在尝试添加选择文件夹弹出功能,并为此编写了以下代码。

create-window.ts 文件中,我已经通过了这些 browserOptions.webPreferences

webPreferences: {
   nodeIntegration: true,
  contextIsolation: true,
  preload: path.join(__dirname, '..', 'preload.js'),
  ...options.webPreferences,
},

在同一个文件中,我在调用 new BrowserWindow(browserOptions) 后立即添加了这一点逻辑

ipcMain.handle('select-folder-popup', (handler, args) => {
      return new Promise((resolve, reject) => {
         dialog
            .showOpenDialog(win, {
               properties: ['openDirectory'],
               title: 'Select folder',
            })
            .then(paths => {
               if (paths) {
                  resolve(paths[0])
               } else {
                  reject()
               }
            })
            .catch(error => {
               console.log('open folder', error)
               reject(error)
            })
      })
})

preload.js 文件中,我写过

const { ipcRenderer, contextBridge } = require('electron')

contextBridge.exposeInMainWorld('api', {
   selectFolderPopup: () => ipcRenderer.invoke('select-folder-popup', true),
})

这段代码导致了错误

ReferenceError: global is not defined

通过在 next.config.js 中添加这一行解决了

config.output.globalObject = 'this'

实现了这么多,现在我收到以下错误:

ReferenceError: require is not defined

经过一段时间的研究,我发现其中一个解决方案是设置 nodeIntegration: true ,在我的例子中它已经设置为 true

设置 contextIsolation: false ,不是一个选项,因为这会导致安全问题,我不能使用 contextBridge ,它设置为 false

依赖关系:

"dependencies": {
      "@emotion/css": "^11.1.3",
      "@emotion/react": "^11.4.1",
      "@emotion/server": "^11.4.0",
      "@emotion/styled": "^11.3.0",
      "axios": "^0.21.4",
      "electron-serve": "^1.1.0",
      "electron-store": "^8.0.0",
      "react-modal": "^3.14.3",
      "react-select": "^4.3.1"
   },
   "devDependencies": {
      "@emotion/babel-plugin": "^11.3.0",
      "@types/node": "^14.14.31",
      "@types/react": "^17.0.0",
      "@types/react-modal": "^3.12.1",
      "@types/react-select": "^4.0.17",
      "babel-plugin-macros": "^3.1.0",
      "electron": "^13.1.7",
      "electron-builder": "^22.11.7",
      "eslint": "^7.32.0",
      "eslint-config-next": "^11.1.2",
      "next": "^11.0.1",
      "nextron": "^7.0.0",
      "react": "^17.0.2",
      "react-dom": "^17.0.2",
      "tailwindcss": "^2.2.7",
      "twin.macro": "^2.7.0",
      "typescript": "^4.3.5"
   },


【解决方案1】:

更新: 我已经决定使用一种替代解决方案,它在某种程度上是这种逻辑的派生。

background.ts 文件中,我执行了以下操作:

let mainWindow
;(async () => {
   ...
   mainWindow = createWindow('main', {
      width: 1000,
      height: 600,
   })
  ...
})()

...

ipcMain.handle('select-folder-popup', () => {
   return new Promise((resolve, reject) => {
      dialog
         .showOpenDialog(mainWindow, {
            title: 'Select folder',
            properties: ['openDirectory'],
         })
         .then(({ filePaths: paths }) => {
            if (paths) {
               resolve(paths[0])
            } else {
               reject()
            }
         })
         .catch(error => {
            reject(error.message)
         })
   })
})

在渲染器中,执行以下操作即可。

import { ipcRenderer } from 'electron'

function Home () {
  return 
}