Search code examples
typescriptelectroneslintdynamic-import

How can I use require inside functions or conditions with TypeScript type support on Electron?


In the Electron Performance docs, the following is said:

In traditional Node.js development, we're used to putting all our require() statements at the top. If you're currently writing your Electron application using the same strategy and are using sizable modules that you do not immediately need, apply the same strategy and defer loading to a more opportune time.

So it recommends to allocate resources "just in time" calling require() just when it is needed. The problem is that I'm trying to use electron-react-boilerplate and TypeScript doesn't seem to support well this kind of code. Here is an example:

src/main.dev.ts:

if (
  process.env.NODE_ENV === 'development' ||
  process.env.DEBUG_PROD === 'true'
) {
  require('electron-debug')({ showDevTools: false });
}

It has an ESLint error "Unsafe call of an any typed value. eslint(@typescript-eslint/no-unsafe-call)" in require('electron-debug'), even though this library has types defined.

But if if replace it by import, it works without that error:

import electronDebug from 'electron-debug'; // at the top of the file

if (
  process.env.NODE_ENV === 'development' ||
  process.env.DEBUG_PROD === 'true'
) {
  electronDebug({ showDevTools: false });
}

So how can I use require in that situation with types support?

I read this answer saying to use import module = require('module') but then an error occurs saying "An import declaration can only be used in a namespace or module. ts(1232)" if I use it inside an if or a function.


Solution

  • We can use an asynchronous import() to solve that problem:

    if (
      process.env.NODE_ENV === 'development' ||
      process.env.DEBUG_PROD === 'true'
    ) {
      import('electron-debug').then(electronDebug =>
        electronDebug.default({ showDevTools: false }),
      );
    }
    

    Notice that for CommonJS it will be transpiled to require (read more about it here), so we can assume that it still uses the require cache that is mentioned on Electron docs.


    Using this approach with electron-react-boilerplate may create extra files on yarn package, such as 252.main.prod.js, which will result in an error when trying to execute the program (Error: Cannot find module '../../src/252.main.prod.js'). To avoid it, you'll need to tell Webpack to ignore it as the bellow example:

    Before:

    const sourceMapSupport = require('source-map-support');
    sourceMapSupport.install();
    

    After:

    import(/* webpackIgnore: true */ 'source-map-support')
      .then((sourceMapSupport) => sourceMapSupport.install())
      .catch(console.error);