Preload.js is not a module - Unable to load preload script; Unexpected token 'export'
See original GitHub issuePrerequisites
- Using yarn
- Using an up-to-date
mainbranch - Using latest version of devtools. Check the docs for how to update
- Tried solutions mentioned in #400
- For issue in production release, add devtools output of
DEBUG_PROD=true yarn build && yarn start
Expected Behavior
The preload.js file should be handled as a module, so I would be able to use import statements in it, among other things.
Current Behavior
When I use import in preload.js, it throws an error:
Cannot use import statement outside a module
Trying to avoid the use of imports leads to other errors, so I thoguht it would be better to handle preload.js as a module.
Steps to Reproduce
-
Clone this repo.
-
Create a file
src/main/helper.tswith the following content:
export const helper = () => {
console.log('helped!');
};
- Import it in
preload.js:
// ...
// import { helper } from './helper'; // This throws an error: Cannot use import statement outside a module
// const { helper } = require('./helper'); // This throws an error: Cannot find module './helper'
const { helper } = require('./helper.ts'); // I don't know if this will be a problem in production, since I need to
// provide the file extension
contextBridge.exposeInMainWorld('electron', {
help: helper,
// ...
}
- Run
yarn startand see the console:
VM496 renderer_init.js:93 Unable to load preload script: C:\path\electron-react-boilerplate-main\src\main\preload.js
(anonymous) @ VM496 renderer_init.js:93
./lib/renderer/init.ts @ VM496 renderer_init.js:93
__webpack_require__ @ VM496 renderer_init.js:1
(anonymous) @ VM496 renderer_init.js:1
___electron_webpack_init__ @ VM496 renderer_init.js:1
(anonymous) @ VM496 renderer_init.js:165
compileForInternalLoader @ VM431 loaders.js:283
compileForPublicLoader @ VM431 loaders.js:225
loadNativeModule @ VM471 helpers.js:35
Module._load @ VM464 loader.js:747
f._load @ VM491 asar_bundle.js:5
executeUserEntryPoint @ VM490 run_main.js:72
(anonymous) @ VM459 run_main_module.js:17
VM496 renderer_init.js:93 C:\path\electron-react-boilerplate-main\src\main\helper.ts:1
(function (exports, require, module, __filename, __dirname, process, global, Buffer) { return function (exports, require, module, __filename, __dirname) { export const helper = () => {
^^^^^^
SyntaxError: Unexpected token 'export'
at new Script (vm.js:101:7)
at createScript (vm.js:262:10)
at Object.runInThisContext (vm.js:310:10)
at wrapSafe (internal/modules/cjs/loader.js:974:15)
at Module._compile (internal/modules/cjs/loader.js:1034:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1108:10)
at Module.load (internal/modules/cjs/loader.js:935:32)
at Module._load (internal/modules/cjs/loader.js:776:14)
at Function.f._load (electron/js2c/asar_bundle.js:5:12913)
at Function.o._load (electron/js2c/renderer_init.js:33:379)
Possible Solution (Not obligatory)
I’m still trying to figure it out 🤷♂️. It looks like this could be fixed using Webpack (see How do I compile a preload script w/ webpack in Electron?), but I’m far away of being an expert in it, so I didn’t find a solution yet.
Context
I have some files in /main folder that I want to import to preload.js in order to have access to its methods from Renderer process. For example, I have an IpcService like the one in this article, and this file makes use of import statements and export. That’s why I need preload.js to be able handled as a module, such as the rest of the project.
Your Environment
- Node version : v14.15.4
- electron-react-boilerplate version or branch : main (3.0.2)
- Operating System and version : Windows 10 verison 21H1 (19043.1165)
- Link to your project : - (i just cloned this repo and reproduced it as mentioned in Steps to Reproduce)
Issue Analytics
- State:
- Created 2 years ago
- Comments:8 (1 by maintainers)
Top Related StackOverflow Question
TypeScript cannot be executed from a browser / node.js environment directly. At first you have to transpile it into native javascript. So it cannot be executed in a
javascriptfile code from atypescriptfile. The funny thing is that you can do it viceversa, you can importjavascriptfiles intotypescriptfiles, so this is not a bug, is more like it CANNOT be done as you can see for my explanation above.Possible solution: Just create a preload folder and then just use
.jsfiles for this, and you can import that to any.tsfiles that you want and work fine with it (that’s how I am doing in it), another solution is, you can build the project each time that you do a change, and you will work with.tsfiles as thehelper.tsand you can import this into thepreload.jsfile without problems because is being compiled and not transpiled.Why need to be like this (in my opinion): Because when we transpile the code to javascript the
main.tswill search for a javascript code, not for typescript code, because we are transpiling, for obvious reasons you cannot call a ts file in a js file (the explanation that I left above).If you do
npm run buildand you go to the directory ofmain-project/release/app/dist/main/main.jsand you runelectron ./main.js, and you import thehelper.tsinto thepreload.jsfile it will work, but why?, because the code is being compile and not transpile webpack will bundle everything into thepreload.jsas javascript code.I wanted just to give a full explanation about this because some time when I read about this of people getting confused why their typescript code doesn’t work in their javascript code.
In case anyone lands in this thread in 2022.
No browsers that I’m aware of run TypeScript. You must transpile to JavaScript.
Remember, the main process of an Electron app is run by NodeJS, the renderer process is run within Chromium, BUT the preload process is also within Chromium. Preload is just a special case, which has the contextBridge and ipcRenderer from electron. This is so you can build a bridge between the renderer (UI) and the main process. This also means that short of those two electron types, you cannot do fancy Node things, and you cannot do
import { yourOwn } from "./your-own-module.js". Nor can youimport "./your-own.js". You can’t evenconst yourOwn = require("./your-own-module.js")even though all of those are technically correct. You can’t do this EVEN if you already transpiled your TS versions of those into JS.There are two solutions: You can overcome that limitation by setting webPreferences.nodeIntegration = true when you create your BrowserWindow, just be sure to read about the risks of doing so. (You still have to transpile TS to JS, but now your imports of your own modules will work.)
Or you can use a bundler to combine all of your previously transpiled preload modules into a single preload.js. This is what Rafatcb was beginning to investigate above.