web-dev-qa-db-ja.com

モジュールと名前空間:大規模なTypeScriptプロジェクトを整理する正しい方法は何ですか?

私はTypeScriptを初めて使い、WebGlの小さなプロトタイプフレームワークを書いています。私は現在、プロジェクトをリファクタリングしていますが、プロジェクトを整理する方法としていくつかの問題に遭遇しました。両方の(モジュールと名前空間)アプローチには重大な欠点があるようです。

この投稿では、これらのパターンを使用する方法については説明しませんが、これらのパターンがもたらす問題を克服する方法について説明します。

現状:名前空間の使用

C#からは、これが最も自然な方法のように思えました。すべてのクラス/モジュールは適切な名前空間を取得し、tsconfig.jsonで「outFile」パラメーターを指定して、すべてが1つの大きなファイルに連結されるようにします。コンパイル後、グローバル名前空間としてルート名前空間があります。依存関係はプロジェクトに組み込まれていないため、必要な* .jsファイルを手動でhtmlに提供する必要があります(良くない)

サンプルファイル

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

使用例(html内のjsファイルを追加する前に、クロス名前空間がグローバル名前空間にロードされていることを確認する必要があります)

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

        //code omitted
    }
}

長所

  • C#/ Javaから来ている場合は簡単に使用できます
  • ファイル名に依存しない-ファイルの名前を変更してもコードが壊れることはありません。
  • リファクタリングが簡単:IDEは名前空間/クラスの名前を簡単に変更でき、コード全体に一貫して変更が適用されます。
  • 利便性:クラスをプロジェクトに追加するのは、ファイルを追加して目的の名前空間で宣言するのと同じくらい簡単です。

短所

ほとんどのプロジェクトでは、外部モジュールを使用し、名前空間を使用して簡単なデモを行い、古いJavaScriptコードを移植することをお勧めします。

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

  • ルート名前空間は常に(?)グローバルオブジェクトです(悪い)
  • Libをその依存関係にバンドルしたり、実際に使用するときにカスタムコードをlibにバンドルするために不可欠なbrowserifyやwebpackなどのツールでは使用できません。
  • Npmモジュールのリリースを計画している場合の悪い習慣

最先端(?):モジュール

TypeScriptはES6モジュールをサポートしています。それらは新しくて光沢があり、誰もが進むべき道に同意しているようです。各ファイルはモジュールであり、importステートメントでファイルを追加することにより、依存関係を非常に明示的に定義できるため、バンドルツールでコードを効率的にパックすることが容易になります。ほとんどの場合、ファイルごとに1つのクラスがあり、dhteモジュールパターンではうまく機能しないようです。

これはリファクタリング後の私のファイル構造です:

enter image description here

また、各フォルダーにindex.tsファイルがあるので、import * as FolderModule from "./folder"ですべてのクラスをインポートできます。

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

サンプルファイル-ここで問題が明確に見えるようになると思います。

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
}

使用例。ご覧のとおり、クラスを直接インポートできるため、名前空間を調べる必要がなくなりました。

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.
}

長所

  • ネームスペースにバインドされなくなったため、コードをよりモジュール化します。
  • Browserfyやwebpackなどのバンドルツールを使用できます。これらのツールはすべての依存関係もバンドルできます
  • クラスをインポートするときの柔軟性が向上し、名前空間チェーンを歩く必要がなくなりました。

短所

  • すべてのクラスが異なるファイルである場合、非常に退屈です。同じimportステートメントを何度も入力する必要があります。
  • ファイルの名前を変更すると、コードが破損します(悪い)。
  • クラス名のリファクタリングはインポートに反映されません(非常に悪い-IDEが、vs-codeを使用していますが)

IMOの両方のアプローチには欠陥があるようです。名前空間はひどく時代遅れで、大規模なプロジェクトには実用的ではなく、一般的なツールと互換性がありませんが、モジュールの使用は非常に不便で、最初にTypeScriptを採用していた機能の一部が壊れています。

完全な世界では、名前空間パターンを使用してフレームワークを記述し、それをモジュールとしてエクスポートしてから、インポートしてその依存関係とバンドルできます。しかし、これはいくつかのいハックなしでは可能ではないようです。

だからここに私の質問です:これらの問題にどのように対処しましたか?各アプローチが示唆する欠点を最小限に抑えるにはどうすればよいですか?

更新

TypeScriptとjavascriptの開発全般についてもう少し経験を積んだ後、おそらくすべてのユースケースの90%でモジュールを使用する方法であることを指摘する必要があります。

最後の10%は、グローバル名前空間を使用するレガシープロジェクトであり、小さなTypeScript(これはうまく機能します)で味付けしたいものです。

私のモジュールに対する批判の多​​くは、より良いIDEサポート。VisualStudio Codeが自動モジュール解決を追加したことで解決しました。

27
mode777

tl; dr:過去を選択しないでください。未来を選択:モジュール。

ES6モジュール仕様の初期のドラフトでは、インラインモジュールの概念がありましたが、この概念は 2013年9月に廃止されました です。ただし、この概念は、2012年にTypeScriptチームによって言語の最初のベータバージョンで既に実装されていました。つまり、内部モジュールでした。次に、ES6モジュールの最終仕様 2014年7月にリリースされました インラインモジュールなし。 1年後、2015年7月、TypeScriptバージョン1.5で、内部モジュール名前が変更されました tonamespaces 標準との混乱を避けるため。

名前空間はレガシー機能です。 ECMAScript言語の一部にはなりません。そして、TypeScriptチームは引き続き標準に従います。 2014年7月にECMAScriptモジュール標準がリリースされて以来、TS名前空間に関する改善はありませんでした。

短所[ES6モジュールの]

  • すべてのクラスが異なるファイルである場合、非常に退屈です。同じimportステートメントを何度も入力する必要があります。
  • ファイルの名前を変更すると、コードが破損します(悪い)。
  • クラス名のリファクタリングはインポートに反映されません(非常に悪い-IDEが、vs-codeを使用していますが)

将来のIDEでこれらの問題が改善されることを期待できます。最初のものはすでにWebStormによって解決されています。

10
Paleo