【问题标题】:Dynamically loading a module that is not in a script tag with type="module"?动态加载不在 type="module" 的脚本标签中的模块?
【发布时间】:2018-11-06 19:45:41
【问题描述】:

是否可以在没有脚本标签的情况下为所述模块使用导入?

我的问题是我想根据配置文件动态加载模块,例如:

文件夹结构:

|-- main.js
|-- config.json.js
|-- modules
    |-- module1.js
    |-- module2.js
    |-- module3.js

Index.html 头:

<script src="/config.json.js" type="module"></script>
<script src="/main.js"></script>

config.json.js:

export default {

  modules : ['module1', 'module3']

}

main.js:

import config from '/config.json.js'

//Loading modules defined in config
config.modules.forEach(moduleName => {
  import(`modules/${moduleName}`)
  .then( module => {
    console.log(`${module.name} loaded.`);
  )}
})

由于模块尚未在脚本标签中定义,因此上述方法不起作用。

有没有什么方法可以使用 vanilla JS 实现这一点并保持干净?

【问题讨论】:

  • 框架是用vanilla JS编写的,所以如果它在框架中是可能的,那么在JS中也是可能的。也就是说,这似乎有点像滥用模块。
  • 能否动态创建脚本标签并将其附加到头部?
  • 你根本不需要&lt;script src="/config.json.js" type="module"&gt;&lt;/script&gt;,删除它。而是必须使用 type="module" 包含 importing 文件。

标签: javascript ecmascript-6 es6-modules


【解决方案1】:

可以,只要您的加载程序脚本标记为module

<script type="module">
  const moduleSpecifier = './myModule.mjs';
  import(moduleSpecifier)
    .then((module) => {
      // do something
    });
</script>

尽管在您的情况下,简单的forEach 可能还不够。如果您想等待所有模块从您的配置中加载,您可能需要Promise.all 或类似名称。

const modules = config.modules.map(moduleName => import(`modules/${moduleName}`))

Promise.all(modules)
  .then(modules => {
    // modules is an array of all your loaded modules
    console.log('All modules loaded.');
  )}

进一步阅读:

【讨论】:

  • 谢谢你,漂亮的答案,尽管模块属性进入加载器而不是模块似乎有点奇怪,我很高兴它是这样的。
  • 我刚刚意识到,如果任何动态加载的模块内部也有导入,这将不起作用,对吧?
【解决方案2】:

编辑! Dynamic import has landed in Firefox 67+.

  (async () => {
    await import('./synth/BubbleSynth.js')
  })()

https://caniuse.com/#feat=es6-module-dynamic-import


旧答案:

在 DOM 加载后导入更多模块,一种不太干净但可行的方法是创建一个新的模块类型的调用者脚本。

/* Example */
/* Loading BubbleSynth.js from «synth» folder*/
let dynamicModules = document.createElement("script")
dynamicModules.type = "module"
dynamicModules.innerText = "import * as bsynth from '../synth/BubbleSynth.js'"
/* One module script already exist. eq: «main.js», append after it */ 
document.querySelector("script[type='module']").parentElement.appendChild(dynamicModules)

销毁模块调用者脚本不会损害过去的调用:

document.querySelectorAll("script[type='module']")[1].outerHTML = ""
// *BubbleSynth* is still in memory and is running

但是向该脚本附加一个新的模块调用不起作用。必须创建一个新的调用者模块脚本。

作为一个函数:

function dynModule(me){
  let dyn = document.createElement("script")
  dyn.type = "module"
  dyn.innerText = `import * as ${me} from '../synth/${me}.js'`
  document.querySelector("script[type='module']").parentElement.appendChild(dyn)
  document.querySelectorAll("script[type='module']")[1].outerHTML = ""
}

dynModule("BubbleSynth")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-14
    • 2020-02-25
    • 1970-01-01
    • 2018-06-07
    • 2015-05-08
    • 2018-07-20
    • 1970-01-01
    • 2015-07-27
    相关资源
    最近更新 更多