-->

Creating a single CommonJS module from several Typ

2019-03-19 16:26发布

问题:

I'm trying to work out the best way to split my application into a few CommonJS modules that can be consumed by other applications.

I have 5 TS classes, and I'd like to bundle them as a single CommonJS module. I then intend to publish this module to a private NPM repo, so it can be consumed by other applications. Ideally I'd like to package the relevant *.d.ts definition files with it.

What's the best way to do this? I'm using external TS modules, but these produce a separate CommonJS module per TS class.

回答1:

As far as i know typescript doesn't support combining external modules yet. From their wiki on codeplex:

TypeScript has a one-to-one correspondence between external module source files and their emitted JS files. One effect of this is that it's not possible to use the --out compiler switch to concatenate multiple external module source files into a single JavaScript file.

However, you can do a trick by using internal modules in typescript, since the tsc compiler has the ability to compile them into a single file, and then you can just add one more file with a module.exports directive for the whole namespace to make it a CommonJS module.

Here is a step by step example. Let's say you have the following internal modules split into three files:

Validation.ts:

module Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}

ZipCodeValidator.ts

/// <reference path="Validation.ts" />
module Validation {
    var numberRegexp = /^[0-9]+$/;
    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}

LettersOnlyValidator.ts

/// <reference path="Validation.ts" />
module Validation {
    var lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}

If you compile these with with the --out parameter in the tsc compiler you can combine them into a single file. However, that doesn't make them a CommonJS module. To export them you use a trick to add one more ts file called ValidationExport.ts containing the export directive for the namespace:

var module: any = <any>module;
module.exports = Validation;

And then you can run the tsc command to compile everything to a single file called "validationmodule.js":

tsc --out validationmodule.js Validation.ts ZipCodeValidator.ts LettersOnlyValidator.ts ValidationExport.ts

The output is a CommonJS module you can use in Node.js:

var Validation = require("./validationmodule");

var zipCodeValidator = new Validation.ZipCodeValidator();
var lettersOnylValidator = new Validation.LettersOnlyValidator();

console.log(zipCodeValidator.isAcceptable("16211"));
console.log(lettersOnylValidator.isAcceptable("5555"));


回答2:

Having a separate CommonJS module per file is completely appropriate. All the require calls in TypeScript will translate to CommonJS require calls in JavaScript, and the .d.ts files will be picked up in the process. (If you're doing something silly like requireing classes outside your source directory... stop.)

You would only need to consider a packaging step if you intended to use this NPM package in other applications, in which case look into Browserify