想请教一下 Creator 3 对npm包的引入原理

我猜测你这里 npm 包源码是 esm 格式的 ts 文件,是否还会通过 tsc 编译成 CommonJS 的 js 文件呢?如果是这样的话,应该会编译成

// index.js
module.exports.apiBase = ...

而编辑器的 build tool 只会处理 npm 包实际导出的 js 文件,即 index.js
这个 index.js 会被编辑器的 build tool 做多一次包装,包装成类似这样的模块

export const __cjsMetaURL = 'pack:///chunks/...';
export const default = {
    apiBase: ...,
};  // 注意:这个 default 对象的所有属性是运行时动态赋值的,因为 CommonJS 并不能被很好地支持静态解析
// 所以目前也没有办法解析生成  `export const apiBase = ...` 这样的导出语句。

所以后面的一系列输出应该就可以理解了,

import api from "api";  // 其实就是 `import { default as api } from 'api'`, api 就是 default 对象

import * as api from "api";   // 输出就是 index.js 导出的所有对象,包括 __cjsMetaURL  和 default

import { apiBase } from "api"; // 就有问题了,因为 index.js 没有导出 apiBase 对象, 就报错了
// 这里可能报错信息有一些误导性,应该不是循环引用导致的,这个后续我们优化一下

import { default as _default } from "api";  // 同上 `import api from "api";`
1赞

所以可以被解决吗?因为npm上其他包也出现了类似的问题,我知道这样说有点委屈你们,但是无论原理上是什么样子,无法正常引入就可以算是cocos的bug :joy: 因为一个npm包没办法用正常的方式使用了。

我的包是用比较规范的方式构建的,cjs、esm格式都有。用的是字节的modernjs框架直接生成的包。如果有任何问题,需要我的都可以问我,我会尽量提供细节。

1赞

问一下目前 npm 包是否配置了条件导出呢,不太确定是不是我们的 build tool 对条件导出的解析有问题,如果解析到 cjs 的入口,可能就出错了

可以贴一下 package.json 下 exports 字段的相关信息吗

这样,我之前提到的另一个帖子中的 typedjson这个包也是同样的问题,如果方便的话可以测试一下。我一会儿也再找一些类似的例子看看。 package的信息我稍等贴出来

package.json相关内容:

  "jsnext:source": "./src/index.ts",
  "types": "./dist/types/index.d.ts",
  "main": "./dist/js/node/index.js",
  "module": "./dist/js/treeshaking/index.js",
  "jsnext:modern": "./dist/js/modern/index.js",

构建结果:

image

modern 里面:

export const apiBase = ...

node 里面:

exports.apiBase = apiBase;

treeshaking 里面:

export var apiBase = ...

了解了,我这边也做了一些测试,node 上确实是能够支持 ESM 模块以具名导入的方式导入 CJS 模块的,但是支持也是相对有限,

例如下边例子中的变量 d

// main.mjs
import { a, b, c, d } from './test.cjs';
console.log(a, b, c, d)

setTimeout(() => {
    console.log(a, b, c, d)  // 这里的 d 依旧是 undefined,是不支持 live binding 的
}, 2000)

// test.cjs
module.exports.a = 'a';
module.exports['b'] = 'b';
Object.defineProperty(module.exports, 'c', {
    value: 'c'
});
setTimeout(() => {
    console.log('dynamic assign d');
    module.exports['d'] = 'd';
}, 1000)

下边这种情况也不支持


// main.mjs
import { test } from './test.cjs';
console.log(test)

// test.cjs
module.exports['te' + 'st'] = 'test';

我们可以排期把前边 a b c 的情况支持掉

1赞

好的 :+1: 非常感谢

以及请问cocos对多种导入模式的优先级是怎样的?

应该是以 conditional exports 为最高优先级,其次是 main 作为 legacy 方案

conditional exports 不支持 node 导出,因为 node 环境并不能实现跨平台

1赞

你的还没能使用吗?心痛1999

没有,我这边也可以用同样的方法解决一下,但是并不是完美方案。

哥们呢还是别纠结了,其他bug还一堆呢,官方很忙,不建议在这方面浪费精力

不能这样想。我们现在只能解决“你 引用了 包A”的情况,那如果“包A”用同样不被兼容的方式引入了“包B”,是不是就不行了。这种情况还挺常见的。

就比如,你能通过之前的方式引入typedjson,但是有一天你必须要用的另一个包也引入了typedjson并且报了同样的错,该怎么办?进一步的,如果是包引用包引用包这样的递归情况中,任一环节出了问题,是不是这个包就没法用了。这是一个复合概率,会随着包的复杂程度而增加,最后变成 100%。

那你岂不是需要把所有包里面的引用都改成先cocos应用typedjson那种?
好像现在有ide大范围查找,虽然比较艰难,但还是可以做到的。期待下,我很少上论坛,除非遇到问题,还是很感谢你帮我一个大忙的,但是我一直都对官方不大抱希望,比如你这个需求提出来,怎么说,最快也得等到明年末才能做到你想要的那个功能,如果迟疑一点的话,那就几乎可以跨越很多年了

所以不能这样做,因为这样不现实,也不正确,怎么能去动node_modules里面的东西呢。

所以正确的方式是,让 cocos 正确支持各种 import 的方式,保证不出错,而不是去动包。要解决问题不能去解决出问题的人啊 :joy:

是的,你的想法是对的,但是没法,这个毕竟不是官方急,人家有其他功能要做,很少会把你的需求优先级提上去,别问我怎么知道。能自己弄就自己弄吧

能做的就是提供一些解决思路,以及把重要性描述清楚,然后相信官方。

(毕竟除了官方也没人能信了)还是希望并感谢官方尽快排期解决。

1赞

期待下吧,手动狗头

我们这边使用了msgpackr库,但是最后可用版本是1.2.11,超过此版本后,浏览器无措,真机启动黑屏。
想探讨一下是什么原因。

npm i @race-foundation/borsh
npm i @race-foundation/sdk-core
npm i @race-foundation/sdk-solana
npm i @race-foundation/sdk-facade
大佬,我使用上面任意一个npm都无法运行,请问什么问题,如何解决,查了很多,都没有找到解决方案
import { FacadeTransport } from ‘@race-foundation/sdk-facade’;
console.log(FacadeTransport , “FacadeTransport********”);
就是引用,然后Log就出问题了

@Sttot @_PP 两位能帮看下吗?等着救命啊