我正在尝试制作一个既可以在浏览器中又可以在 Node 中运行的库。
我有三个 json 配置文件,后两个扩展 tsconfig.json
- tsconfig.json(仅包含构建文件)
- tsconfig.browser.json
- tsconfig.node.json
tsconfig.browser.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"target": "es6",
"module": "system",
"outFile": "../dist/browser/libjs.js",
"removeComments": true,
"declaration": true
}
}
tsconfig.node.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../dist/node",
"removeComments": true,
"declaration": true,
"declarationDir": "../dist/node/typings"
},
"files": [
"./index"
]
}
我有这个 index.ts 文件(仅包含在 Node 构建中):
export { collect } from './components/collections'
export { query } from './components/query'
然后我在 collections.ts 文件中有这个:
export namespace libjs {
export function collect<T>(data: T[]) {
// Do some stuff
}
export class collection(){}
}
还有这个query.ts 文件:
export namespace libjs {
export class query<T> {
private _results: collection<T>
}
}
我遇到的问题是,当我尝试构建到 Node 时,索引文件找不到 collect
函数,而当我构建到浏览器时,query
类找不到 collection
类。最好的编码方式是什么,以便我可以构建到 Node 和浏览器?如果我删除 namespace
上的 export
,我可以很好地构建到浏览器,但我无法构建到 Node 。
我想使用它们的方式如下:
Node
const libjs = require('libjs')
let c = libjs.collect([1, 123, 123, 1231, 32, 4])
浏览器
<script src="/js/libjs.js"></script>
<script>
let c = libjs.collect([1, 123, 123, 1231, 32, 4])
</script>
最佳答案
当你编译在顶层有 export ...
的文件时,每个文件都被视为一个有自己范围的模块,每个文件中都有 namespace libjs
与所有其他文件中的 libjs
不同并分开。
如果你想生成一个可以在没有模块加载器的浏览器中使用的脚本(将 libjs
定义为全局),你必须删除所有顶层导出,并且不要设置 module
在 tsconfig
中:
components/collections.ts
namespace libjs {
export function collect<T>(data: T[]) {
// Do some stuff
}
export class collection<T>{}
}
components/query.ts
namespace libjs {
export class query<T> {
private _results: collection<T>
}
}
现在,您也可以在 Node 中使用相同的生成脚本,如果您添加在运行时检测 Node 环境的代码并将 libjs
分配给 module.exports
:
index.ts
namespace libjs {
declare var module: any;
if (typeof module !== "undefined" && module.exports) {
module.exports = libjs;
}
}
用于浏览器和 Node 的单个 tsconfig.json(请注意,我将输出从 ../dist
更改为 dist
)
{
"compilerOptions": {
"outFile": "./dist/libjs.js",
"removeComments": true,
"declaration": true
},
"files": [
"components/collections.ts",
"components/query.ts",
"index.ts"
]
}
您可以在 javascript 的 Node 中立即使用生成的脚本:
test-js.js
const lib = require('./dist/libjs')
console.log(typeof lib.collect);
let c = lib.collect([1, 123, 123, 1231, 32, 4])
不幸的是,您不能在带有生成的 libjs.d.ts
的 typescript Node 中使用它,因为它将 libjs
声明为全局的。对于 Node ,您需要单独的 libjs.d.ts
,其中包含一个您必须手动添加或作为构建过程的一部分添加的附加 export = libjs
语句:
完成 Node 的dist/libjs.d.ts
declare namespace libjs {
function collect<T>(data: T[]): void;
class collection<T> {
}
}
declare namespace libjs {
class query<T> {
private _results;
}
}
declare namespace libjs {
}
// this line needs to be added manually after compilation
export = libjs;
test-ts.ts
import libjs = require('./dist/libjs');
console.log(typeof libjs.collect);
let c = libjs.collect([1, 123, 123, 1231, 32, 4])
tsconfig.test.json
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"removeComments": true
},
"files": [
"./test-ts.ts",
"./dist/libjs.d.ts"
]
}
你可以选择走一条完全不同的路线,构建一个由模块组成的库,但为此你必须在浏览器中使用模块加载器(或使用 webpack 构建),你可能需要阅读 this answer解释为什么 namespace libjs
对于模块来说是完全不必要的。
关于javascript - 为浏览器和 nodejs 构建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44709031/