Creator 3.x npm包 一些坑的解决方法(新手向)

看了相关的文档
外部模块使用案例 · Cocos Creator
https://docs.cocos.com/creator/manual/zh/scripting/modules/example.html
模块规范 · Cocos Creator
https://docs.cocos.com/creator/manual/zh/scripting/modules/spec.html

在论坛中看了n个相关的帖子
这些帖子中的解释说明比较有帮助



把碰到的几种情况解决了,所以菜菜地、啰嗦地分享一下
因为本身是新手,所以按照新手的思路,自问自答一些碰到的疑问(不一定对,但就还…挺自洽的)


0、包里没有web版本
用不了,放弃

一、正常情况,ESM模块 + 有web版本 + 指向web版本

比如 msgpackr

// 命令行install后
npm install --save msgpackr

// 直接就能用
import { pack } from "msgpackr";

二、CJS模块 + 没有默认导出

比如 @msgpack/msgpack

// 命令行install后
npm install --save @msgpack/msgpack

// import里有代码提示,但是打印出来是undefined
import { encode } from "@msgpack/msgpack";

// 输出undefined
console.log(encode);

这种情况下

// 需要在 tsconfig.json 中加上这个,允许默认导入
"allowSyntheticDefaultImports": true

// 然后改用如下写法
import msgpack from "@msgpack/msgpack";
const { encode } = msgpack;

三、CJS模块 + 没有默认导出 + 指向Node版本 + 没有声明文件 + 没有Web版本声明文件 (天选npm包)

比如 msgpack-lite

// 命令行install后
npm install --save msgpack-lite

出现这个警告

npm install --save-dev @types/msgpack-lite

执行上述命令后,警告消失了,node_modules下多了这些文件
image

// 但还是和2一样输出undefined
console.log(encode);

// 和2一样解决
// 改用如下写法
import msgpack from "msgpack-lite";
const { encode } = msgpack;

// 红线提示“没有默认导出”,则在 tsconfig.json 中加上这个
"allowSyntheticDefaultImports": true

在编辑器控制台中输出的是 [Scene] [Function: encode]
但是在浏览器中预览时报错了
因为指向的是Node版本
image

所以需要改用如下写法,导入web版本
“Web 版本放在包下的 dist/xxx.js 或者 dist/xxx.min.js 文件里”

import msgpack from "msgpack-lite/dist/msgpack.min.js";

但是又出现了警告,因为没有web版本的声明文件

所以需要在这个路径下建一个同名的声明文件 msgpack.min.d.ts
里面写上

declare module "msgpack-lite/dist/msgpack.min.js" {
    export * from "msgpack-lite";
}

借用Node版本的类型声明,警告就消失了,搞定

文档中写的是 “任意新建个 .d.ts 到项目里”
测试多次后,发现不太准确,必须同名(包括min)
不是所有路径都可以,部分路径还是不行
所以仿照其他包的规则,就放在同一路径吧,也方便管理


自问自答(可能有几个答得不一定准确)


怎么判断是ESM模块,还是CJS模块?
包的 package.json 中
有一级字段,“type”: “module”,则是ESM模块
否则就是CJS模块
(其实吧,看import有没有问题就是了)

怎么判断包里有没有web版本?
包里有没有这个文件
dist/xxx.js 或者 dist/xxx.min.js

怎么判断指向什么版本?
光看 package.json 中的main字段,好像也不太准
因为msgpackr中的还长这样呢,“main”: “./dist/node.cjs”,但还是能直接from “msgpackr”
好像和这个有关
“在新版的 Node 里,package.json 加入了一个很好的机制来告诉用户什么情况应该使用哪个版本。”
是exports字段?
(其实吧,看浏览器预览会不会报错就是了)

怎么判断有没有默认导出?
index.js 里没有 module.exports 这种写法,就没有默认导出
(其实吧,看代码红线就是了)

怎么判断有没有声明文件?
没有对应的 index.d.ts
(其实吧,看代码警告就是了)

怎么判断有没有web版本声明文件?
没有对应的 dist/xxx.min.d.ts
(其实吧,看代码警告就是了)


更多自问自答


为什么npm包里没有web版本就用不了?
模块规范 · Cocos Creator
https://docs.cocos.com/creator/manual/zh/scripting/modules/spec.html

// 因为上面文档中的原文是
“Cocos Creator 支持 Web 平台”
“Cocos Creator 并不支持 Node.js 内置模块”

为什么import里有代码提示,但是打印出来是undefined?
https://nodejs.org/api/esm.html#interoperability-with-commonjs
The detection of named exports is based on common syntax patterns but does not always correctly detect named exports. In these cases, using the default import form described above can be a better option.

因为和CJS模块交互时,虽然有支持静态代码分析,但不是一定奏效
有具体写法有关,像这种简单的才行吧

module.exports.c = 3;

import { c } from './foo.js'
console.log(c); // 3

只有这里面列出的npm包才能用吗?
Can I use … npm module…
https://shrinktofit.github.io/can-i-use-npm-in-cocos-creator/
不是,这些只是反馈记录而已

5赞

下个版本我们会优化“使用Web版本”的情况。那个网站只是列举了一些反馈过得包的用法