I build an Electron application using electron-forge's react-typescript template, meaning it uses electron-prebuilt-compile, which according to the only documentation I can find is supposed to just work.
The index.html contains typescript that just works, as advertised. But I am also using a webview tag with a preload script, in order to display external websites and modify them. This is the code I'm using:
<webview id="webview" preload="./preload.ts" webpreferences="contextIsolation, webSecurity=no" src="https://example.com"></webview>
This preload script is rather involved, and I would love to use typescript for it. But it is apparently parsed as javascript, with any type annotations leading to syntax errors. Is there a trick to make this work with typescript? If I have to call the transpiler manually, how do I integrate this with electron-forge's build process?
tl;dr: preload script is parsed as javascript despite typescript "just working" everywhere else, I would like to use typescript here too
You can use TypeScript in a preload file (or any file). Just import the ts-node package and configure it before you import any of your TypeScript code.
F.e., make an index.js file containing:
require('./require-hooks')
module.exports = require('./entry') // this is your TypeScript entry point.
then in your require-hooks.js file configure ts-node (ts-node is a require hook that compiles TypeScript on the fly, with caching for subsequent runs):
// ability to require/import TypeScript files
require('ts-node').register({
typeCheck: false, // faster, no type checking when require'ing files. Use another process to do actual type checking.
transpileOnly: true, // no type checking, just strip types and output JS.
files: true,
// manually supply our own compilerOptions, otherwise if we run this file
// from another project's location then ts-node will use
// the compilerOptions from that other location, which may not work.
compilerOptions: require('./tsconfig.json').compilerOptions,
})
Note, you can put all sorts of require hooks in there, for example so you can do things like require('path/to/file.ts'), require('path/to/file.tsx'), require('path/to/file.jsx'), require('path/to/file.png'), require('path/to/file.mp3'), etc, where you can define hooks for handling certain types of files (similar to Webpack in some way, but hooking into Node's builtin require function). For example, @babel/register is a hook for running JS files through Babel, asset-require-hook is a require hook that allows you to import assets like JPG files, yaml-hook allows you to require .yaml files. EDIT: Even more: css-modules-require-hook for importing CSS modules, and module-alias for creating aliases like with WebPack.
The pirates lib is a popular tool for making your own require hooks, though I also find it easy to make hooks manually without a library. You can, for example, override Module.prototype.require to implement some simple hooks:
const path = require('path')
const url = require('url')
const Module = require('module')
const oldRequire = Module.prototype.require
function toFileURL(filePath) {
return url.format({
pathname: filePath,
protocol: 'file:',
slashes: true,
})
}
Module.prototype.require = function(moduleIdentifier) {
// this simple hook returns a `file://...` URL when you try to `require()`
// a file with extension obj, svg, png, or jpg.
if (['.obj', '.png', '.svg', '.jpg'].some(ext => moduleIdentifier.endsWith(ext))) {
const result = String(toFileURL(path.resolve(path.dirname(this.filename), moduleIdentifier)))
result.default = result
return result
} else {
return oldRequire.call(this, moduleIdentifier)
}
}
then in some other file,
const fs = require('fs')
const img = require('path/to/foo.jpg')
console.log(img) // file:///absolute/path/to/foo.jpg
document.createElement('img').src = img
You could even move the call to document.createElement('img').src = img into your overridden require method to do it automatically and return the img element instead of returning a file:// URL. :)
Finally, in your ./entry.ts file that the above index.js file imports, you can have any TypeScript in there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With