Preload.js is not a module - Unable to load preload script; Unexpected token 'export'

See original GitHub issue

Prerequisites

  • Using yarn
  • Using an up-to-date main branch
  • 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

  1. Clone this repo.

  2. Create a file src/main/helper.ts with the following content:

export const helper = () => {
  console.log('helped!');
};
  1. 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,
  // ...
}
  1. Run yarn start and 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:closed
  • Created 2 years ago
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
guillermorivcommented, Nov 7, 2021

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 javascript file code from a typescript file. The funny thing is that you can do it viceversa, you can import javascript files into typescript files, 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 .js files for this, and you can import that to any .ts files 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 .ts files as the helper.ts and you can import this into the preload.js file 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.ts will 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 build and you go to the directory of main-project/release/app/dist/main/main.js and you run electron ./main.js, and you import the helper.ts into the preload.js file it will work, but why?, because the code is being compile and not transpile webpack will bundle everything into the preload.js as 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.

2reactions
michaelprescottcommented, Aug 12, 2022

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 you import "./your-own.js". You can’t even const 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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

electron-builder with browserWindow and preload.js. Unable ...
Unable to load preload script, but actually something was wrong with the initialize.js. in my file, has an error that remote.
Read more >
SyntaxError: Unexpected token * on an quickstarted Electron ...
Hi,. i wanted to jump start a simple babylonJS application with electron and typescript. The compilation works just fine but the appearing ...
Read more >
jest uuid syntaxerror: unexpected token 'export' - You.com
This means, that a file is not transformed through TypeScript compiler, e.g. because it is a JS file with TS syntax, or it...
Read more >
ES6 browser support: is it time to rethink bundling? - Contentful
Unfortunately, preloading of ES6 modules is not so easy because they behave differently than normal scripts. The question is how a link element ......
Read more >
html-loader - webpack
file.js import html from "./file.html";. webpack.config.js module.exports ... manifest , prefetch , preload or when the itemprop attribute is image ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found