动态加载不在 type="module" 脚本标记中的模块?

Dynamically loading a module that is not in a script tag with type="module"?

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

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

文件夹结构:

|-- 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 实现这一点并保持它的清洁?

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

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

尽管在您的情况下,简单的 forEach 可能还不够。如果你想等待 all 模块从你的配置加载,你可能需要 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.');
  )}

延伸阅读:

编辑! 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")