web-dev-qa-db-fra.com

Modules et espaces de noms: quelle est la bonne façon d'organiser un grand projet TypeScript?

Je suis assez nouveau sur TypeScript et j'écris un petit framework de prototypage pour WebGl. Je suis actuellement en train de refactoriser mon projet et j'ai rencontré des problèmes pour organiser mon projet, car les deux approches (modules et espaces de noms) semblent avoir de sérieux inconvénients.

Ce message ne traite pas de la façon d'utiliser ces modèles, mais de la façon de surmonter les problèmes que chacun d'eux pose.

Statu quo: utilisation des espaces de noms

Venant de C #, cela semblait être la voie la plus naturelle. Chaque classe/module obtient son espace de noms approprié et je fournis le paramètre "outFile" dans tsconfig.json pour que tout soit concaténé dans un grand fichier. Après la compilation, j'ai mon espace de noms racine en tant qu'objet global. Les dépendances ne sont pas intégrées au projet, vous devez donc fournir manuellement les fichiers * .js nécessaires en html (pas bon)

Fichier d'exemple

namespace Cross.Eye {
    export class SpriteFont {   
        //code omitted
    }    
}

Exemple d'utilisation (Vous devez vous assurer que l'espace de noms Cross est chargé dans l'espace de noms global avant en fournissant le fichier js dans le html)

namespace Examples {
    export class _01_BasicQuad {
        context: Cross.Eye.Context;
        shader: Cross.Eye.ShaderProgram;

        //code omitted
    }
}

Avantages

  • Simple à utiliser si vous venez de C #/Java
  • Indépendant des noms de fichiers - renommer des fichiers ne cassera pas votre code.
  • Facile à refactoriser: les IDE peuvent facilement renommer des espaces de noms/classes et les modifications seront appliquées de manière cohérente dans votre code.
  • Commodité: l'ajout d'une classe au projet est aussi simple que l'ajout d'un fichier et sa déclaration dans l'espace de noms souhaité.

Les inconvénients

Pour la plupart des projets, nous vous recommandons d'utiliser des modules externes et d'utiliser l'espace de noms pour des démos rapides et le portage de l'ancien code JavaScript.

de https://basarat.gitbooks.io/TypeScript/content/docs/project/namespaces.html

  • Un espace de noms racine est toujours (?) Un objet global (mauvais)
  • Ne peut pas (?) Être utilisé avec des outils comme browserify ou webpack qui sont essentiels pour regrouper la bibliothèque avec ses dépendances ou regrouper votre code personnalisé avec la bibliothèque lors de son utilisation réelle.
  • Mauvaise pratique si vous prévoyez de publier un module npm

Etat de l'art (?): Modules

TypeScript prend en charge les modules ES6, ils sont nouveaux et brillants et tout le monde semble d'accord pour dire qu'ils sont la voie à suivre. L'idée semble être que chaque fichier est un module et en ajoutant les fichiers dans les instructions d'importation, vous pouvez définir vos dépendances de manière très explicite, ce qui permet aux outils de regroupement de compresser efficacement votre code. J'ai surtout une classe par fichier qui ne semble pas bien fonctionner avec le modèle de module dhte.

Voici ma structure de fichiers après le refactor:

enter image description here

J'ai également un fichier index.ts dans chaque dossier afin que je puisse importer toutes ses classes par import * as FolderModule from "./folder"

export * from "./AggregateLoader";
export * from "./ImageLoader";
export * from "./TiledLoader";
export * from "./XhrLoaders";
export * from "./XmlSpriteFontLoader";

Fichier d'exemple - je pense que le problème devient clairement visible ici ..

import {SpriteFont} from "./SpriteFont";
import {ISpriteTextGlyph, ISpriteChar} from "./Interfaces";
import {Event,EventArgs} from "../../Core";
import {Attribute, AttributeConfiguration} from "../Attributes";
import {DataType} from "../GlEnums";
import {VertexStore} from "../VertexStore";
import {IRectangle} from "../Geometry";
import {vec3} from "gl-matrix";

export class SpriteText {
    // code omitted
}

