处理 es6 模块中的依赖关系,用于节点和浏览器

Posted

技术标签:

【中文标题】处理 es6 模块中的依赖关系,用于节点和浏览器【英文标题】:Handling dependencies in es6 module, intended for node and browser 【发布时间】:2020-10-08 21:25:08 【问题描述】:

我编写了一个 javascript 库作为 ES6 模块,主要用于浏览器。现在我想为节点打包它。我可以限制到节点 v 14+。我不想转译。

我不确定如何处理依赖项。特别是moment-js,给我带来了麻烦。

在浏览器中(尝试了最新的 FF + Chrome),我在 <script> 标记中引用了矩库,然后在我的代码中,我可以只使用变量 moment,而不必先导入它。

my-module.js:

function testFn() 
  return moment.duration(300).asSeconds();


export  testFn 

browser code

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js"></script>
<script type="module" src="my-module.js"></script>
<script>

import  testFn  from 'my-module.js';
let val = testFn();
console.log(val); 

</script>

但是,在节点中,我需要模块包含 import 才能使其工作:

my-module.js:

import moment from 'moment';

function testFn() 
  return moment.duration(300).asSeconds();


export  testFn 

然后我可以在节点中使用my-module

import  testFn  from 'my-module.js';

let val = testFn();
console.log(val); 

但是,现在浏览器代码坏了: TypeError: Error resolving module specifier: moment

我尝试了不同的 imports (import * as ..., import moment from ...) 但没有运气 - 浏览器仍然在抱怨。

Moment-js 只是一个例子——我想要一个通用的解决方案,因为我也有其他依赖项。

这一定是其他人已经遇到并解决的问题,而无需求助于检测环境和有条件导入等糟糕的解决方法。有没有人有好的解决方案或参考?谢谢!!

【问题讨论】:

你把npm安装到目录了吗?看起来您以前使用过 cdn,只是想覆盖基础 是的,模块文件夹通过 npm 安装了依赖项(moment-js)。否则导入语句根本不起作用。问题是,当在浏览器中运行的脚本中使用模块时,在模块源中包含该语句会引发错误,而在节点环境中,如果没有它,它将无法工作。 我觉得这可能是那些很简单但仍然需要几个小时才能弄清楚的愚蠢事情之一,哈哈。比如需要某些模块的顺序 有很好的理由,人们使用转译器。像这个。有一个动态 import() 可能对您的情况有所帮助:v8.dev/features/dynamic-import 或者,您可以在全局范围内注册您的第三方库(工作人员的自我,浏览器的窗口和节点中的全局。或者只是在较新的环境中使用 globalThis ) 您需要提供包的相对路径,因为浏览器无法像 nodejs 那样解析 node_modules 路径。在这里,检查这个答案:***.com/a/52558858/6080889 【参考方案1】:

您是否尝试过import * as moment from "./moment.js";(您可能需要根据安装位置以及moment 处理文件的方式来调整路径)?

浏览器不支持裸导入,我相信像 moment 这样的旧库仍然是裸的。

另外我只想说,这正是转译和构建工具的优势所在。它可以使处理这种情况变得更加简单。有些东西不能有条件地检查,你只需要转译到最低的兼容性。

【讨论】:

【参考方案2】:

这应该有点像下面的警告:

const M = typeof moment !== 'undefined' ? moment
  : (await import('moment')).default
截至目前,*** await 仅适用于 chrome、node 和 firefox canary 正式来说,*** await 仍然只是第 3 阶段的提案

【讨论】:

【参考方案3】:

package.json 中设置 main:main.jsbrowser:browser.js 字段,在导入和重新导出之前设置任何特定于环境的元素通用 index.js 模块。

//main.js fix for nodejs
import something from 'nodejsSpecificModule'
global.something = something //or export whatever is needed
export ... from './index.js'
//browser.js fix for browser
import something from 'browserSpecificModule'
window.something = something //or export whatever is needed
export ... from './index.js'

这避免了使用***等待的动态导入

【讨论】:

以上是关于处理 es6 模块中的依赖关系,用于节点和浏览器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ES6 模块模拟单元测试的依赖关系

es6:module模块(export,import)

记录 script module

ES6语法总结-Module的语法

ES6模块加载

模块化es6规范