Búsqueda de sitios web

ecmascript 6 - ¿Qué estrategia de construcción de módulos debería usar para un módulo de Typescript que podría ser usado tanto en navegador como en node?


Estoy dando vueltas en círculos aquí: déjame exponer mi entendimiento sobre los módulos tal como lo entiendo actualmente. Corrígeme si estoy equivocado en algún punto.

Los módulos son útiles para evitar la contaminación del espacio de nombres (es decir, variables con los mismos nombres), al mismo tiempo que te permiten escribir tu código de manera que sepas que estás dependiendo de un módulo.

(es decir, la alternativa es un día en el que estás escribiendo un poco de código que asume que jQuery existe como una variable global, y eso hace que sea arriesgado eliminar varias dependencias ya que no estás seguro de si se están utilizando o no.)

CommonJS es la solución que se creó para Nodejs, mientras que RequireJS (también conocido como AMD) era la solución para los navegadores.

Sin embargo, a partir de ES2015 existe una especificación estandarizada para módulos en Javascript, y los navegadores modernos lo soportan, mientras que está en desarrollo para NodeJS.

Typescript - Mi entendimiento es que TypeScript se compilará en la estrategia de módulo que se especifique en compilerOptions.module, es decir, "module": "commonjs" se compilará al sintaxis que usa CommonJS, mientras que "module": "amd" se compilará al sintaxis de require. Supongo que "module": "es2015" se compila al sintaxis de módulo estándar de ES2015.

Lo que estoy tratando de hacer:

Estoy tratando de escribir un par de bibliotecas que contengan clases simples de ES6. Estas bibliotecas luego serán utilizadas por otra biblioteca, que también usará Typescript.

Para empezar:

mkdir foo bar biz 

En cada directorio:

tsc --init && npm init

Esto nos dará un tsconfig.json predeterminado de

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code */
    "strict": true,                           /* Enable all strict type-checking options. */
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */

  }
}

Pero es un poco desordenado tener el .ts y el .js compilado en la misma carpeta, y además queremos archivos de declaración, así que lo cambiaré a esto en cada carpeta:

{
    "compilerOptions": {
      /* Basic Options */
      "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
      "module": "commonjs",                     /* Specify module code */
      "declaration": true,                   /* Generates corresponding '.d.ts' file. */
      "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
      "outDir": "./lib/",                        /* Redirect output structure to the directory. */
      "rootDir": "./src/",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
      "strict": true,                           /* Enable all strict type-checking options. */
      "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */

    }
  }

En package.json también necesitamos cambiar esto:

"main": "lib/index.js",

(pero preguntas sobre esto más adelante).

En foo:

**src/index.ts**


export function hello() : string {
    return "hello!"; 
}

export function myRandom() : number{
    return Math.random(); 
}

Y correremos:

tsc 
sudo npm link 

esto nos dará en la carpeta lib/:

lib/index.d.ts

export declare function hello(): string;
export declare function myRandom(): number;
//# sourceMappingURL=index.d.ts.map

lib/index.d.ts.map

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,IAAK,MAAM,CAE/B;AAED,wBAAgB,QAAQ,IAAK,MAAM,CAElC"}

lib/index.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function hello() {
    return "hello!";
}
exports.hello = hello;
function myRandom() {
    return Math.random();
}
exports.myRandom = myRandom;

En bar:

src/alpha.ts

import {hello, myRandom} from "foo"; 

export class Alpha {

    blurp () : string {
        return hello() + myRandom(); 
    }
}

src/beta.ts

export class Beta {


    flurf () : number {
        return Math.random(); 
    }
}

y enlazaremos esto con nuestro módulo foo y compilaremos con:

sudo npm link foo tsc sudo npm link

Y esto se compila bien: en nuestra carpeta lib/ tenemos:

 - alpha.d.ts
 - alpha.d.ts.map 
 - alpha.js
 - beta.d.ts
 - beta.d.ts.map
 - beta.js

Y el archivo interesante allí va a ser lib/alpha.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var foo_1 = require("foo");
var Alpha = /** @class */ (function () {
    function Alpha() {
    }
    Alpha.prototype.blurp = function () {
        return foo_1.hello() + foo_1.myRandom();
    };
    return Alpha;
}());
exports.Alpha = Alpha;

Pero aquí es donde las cosas se me complican:

En negocios

Quiero poder hacer algo así:

src/app.ts

import {hello} from "foo"; 
import {Alpha, Beta} from "bar"; 

const a = new Alpha(); 
const b = new Beta(); 

console.log(a.blurp());  
console.log(b.flurf()); 
console.log(hello()); 

Pero lo que obtenemos aquí es [ts] No se puede encontrar el módulo 'bar'.

Ahora esto tiene sentido quizás. El package.json de bar apunta a un index.js que no existe.

Ahora podría intentar cambiar el tsconfig de bar para establecer el archivo de salida en lib/index.js, pero a TypeScript no le gusta eso:

tsconfig.json:5:5 - error TS6082: Only 'amd' and 'system' modules are supported alongside --outFile.

    5     "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
          ~~~~~~~~

    tsconfig.json:13:6 - error TS6082: Only 'amd' and 'system' modules are supported alongside --outFile.

    13      "outFile": "./lib/index.js",                       /* Concatenate and emit output to single file. */

Así que podría cambiar el módulo a "amd", pero entonces no encontrará el paquete 'foo'

src/alpha.ts:1:31 - error TS2307: Cannot find module 'foo'.

1 import {hello, myRandom} from "foo";

Te haces una idea.

¿Alguien tiene algún consejo general sobre lo que necesito entender aquí?

Mi preferencia es usar la sintaxis import {ItemA, ItemB} from "my-module";, pero una cosa que me preocupa es si estoy escribiendo módulos que requieren una configuración de importación específica en su extremo.

He puesto todo el código aquí:

https://github.com/dwjohnston/typescript-issues

Respuesta #1

La mejor solución que tengo es crear un archivo index.ts y llenarlo con:

   export * from "./alpha.ts"; 
   export * from "./beta.ts"; 

etc.

Esto también te da control sobre qué módulos estás realmente exportando.

Artículos relacionados