为浏览器和nodejs构建

时间:2017-06-22 20:42:30

标签: javascript node.js typescript browser

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

我有三个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(){}
}

query.ts 文件:

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

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

我想使用它们的方式如下:

的NodeJS

namespace

浏览器

const libjs = require('libjs')
let c = libjs.collect([1, 123, 123, 1231, 32, 4])

1 个答案:

答案 0 :(得分:1)

当您编译顶级export ...的文件时,每个文件都被视为具有自己范围的模块,每个文件中的namespace libjs是不同的,并且与libjs分开在每个其他文件中。

如果要生成可在没有模块加载器的浏览器中使用的单个脚本(将libjs定义为全局),则必须删除所有顶级导出,并且不要设置module完全在tsconfig

<强>组件/ collections.ts

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

<强>组件/ query.ts

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

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

<强> index.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中的节点中立即使用生成的脚本:

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

为节点

完成 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;

<强>测试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完全不需要模块。