编写 TypeScript 并为浏览器和 Node 生成一个库

Write TypeScript and emit a library for Browser and Node

我有一个在 Node.js 和浏览器中使用的内部库。它有许多文件,与 Grunt 任务和不同的序言连接在一起,一个用于浏览器,一个用于 Node:

浏览器:

// dependent 3rd-party libs like Mustache are already global
window.myLib = { /*just a namespace object filled with stuff later*/ }

// then comes the plain javascript which just adds elements to myLib.
// This part is identical to that used in Node
// example:
myLib.renderPartDetail = function (...) {...};

节点:

var Mustache = require('mustache');
var myLib = {};
module.exports = myLib;

// then comes the plain javascript which just adds elements to myLib.
// This part is identical to that used in Browser

这会产生 2 个不同的单一输出 js 文件,一个用于浏览器,一个用于 Node。

我想要什么

我有什么困惑[=​​63=]

我在 TypeScript 中发现了 2 种不同的模块处理方式:

import {a, b} from './x'

import c = require('./y')

我从 node 习惯了后者,但第一个看起来像 ES6(可能是未来)。

目前我使用tsc --module commonjs但这只是输出格式,对吧?还有 --module system 但我找不到此选项的文档,当我使用它时,编译器抱怨 export = ... is not allowed.

还没有玩过 browserifytsifywatchifyjspm、SystemJS、webpack - 它太相似了很多,但我认为这些工具中的一个或几个可以为我完成这项工作。

而当我require(<a node module living in node_modules>)时,tsc找不到模块:"TS2307: Cannot find external module 'moment'".

具体问题

  • 我应该在我的代码中使用哪种模块语法才能最好地使用 Node 和浏览器?
  • 哪个工具链可以解决我的需求?有没有我可以从中复制的示例项目或样板? (我也对 Gulp 持开放态度,不必使用 Grunt)。
  • 目前支持哪些 TypeScript 和 Node 版本?我在 IntelliJ 中嵌入了 1.4,当将 1.6.2 引用为外部时,我收到非常深奥的神秘错误消息,例如 "TypeError: host.fileExists is not a function"(没有发现任何有用的信息)。也许使用 Node v4.1.1 不是最佳选择?

很抱歉 post 太复杂了。如有必要,请给我建议从哪里开始,或者最重要的改变或开始的事情是什么。

Which module syntax should I use in my code to best work with Node and Browser?

如果您的目标是 es5,那么两种语法都会编译成实际上相同的东西。使用其中任何一种,并随意混合搭配。

Which tool-chain will solve my requirements? Is there an example project or a boilerplate where I can copy from

我使用(并推荐)webpack。你可以按原样使用 commonjs / nodejs,然后 webpack 可以为前端创建包。有关示例,请参阅 https://github.com/basarat/tsb/tree/master

Which TypeScript and Node versions are currently supported? I'm having 1.4 embedded in IntelliJ, when referencing 1.6.2 as external I'm getting very deep cryptic error messages like "TypeError: host.fileExists is not a function" (not finding anything helpful about this). Maybe it's not optimal to use Node v4.1.1?

使用最新的 TypeScript(来自 TypeStrong 的各种工具,例如 atom-typescript/grunt-ts/ts-loader 支持)。您得到的错误是一个 webstorm 错误,应该报告给他们。 (我使用 atom-typescript)。

我还有 TypeError: host.fileExists WebStorm 10 和自定义 Typescript 编译器(通过 npm 安装)的错误。

但是,这 已在 WebStorm 11(2015 年 11 月 2 日发布)中修复 https://www.jetbrains.com/webstorm/download/

这是我使用 webpack 和 babel 得到它的方式:

我的 index.ts 文件在 src 文件夹中

package.json

{
  "scripts": {
    "bundle-dev" : "rimraf dist && tsc --outDir dist/temp && webpack --env.development --display-error-details && rimraf dist/temp",
    "bundle-prod": "rimraf dist && tsc --outDir dist/temp && webpack --env.production  --display-error-details && rimraf dist/temp"
  },
  "devDependencies": {
    "@babel/core": "^7.11.6",
    "@babel/plugin-transform-reserved-words": "^7.10.4",
    "@babel/plugin-transform-typescript": "^7.11.0",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "@babel/plugin-syntax-flow": "^7.10.4",
    "@babel/preset-env": "^7.11.5",
    "babel-loader": "^8.1.0",
    "esmify": "^2.1.1",
    "rimraf": "^3.0.2",
    "ts-loader": "^8.0.4",
    "ts-node": "^8.10.2",
    "typescript": "^3.9.7",
    "webpack": "^4.44.2",
    "webpack-cli": "^3.3.12"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "module": "AMD",
    "target": "ES5",
    "declaration": true,
    "outDir": "dist/my-javascript-package",
    "moduleResolution": "node"
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "src/**/*"
  ]
}

.babelrc

{
    "plugins": [
        "transform-class-properties",
        "@babel/plugin-syntax-flow",
        "@babel/plugin-transform-reserved-words",
        "@babel/plugin-transform-typescript"
    ]
}

webpack.config.js

const path = require('path');

module.exports = env => {
    const mode = env.production ? 'production' : 'development';

    const config = (target) => {
        return {
            entry: {
                index: './src/index.ts'
            },
            target: target,
            output: {
                path: path.resolve(__dirname, "dist/my-javascript-package"),
                filename: target+'.js',
                library: 'MyJavaScriptPackage',
                libraryTarget: "umd",
                umdNamedDefine: true,
                globalObject: 'this',
            },
            plugins: [
                new (require('webpack')).DefinePlugin({
                    'process.env.NODE_ENV': JSON.stringify(mode)
                }),
            ],
            mode: mode,
            resolve: {
                extensions: ['.ts', '.js', '.json']
            },
            module: {
                rules: [
                    {
                        test: /\.ts$/,
                        exclude: /node_modules/,
                        use: [
                            {
                                loader: "babel-loader",
                                options: {
                                    presets: [
                                        [
                                            "@babel/preset-env",
                                            {
                                                "targets": {
                                                    "browsers":["last 2 versions"],
                                                    "node":"current"
                                                }
                                            }
                                        ]
                                    ],
                                },
                            },
                            {
                                loader: "ts-loader",
                            },
                        ],
                    },
                ],
            },
        };
    };

    return [config('node'), config('web')]
};

捆绑它

npm run bundle-dev

npm run bundle-prod 

导入

import {MyJavaScriptPackage} from "my-javascript-package/node";
//or 
import {MyJavaScriptPackage} from "my-javascript-package/web"; // SPA example

参考文献: