nuxt-electron: require is not defined in ES module scope

when run nuxt dev && electron . error require is not defined in ES module scope, you can use import instead This file is being treated as an ES module because it has a ‘.js’ file extension and ‘[path]\package.json’ contains “type”: “module”. To treat it as a CommonJS script, rename it to use the ‘.cjs’ file extension.

help me,please!

About this issue

  • Original URL
  • State: closed
  • Created 5 months ago
  • Comments: 35 (1 by maintainers)

Most upvoted comments

package.json

{
- "type": "module",
}

If we’re trying to use ES Modules (ESM) in Electron we should have "type": "module" in our package.json and the preload scripts must have the .mjs extension

The problem is that the nuxt-electron plugin does’t do this automatically despite it using vite-plugin-electron internally and this was discussed/fixed on electron-vite/vite-plugin-electron#186

This is a little workaround that worked for me

nuxt.config.ts

export default defineNuxtConfig({
  ...,
  modules: ['nuxt-electron'],
  electron: {
    renderer: { },
    build: [
      { entry: 'electron/main.ts' },
      {
        entry: 'electron/preload.ts',
        vite: {
          build: {
            rollupOptions: {
              output: {
                entryFileNames: `[name].mjs`,
                chunkFileNames: `[name].mjs`,
              },
            },
          },
        },
        onstart(args) {
          args.reload()
        },
      },
    ],
  },
})

This generates the proper dist-electron/preload.mjs file that the main electron script expects.

electron/main.ts

import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { env } from 'node:process'
//
import { BrowserWindow, app } from 'electron'

/** Env */
const isDev = !!env.VITE_DEV_SERVER_URL
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)

env.ROOT = path.join(dirname, '../')
env.DIST = path.join(env.ROOT, 'dist-electron')
env.VITE_PUBLIC = isDev ? path.join(env.ROOT, 'public') : path.join(env.ROOT, '.output/public')
// env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'

/** Create main windows and load app */
function bootstrap() {
  const preload = path.join(env.DIST!, 'preload.mjs')

  const mainWindow = new BrowserWindow({
    width: 1280,
    height: 1024,
    webPreferences: {
      preload,
      nodeIntegrationInWorker: true,
      contextIsolation: false,
      nodeIntegration: true,
      webSecurity: false, // TODO: fix `Insecure Content-Security-Policy`
    },
  })

  if (isDev) {
    mainWindow.loadURL(env.VITE_DEV_SERVER_URL!)
    mainWindow.webContents.openDevTools()
  }
  else {
    mainWindow.loadFile(path.join(env.VITE_PUBLIC!, 'index.html'))
  }
}

/** Main process */
app.whenReady().then(() => {
  bootstrap()
})

I’ve to mention that I don’t know what I’m doing, nor am I a Nuxt or Electron expert, but all the @angelhdzmultimedia messages helped me to find a way, thanks 🙋‍♂️.

Hey! Thanks for the feedback. Will try your solution.

If we’re trying to use ES Modules (ESM) in Electron we should have "type": "module" in our package.json and the preload scripts must have the .mjs extension

The problem is that the nuxt-electron plugin does’t do this automatically despite it using vite-plugin-electron internally and this was discussed/fixed on electron-vite/vite-plugin-electron#186

This is a little workaround that worked for me

nuxt.config.ts

export default defineNuxtConfig({
  ...,
  modules: ['nuxt-electron'],
  electron: {
    renderer: { },
    build: [
      { entry: 'electron/main.ts' },
      {
        entry: 'electron/preload.ts',
        vite: {
          build: {
            rollupOptions: {
              output: {
                entryFileNames: `[name].mjs`,
                chunkFileNames: `[name].mjs`,
              },
            },
          },
        },
        onstart(args) {
          args.reload()
        },
      },
    ],
  },
})

This generates the proper dist-electron/preload.mjs file that the main electron script expects.

electron/main.ts

import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { env } from 'node:process'
//
import { BrowserWindow, app } from 'electron'

/** Env */
const isDev = !!env.VITE_DEV_SERVER_URL
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)

env.ROOT = path.join(dirname, '../')
env.DIST = path.join(env.ROOT, 'dist-electron')
env.VITE_PUBLIC = isDev ? path.join(env.ROOT, 'public') : path.join(env.ROOT, '.output/public')
// env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'

/** Create main windows and load app */
function bootstrap() {
  const preload = path.join(env.DIST!, 'preload.mjs')

  const mainWindow = new BrowserWindow({
    width: 1280,
    height: 1024,
    webPreferences: {
      preload,
      nodeIntegrationInWorker: true,
      contextIsolation: false,
      nodeIntegration: true,
      webSecurity: false, // TODO: fix `Insecure Content-Security-Policy`
    },
  })

  if (isDev) {
    mainWindow.loadURL(env.VITE_DEV_SERVER_URL!)
    mainWindow.webContents.openDevTools()
  }
  else {
    mainWindow.loadFile(path.join(env.VITE_PUBLIC!, 'index.html'))
  }
}

/** Main process */
app.whenReady().then(() => {
  bootstrap()
})

I’ve to mention that I don’t know what I’m doing, nor am I a Nuxt or Electron expert, but all the @angelhdzmultimedia messages helped me to find a way, thanks 🙋‍♂️.

Tried all the suggestions here but still getting this: image

SOLUTION

In ~/electron/main.ts, replace process.env.ROOT = path.join(process.cwd(), '..') or process.env.ROOT = path.join(__dirname, '..') with process.env.ROOT = path.join(import.meta.url, '..').

As per the error shown, __dirname doesn’t work in ES6 modules. Replacement for modules is import.meta.url to get the path to the electron/main.ts file (to itself) and from there, 2 levels up to reach the CWD (Current Working Directory, the root of the nuxt project).

This worked! Thanks for the help.

Tried all the suggestions here but still getting this: image

SOLUTION

In ~/electron/main.ts, replace process.env.ROOT = path.join(process.cwd(), '..') or process.env.ROOT = path.join(__dirname, '..') with process.env.ROOT = path.join(import.meta.url, '..').

As per the error shown, __dirname doesn’t work in ES6 modules. Replacement for modules is import.meta.url to get the path to the electron/main.ts file (to itself) and from there, 2 levels up to reach the CWD (Current Working Directory, the root of the nuxt project).

Tried all the suggestions here but still getting this: image

Show package.json and nuxt.config please.

// https://nuxt.com/docs/api/configuration/nuxt-config
import vuetify from 'vite-plugin-vuetify'

export default defineNuxtConfig({
  typescript: {
    shim: false,
  },
  ssr: false,
  electron: {
    build: [
      {
        // Main-Process entry file of the Electron App.
        entry: 'electron/main.ts',
      },
      {
        entry: 'electron/preload.ts',
        onstart(args) {
          // Notify the Renderer-Process to reload the page when the Preload-Scripts build is complete,
          // instead of restarting the entire Electron App.
          args.reload()
        },
      },
    ],
    renderer: {},
  },
  modules: [
    'nuxt-electron',
    (_options, nuxt) => {
      nuxt.hooks.hook('vite:extendConfig', (config) => {
        config.plugins.push(vuetify({ autoImport: true }))
      })
    },
  ],
  build: {
    transpile: ['vuetify'],
  },
  devtools: { enabled: true },
})
{
  "name": "nuxt-app",
  "version": "1.0.0",
  "private": true,
  "main": "dist-electron/main.js",
  "type": "module",
  "scripts": {
    "dev": "nuxi dev",
    "build": "nuxi build --prerender && electron-builder",
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  },
  "dependencies": {
    "@mdi/font": "^7.4.47"
  },
  "devDependencies": {
    "@antfu/eslint-config": "^2.6.4",
    "electron": "^28.2.4",
    "electron-builder": "^24.12.0",
    "eslint": "^8.56.0",
    "nuxt": "^3.10.1",
    "nuxt-electron": "^0.7.0",
    "sass": "^1.70.0",
    "vite-plugin-electron": "0.28.1",
    "vite-plugin-electron-renderer": "^0.14.5",
    "vite-plugin-vuetify": "^2.0.1",
    "vuetify": "^3.5.3"
  }
}

Tried all the suggestions here but still getting this: image

Not yet. Will keep playing with the renderer options until I solve it and will let you know.

Thanks!!

I’m getting somewhere

My question is same to you,So,Did you solve it?

Not yet. Will keep playing with the renderer options until I solve it and will let you know.

Update

I’m getting somewhere… 👀

image

I’m not from the team by the way 😁

Just wanted to help. I’m starting with Electron and Nuxt, had an issue with the preload, and solved it.

All I’ve read on the internet mentions removing “type”: “module” from package.json to get it working.

Both Nuxt and Electron are ESM ready: https://www.electronjs.org/docs/latest/tutorial/esm https://nuxt.com/docs/guide/concepts/esm

So, do you want to get rid of the error, or you want to have your .js files with ESM imports instead of require?

(will be playing with tsconfig.json to see if I find something)

Thanks for your help again!I wrote the code in nuxt-electron(https://nuxt.com/modules/electron)

No require is used in the code node:v20.11.0 “@nuxt/ui”: “^2.13.0”, “nuxt”: “^3.10.0”, “vue”: “^3.4.15”, “vue-router”: “^4.2.5” “electron-builder”: “^24.9.1”, “electron”: “^28.2.1”, “nuxt-electron”: “^0.7.0”, “vite-plugin-electron”: “^0.15.6”, “vite-plugin-electron-renderer”: “^0.14.5” PC OS:win 10

It worked ! when i remove "type": "module" in package.json,but,I want to use es6,how to update?

~/tsconfig.json

{
...
"compilerOptions": {
  "module: "es6" 
  // or target: "es6"
}
}

Maybe?

Thanks for your help! but ,Still the same error