与动态导入而不是普通 <script> 标记链接时脚本损坏

A script broken when linked with dynamic import instead of plain <script> tag

我有一个自制的音频播放器,当通过常规 script 标签 link 进入页面时,它在我的网站上完美运行:

<head>
  …
  <script type="application/javascript" src="/static/js/player.js"></script>
</head>

脚本本身是用纯JS编写的,没有任何库、框架等。Here is the demo of how it works:你按下三角,播放器开始播放;这里没有什么特别的。 (在某些旧浏览器中可能无法正常工作,但现在这无关紧要。)

但是,如果我 link 使用动态导入(在支持这种导入的浏览器中),播放器就会损坏。在 HTML 中,另一个脚本 index.js 被 linked 而不是 player.js,并且这个 index.js 导入 player.js:

// index.js
console.log('index.js is running…');
import('/static/js/player.js');

Here is the second demo of this version,在 Windows 上的 Chrome 和 macOS 上的 Safari 中测试,所有浏览器和 OS 的最新版本在这一刻 post.

player.js 似乎正在加载和执行。当我在其中包含 console.log()s 时,它会准确地将它们输出到我期望的位置;我也没有发现与以前版本的调试器在开发工具中有任何运行时差异。

但在这种情况下音频播放器不工作。如果您按下三角形,那么您不会启动播放器,而只会直接 link 到 MP3 文件。最初,这是脚本未加载或损坏时的预期行为;但我无法弄清楚在这种情况下究竟发生了什么。

脚本player.js在这两种情况下完全相同;唯一的区别是在第二种情况下添加动态导入。请帮我找出问题所在。

由于旧版本的 JS 没有导入,但自 2015 年(ES6)以来,JS 具有 ES6 模块标准,可以在 NodeJS 中导入模块。

我会尝试这两种不同方法中的一种来使其工作:

1 - 使用来自 index.js 文件的脚本标签动态加载,例如:

Index.js:

function dynamicallyLoadScript(jsFilePath) {
    var js = document.createElement("script");

    js.type = "text/javascript";
    js.src = jsFilePath;

    document.body.appendChild(js);
    //or: document.head.appendChild(script); 
}

dynamicallyLoadScript("/static/js/player.js");

2 - 或使用新的 ES6 模块导入(记得将 player 文件与 mjs扩展名!):

<script type="module">
  import { player } from './static/js/player.mjs';
  player();
</script>

Player.mjs:

export function player() {
   //Your code here
}

此外,如果您需要旧浏览器兼容性,您可以使用一些工具,如 Babel 或 Webpack。您可以在这里找到更多信息:How do I include a JavaScript file in another JavaScript file?

希望对您有所帮助!

您将 js 文件放在 header 上,这就是神奇发生的地方。 如果您阅读 player.js 文件,您会看到播放器在 DOMContentLoaded

上回复
new Effect({  // container
behavior: `
  $window
    DOMContentLoaded
      _.init
`,
prop
....

在你的第一个例子中,你的网站基本上停止加载,直到 player.js 加载,因为你把它放在 header, player.js 能够将事件绑定到 DOMContentLoaded。然后,在所有初始 HTML 文档完全加载和解析后,事件 DOMContentLoaded 触发,您的播放器可以启动

关于你的第二个例子,http://dev.chebykin.ru/player/02/。事件 DOMContentLoaded 将在文件 player.js 上的脚本之后触发,因为您通过导入命令加载了文件。即使您的脚本仍然能够绑定事件 DOMContentLoaded,但它已经触发,所以它没有效果

您可以简单地尝试在 Chrome 控制台上再次手动触发事件,并且会看到您的播放器使用此脚本可以正常工作

window.dispatchEvent(new Event('DOMContentLoaded'))