简体   繁体   English

动态加载 web 工作人员。 解决相对导入的错误

[英]Load web workers dynamically. Errors resolving relative imports

Context:语境:

I am loading several web workers in a dynamic way by using blob-based URIs.我正在使用基于 blob 的 URI 以动态方式加载几个 web 工作人员。 In my problem, this strategy is required because workers' content is partially generated using a template-based solution.在我的问题中,这种策略是必需的,因为工作人员的内容部分是使用基于模板的解决方案生成的。 See (1) in code见代码中的(1)

Problem:问题:

Web workers include import sentences with relative paths. Web 工作人员包括带有相对路径的import语句。 As they are loaded using the Worker constructor and it does not allow to specify a base path, relative imports cannot be properly resolved as absolute references.由于它们是使用Worker构造函数加载的,并且不允许指定基本路径,因此无法将相对导入正确解析为绝对引用。 As a result, the worker loading process fails with no console message (I guess a 404 error is under the hood).结果,工作程序加载过程失败,没有控制台消息(我猜是 404 错误在引擎盖下)。

Example:例子:

In this example we have created the following set of resources:在此示例中,我们创建了以下资源集:

index.html
/scripts
  /helpers
     helper.x.js
     helper.y.js
  /loader
     loader.js
  /workers
     worker.x.js

We have created a dynamic loader in loader.js:我们在 loader.js 中创建了一个动态加载器:

function Loader () {

  function asCode (text) { ... }

  async function load (path) {
    let response = await fetch (path)
    let text     = await response.text ()
    let code     = asCode (text) // (1)
    let blob     = new Blob ([code], { type: 'text/javascript' })
    let url      = URL.createObjectURL(blob)
    let worker   = new Worker (url, { type: 'module' })
    return worker
  }

  return { load }
}

export default Loader ()

The worker in worker.x.js imports two naive helpers X & Y by using relative paths. worker.x.js 中的 worker 使用相对路径导入两个简单的助手 X 和 Y。 Please, notice that if the path in import sentences where absolute (http://...) the problem described here would not appear:请注意,如果 import 语句中的路径绝对(http://...),则不会出现此处描述的问题:

  import X from '../helpers/helper.x.js'
  import Y from '../helpers/helper.y.js'

  X.fx ()
  Y.fy ()

Finally, in index.html we load the worker:最后,在 index.html 中,我们加载了 worker:

<body>
   <script type="module">
     import Loader from './scripts/loader/loader.js'
     let WX = Loader.load ('./scripts/workers/worker.x.js')
   </script>
</body>

Please, visit this replit to explore the project.请访问此副本以探索该项目。

Question:问题:

Is there any way to load web worker scripts in a dynamic way specifying the base path that must be used to resolve relative paths in inner import sentences?有没有办法以动态方式加载 web 工作脚本,指定必须用于解析内部导入语句中的相对路径的基本路径? For me, an extension of the Worker constructor with a new base parameter like this would be perfect:)对我来说,使用这样的新base参数扩展 Worker 构造函数将是完美的:)

let WX = new Worker (path, { type: 'module', base: 'the-base-path' })

You could use your asCode method to also inject the base URI.您也可以使用asCode方法注入基本 URI。

In your template, insert a marker in front of your relative URLs that you'll replace at the time of building your blob.在您的模板中,在您将在构建 Blob 时替换的相对 URL 前面插入一个标记。
To get the "fake" base URL as an absolute one, you can check the Response object you get from fetch() and extract the directory path from its .url property.要获得绝对的“假”基础 URL,您可以检查从fetch()获得的Response object 并从其.url属性中提取目录路径。

Now, your "dynamic" module imports absolute paths and everyone is happy: loader.js现在,您的“动态”模块导入绝对路径,每个人都很高兴: loader.js

function Loader () {

  function asCode (text, baseURI) {
    return baseURI
      ? text.replace(/\$base_url\$/g, baseURI)
      : text;
  }
  
  async function load (path) {
    let response = await fetch (path)
    let text     = await response.text ()
    let absolute = response.url;
    // remove the worker script's file name to get its base URI
    let href     = absolute.substring(0, absolute.lastIndexOf('/'));
    let code     = asCode (text, href)
    let blob     = new Blob ([code], {type: 'text/javascript' })
    let url      = URL.createObjectURL(blob)
    let worker   = new Worker (url, { type: 'module' })
    return worker
  }

  return { load }
}

export default Loader ()

And worker.x.js now looks like worker.x.js现在看起来像

import X from '$base_url$/../helpers/helper.x.js'
import Y from '$base_url$/../helpers/helper.y.js'

X.fx ()
Y.fy ()

Updated repl.it.更新了 repl.it。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM