在 Electron 的预加载脚本中使用 typescript

Jan*_*ese 7 typescript electron

我使用 Electron-forge 的 React-TypeScript 模板构建了一个 Electron 应用程序,这意味着它使用了 Electron-prebuilt-compile,根据我能找到的唯一文档,它应该可以工作。

正如所宣传的那样,index.html 包含可以正常工作的打字稿。但我还使用带有预加载脚本的webview 标签,以便显示外部网站并修改它们。这是我正在使用的代码:

<webview id="webview" preload="./preload.ts" webpreferences="contextIsolation, webSecurity=no" src="https://example.com"></webview>
Run Code Online (Sandbox Code Playgroud)

这个预加载脚本相当复杂,我很想使用打字稿。但它显然被解析为 javascript,任何类型注释都会导致语法错误。有什么技巧可以让打字稿发挥作用吗?如果我必须手动调用转译器,如何将其与 electro-forge 的构建过程集成?

tl;dr:预加载脚本被解析为 javascript,尽管 typescript 在其他地方“正常工作”,我也想在这里使用 typescript

tru*_*ktr 5

您可以在预加载文件(或任何文件)中使用 TypeScript。只需ts-node在导入任何 TypeScript 代码之前导入包并配置它即可。

Fe,创建一个index.js包含以下内容的文件:

require('./require-hooks')
module.exports = require('./entry') // this is your TypeScript entry point.
Run Code Online (Sandbox Code Playgroud)

然后在你的require-hooks.js文件中配置 ts-node (ts-node 是一个 require 钩子,可以动态编译 TypeScript,并为后续运行提供缓存):

// 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,
})
Run Code Online (Sandbox Code Playgroud)

请注意,您可以在其中放置各种 require 挂钩,例如,这样您就可以执行诸如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')等操作,您可以在其中定义用于处理某些类型文件的挂钩(在某种程度上类似于 Webpack,但挂钩到节点的内置require函数)。例如,@babel/register是一个通过 Babel 运行 JS 文件的钩子,asset-require-hook是一个 require 钩子,允许您导入 JPG 文件等资源,yaml-hook允许您require .yaml文件。编辑:甚至更多:css-modules-require-hook用于导入 CSS 模块,以及module-alias创建别名(例如使用 WebPack)。

pirates库是一个流行的工具,用于创建您自己的 require 挂钩,尽管我也发现在没有库的情况下手动创建挂钩很容易。例如,您可以重写Module.prototype.require以实现一些简单的挂钩:

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)
  }
}
Run Code Online (Sandbox Code Playgroud)

然后在其他一些文件中,

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
Run Code Online (Sandbox Code Playgroud)

您甚至可以将调用移至document.createElement('img').src = img重写的require方法中以自动执行并返回img元素而不是返回file://URL。:)

最后,在./entry.ts上述index.js文件导入的文件中,您可以在其中包含任何 TypeScript。


小智 1

预加载脚本是不同类型的,你不能直接将打字稿指向那里。唯一可能的方法是制作 javascript 预加载脚本,其中bootstraps电子在其中进行编译(因为您使用的是电子预构建编译),并且需要其中的打字稿文件。它有点冗长并且需要额外的开销,老实说我不强烈推荐它。