Exemple d'utilisation. Comme vous pouvez le voir, je n'ai plus à parcourir les espaces de noms, car je peux importer les classes directement.

import {
    Context,
    Shader,
    ShaderProgram,
    Attribute,
    AttributeConfiguration,
    VertexStore,
    ShaderType,
    VertexBuffer,
    PrimitiveType
} from "../cross/src/Eye";

import {
    Assets,
    TextLoader
} from "../cross/src/Load";

export class _01_BasicQuad {
    context: Context;
    shader: ShaderProgram;

    // code omitted.
}

Avantages

  • Rend votre code plus modulaire car il n'est plus lié aux espaces de noms.
  • Vous pouvez utiliser des outils de regroupement comme browserfy ou webpack, qui peuvent également regrouper toutes vos dépendances
  • Vous êtes plus flexible lors de l'importation de classes et vous n'avez plus à parcourir les chaînes d'espaces de noms.

Les inconvénients

  • Très fastidieux si chaque classe est un fichier différent, vous devrez taper encore et encore les mêmes instructions d'importation.
  • Renommer des fichiers cassera votre code (mauvais).
  • Le refactoring des noms de classe ne se propagera pas à vos importations (très mauvais - pourrait dépendre de votre IDE cependant, j'utilise vs-code)

Les deux approches de l'OMI semblent défectueuses. Les espaces de noms semblent terriblement dépassés, peu pratiques pour les grands projets et incompatibles avec les outils courants lors de l'utilisation de modules, ce qui est assez gênant et casse certaines des fonctionnalités pour lesquelles j'adaptais TypeScript en premier lieu.

Dans un monde parfait, j'écrirais mon cadre en utilisant le modèle d'espace de noms et l'exporterais en tant que module qui pourrait ensuite être importé et regroupé avec ses dépendances. Cependant, cela ne semble pas possible sans quelques vilains hacks.

Voici donc ma question: comment avez-vous résolu ces problèmes? Comment puis-je minimiser les inconvénients de chaque approche?

Mettre à jour

Après avoir acquis un peu plus d'expérience avec le développement TypeScript et javascript en général, je dois souligner que les modules sont probablement la voie à suivre pour 90% de tous les cas d'utilisation.

Nous espérons que les 10% restants sont des projets hérités qui utilisent des espaces de noms globaux, que vous voulez pimenter avec un peu TypeScript (qui fonctionne très bien d'ailleurs).

Une grande partie de ma critique des modules peut être (et a été) résolue par une meilleure prise en charge IDE. Visual Studio Code a depuis ajouté une résolution de module automatique qui fonctionne très bien.

29
mode777

tl; dr: Ne choisissez pas le passé. Choisissez l'avenir: modules.

Dans les premières versions de la spécification des modules ES6, il y avait une notion de modules en ligne , qui ensuite a été éliminée en septembre 201 . Cependant, cette notion a déjà été implémentée par l'équipe TypeScript, en 2012, avec les premières versions bêta du langage: il s'agissait de modules internes . Ensuite, la spécification finale pour les modules ES6 a été publiée en juillet 2014 sans modules en ligne. Un an plus tard, en juillet 2015, avec la version 1.5 de TypeScript, modules internesa été renommé en espaces de noms afin d'éviter toute confusion avec la norme.

Les espaces de noms sont une fonctionnalité héritée. Il ne fera pas partie du langage ECMAScript. Et l'équipe TypeScript continuera de suivre la norme. Aucune amélioration n'a été apportée aux espaces de noms TS depuis la sortie de la norme des modules ECMAScript en juillet 2014.

Inconvénients [des modules ES6]

  • Très fastidieux si chaque classe est un fichier différent, vous devrez taper encore et encore les mêmes instructions d'importation.
  • Renommer des fichiers cassera votre code (mauvais).
  • Le refactoring des noms de classe ne se propagera pas à vos importations (très mauvais - pourrait dépendre de votre IDE cependant, j'utilise vs-code)

Nous pouvons espérer quelques améliorations sur ces problèmes avec les futurs IDE. Le premier est déjà résolu par WebStorm.

10
Paleo