为浏览器和 nodejs 构建



我正在尝试创建一个既可以在浏览器中又可以在节点中工作的库。

我有三个 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文件(仅包含在节点构建中):

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(){}
}

而这个查询.ts文件:

export namespace libjs {
export class query<T> {
private _results: collection<T>
}
}

我遇到的问题是,当我尝试构建到节点时,索引文件找不到collect函数,当我构建到浏览器时,query类找不到collection类。编写代码以便我可以同时构建节点和浏览器的最佳方法是什么?如果我删除namespace上的export,我可以很好地构建到浏览器,但我不能构建到节点。

我想使用这些方法如下:

Nodejs

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定义为全局),则必须删除所有顶级导出,并且根本不tsconfig中设置module

组件/集合.ts

namespace libjs {
export function collect<T>(data: T[]) {
// Do some stuff
}
export class collection<T>{}
}

组件/查询.ts

namespace libjs {
export class query<T> {
private _results: collection<T>
}
}

现在,您也可以在节点中使用相同的生成脚本,如果您添加在运行时检测节点环境并将libjs分配给module.exports的代码:

索引.ts

namespace libjs {
declare var module: any;
if (typeof module !== "undefined" && module.exports) {
module.exports = libjs;
}
}

浏览器和节点的单个tsconfig.json(请注意,我将输出从../dist更改为dist)

{
"compilerOptions": {
"outFile": "./dist/libjs.js",
"removeComments": true,
"declaration": true
},
"files": [
"components/collections.ts",
"components/query.ts",
"index.ts"
]
}

您可以在javascript的node中立即使用生成的脚本:

测试-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的打字稿的节点中使用它,因为它将libjs声明为全局。对于 node,您需要单独的libjs.d.ts,其中包含一个附加的export = libjs语句,您必须手动添加该语句或作为构建过程的一部分添加该语句:

Completedist/libjs.d.tsfor node

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;

测试-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 构建),并且您可能需要阅读此答案解释为什么模块完全不需要namespace libjs

最新更新