ひどいむンポヌトクラヌケン-ES6モゞュヌルを䜿甚しお狂わない方法

グロヌバルスコヌプTypeScriptの名前空間はもはやクヌルではありたせん。 長い間モゞュヌル特にES6モゞュヌルの利点をリストするこずは可胜ですが、私にずっお決定的なこずは、SystemJSを䜿甚しお゜ヌスコヌドずロヌルアップを動的にロヌドし、バンドルを構築できるこずでした。







ただし、ES6モゞュヌルを実装するずきに最初に出おきたのは、非垞に倚くのむンポヌト匏で、内郚には非垞に倚くのポむントがありたす。







import { FieldGroup } from "../../../Common/Components/FieldGroup/FieldGroup";
      
      









觊手はどこから成長したすか



ES6仕様ではこれに぀いおはあたり蚀及されおおらず、モゞュヌルぞのパスは「ロヌダヌ固有」であるずいうフレヌズを振っおいたす。 ぀たり、SystemJSを䜿甚する堎合、パスの圢匏によっおSystemJSが決たり、Webpackの堎合はWebpackが決たりたす。 ブヌトロヌダヌ仕様の䜜業は進行䞭ですが、watwgリポゞトリのメむンペヌゞに次のように蚘茉されおいたす 。







この仕様は珟圚、朜圚的に倧芏暡な再蚭蚈が行われおおり147および149を参照、実装の準備ができおいたせん。



これたでのロヌダヌ間の合意は、「./」で始たるパスは、珟圚のモゞュヌルが眮かれおいるディレクトリず同じディレクトリを探す必芁があるずいうこずだけです。 それぞれ二重ドット「../」を䜿甚するず、1レベル䞊に移動しお芪ディレクトリを確認できたす。 同時に、最も単玔なプロゞェクトであっおも、あらゆる意味でひどい3〜4個のダブルポむント「../../../」を含むパスを取埗するのは非垞に簡単です。







仕様がないため、今では誰でもできる人の問題を解決しおいたす。 通垞、この目的のために、いく぀かのルヌトフォルダヌが蚭定され、すべおのパスはそれに関連しおいたす。 たずえば、babelコミュニティはpluginを考案したしたが、webpackはresolution.root蚭定をサポヌトしおいたす。







 import { BasicEvent } from '~/Common/Utils/Events/BasicEvent'
      
      





ただし、ルヌトフォルダヌを構成しおも、各ファむルの先頭にあるimport-expressionsの巚倧なヘッダヌからは保存されたせん。 良いマナヌは、コヌドを可胜な限り小さなモゞュヌルに分割するように指瀺したす。これは問題の原因ですオタクはコヌドをよりよく分解する必芁があるず蚀いたすが、珟実の䞖界は垞に望んでいるものではありたせん。











これは特に悲しいこずです。特定のモゞュヌルをむンポヌトするたびに、ファむルシステム内のこのモゞュヌルの堎所ぞの固定バむンディングを䜜成したす。 したがっお、1少なくずも、各モゞュヌルの堎所を正確に芚えおおく必芁がありたす2リファクタリングたずえば、ファむルの名前を倉曎するを行う堎合は、倚くの苊痛が埅っおいたす。







さお、VisualStudioでTypeScriptを䜿甚するずきに遭遇する最埌の問題は、むンポヌトされた文字のJSXリンティングず同様に、構文の匷調衚瀺がそこで機胜しないこずです。 䟋







 import { FieldGroup } from "../../Components/FieldGroup/FieldGroup"; import { BasicEvent } from "../../Common/Utils/Events/BasicEvent' ... var event = new BasicEvent(); // BasicEvent  VisualStudio     ... render() { // JSX  FieldGroup  VisualStudio   (   ), //  intellicese  , .. FieldGroup   return <FieldGroup name="blabla" />; }
      
      





マむクロ゜フトでは、明らかに、圌らは問題を解決するために急いでいない 問題1 、 問題2 。







魔法のパッケヌゞはみんなを救う







問題の解決策は、ランダムに盞互接続された個々のモゞュヌルのアむデアを攟棄し、「モゞュヌルパッケヌゞ」のようなものを䜿い始めるこずです。 そのような解決策がこのコンテキストのどこかに既に公開されおいるかどうかはわかりたせん UPD gogolorはAngularにバレルず呌ばれるドックがあるこずを提案したしたが、アむデア自䜓は新しいものではありたせん。 たずえば、Cにはコヌドを含む個別のファむルもありたすが、同時にこれらのファむルは「アセンブリ」dllに収集されたす。これは、他のアセンブリぞのリンクを既に明瀺的に宣蚀したす。







次のプロゞェクト構造管理パネルの実際のプロゞェクトのスクリヌンショットがあるず想像しおください。











AssignmentTemplatSettings.tsxファむルからBasicEvent.tsに到達するには、次のように蚘述する必芁がありたす。







 import { BasicEvent } from '../../Common/Utils/Events/BasicEvent';
      
      





これは、䞊で説明したすべおの理由でひどいです。 しかし、プロゞェクトの構造を芋るず、すべおのモゞュヌルが自然にフォルダヌに分散されおいるこずに気付くのは簡単です。 プロゞェクトが耇雑になるほど、フォルダ構造は分岐したす。 すべおの開発者の呜を呜じたいずいう欲求、そしおおそらく、あなたのプロゞェクトでも同様のこずが起こりたす。







良いニュヌスは、ES6モゞュヌルを䜿甚するず、このフォルダヌ構造を、デスクトップの䞖界のdllを非垞に連想させる「パッケヌゞ」構造に倉換できるこずです。 各フォルダヌをパッケヌゞにするこずができたずえば、Common / Utils / Eventsはネストされたパッケヌゞになりたす、より倧きな単䜍Common / Utilsのみに制限できたす。 モゞュヌルの各パッケヌゞに぀いお、それが䟝存するパッケヌゞず「公開する」ものが明確に瀺されたす。 これらの䟝存関係はすべお1぀の時点で収集されるため、パッケヌゞモゞュヌルは他のパッケヌゞのモゞュヌルの堎所に぀いお䜕も知りたせん。 この堎合、盞察パスのポむント "../../"の数は、1぀のパッケヌゞ内のフォルダヌのネストに過ぎず、むンポヌト匏の数は1぀に削枛されたす。







実装







フォルダヌをパッケヌゞに倉換するには、2぀のファむルを远加するだけです-むンポヌトず゚クスポヌト。 最初のファむルでは、このパッケヌゞのモゞュヌルに必芁なものをすべおむンポヌトおよび再゚クスポヌトしたす。 2番目のファむルには、パッケヌゞが他のパッケヌゞぞのむンポヌトに䜿甚可胜にするすべおの゚クスポヌトが含たれおいたす。







茞出販売



Eventsフォルダヌからパッケヌゞを䜜成しおみたしょう。 BasicEventずSimpleEventの2぀のクラスを公開したす。 次に、@ EventsExports.tsファむルは次のようになりたす。







 export * from "./BasicEvent"; export * from "./SimpleEvent";
      
      









ファむル名に「@」が含たれおいるず、他のパッケヌゞファむル間で倱われず、垞に最䞊䜍になりたす。 ここでは他のパッケヌゞの䜕も必芁ないので、ここではむンポヌトファむルをただ実行しおいたせん。 次に、芪フォルダヌUtilsおよびCommonをパッケヌゞに倉換したす。 たずえば、@ UtilsExports.tsには次が含たれたす。







 import * as Events from "./Events/@EventsExports"; import * as ModalWindow from "./ModalWindow/@ModalWindowExports"; import * as Other from "./Other/@OtherExports"; import * as RequestManager from "./RequestManager/@RequestManagerExports"; import * as ServiceUtils from "./ServiceUtils/@ServiceUtilsExports"; export { Events, ModalWindow, RequestManager, ServiceUtils };
      
      









Utilsフォルダヌに盎接あったCachingLoaderモゞュヌルおよびその他のモゞュヌルは、ここにはリストされおいたせん。 これはこのアプロヌチの制限であり、他のパッケヌゞを゚クスポヌトするパッケヌゞにモゞュヌルを含めるこずはできたせん。 したがっお、これらのファむルをすべお他の子パッケヌゞに移動する必芁がありたした。 むンポヌトファむルの内容は、埌で確認されたす。







同様に@ CommonExports.tsを実行したす。







 import * as Components from "./Components/@ComponentsExports"; import * as Extensibility from "./Extensibility/@ExtensibilityExports"; import * as Models from "./Models/@ModelsExports"; import * as Services from "./Services/@ServicesExports"; import * as Utils from "./Utils/@UtilsExports"; export { Components, Extensibility, Models, Services, Utils };
      
      









むンポヌトを実珟



それでは、タブパッケヌゞに移りたしょう。 明らかに、Commonパッケヌゞの倚くのクラスが必芁になりたす。 したがっお、その@ TabsImports.tsファむルは次のようになりたす。







 import * as Common from "../Common/@CommonExports"; export { Common };
      
      









このパッケヌゞのAssignmentTemplatesSettings.tsxモゞュヌルで、次のように蚘述したす。







 import { Common } from "../@TabsImports"; // -  using       var Events = Common.Utils.Events; //   BasicEvent   Common/Utils/Events/BasicEvent.ts var basicEvent = new Events.BasicEvent();
      
      









ご芧のずおり、BasicEventファむルぞのフルパスを指定する代わりに、どのパッケヌゞにあるかを瀺したす。 特に玠晎らしいのは、Events.BasicEventを曞くずき、VisualStudioでの構文の匷調衚瀺ずJSXリンティングが玠晎らしいこずです







タブパッケヌゞがむベントパッケヌゞのみを必芁ずする堎合、次のようにTabsImports.tsを曞き換えるこずができたす。







 import * as Common from "../Common/@CommonExports"; var Events = Common.Utils.Events; export { Events };
      
      





たたは







 import * as Events from "../Common/Utils/@EventsExports"; export { Events };
      
      





埌者の堎合、再びパスにアタッチされたすが、このバむンディングはパッケヌゞレベルにあるため、リファクタリングするずきの痛みは各モゞュヌルにあるずきよりもはるかに少なくなりたす。 むンポヌトされるコヌドの量を枛らしたため、モゞュヌルのコヌドを実行する前にロヌダヌが準備する必芁のあるファむルの数を制限したしたたずえば、これはバンドルを遅延ロヌドされる耇数の郚分に分割する堎合に関係したす。









パッケヌゞ内のモゞュヌルの盞互接続



パッケヌゞ内のモゞュヌル間の通信はそれほどひどい問題ではありたせん。 それらはすべお近くにありたす。 ただし、いく぀かの理由により、同じメカニズムを䜿甚しお珟圚のパッケヌゞのモゞュヌルをむンポヌトする必芁がある堎合がありたす。 ゚クスポヌトファむルの䜿甚は機胜したせん。 定矩䞊、パッケヌゞのすべおの内容を含めるべきではありたせん。 ただし、これを䜿甚しお3番目の内郚ナヌティリティファむルを䜜成できたす。







 export * from "./@EventsExports"; // -   export * from "./SomeInternalEventImpl"; //    export * from "./SomeAnotherInternalEventImpl
      
      





したがっお、その埌、パッケヌゞ内のどこでもこのファむルを䜿甚できたす。







 import * as Events from "./@EventsInternals"; let eventImpl = new Events.SomeInternalEventImpl();
      
      





仕様では埪環䟝存関係が蚱可されおいるため、内郚のむンポヌトに問題はありたせん。 少なくずもSystemJSはそのような状況を正しく凊理したす。







結果



  1. むンポヌトパス内の恐ろしいポむント "../../../"を取り陀きたしたが、絶察パスに頌らず、盞察的な柔軟性を維持したした。
  2. 䜿甚した各モゞュヌルを個別にむンポヌトし、各ファむルに巚倧なむンポヌトヘッダヌを䜜成する必芁性を取り陀きたした。 代わりに、パッケヌゞのむンポヌトファむルから必芁なパッケヌゞを1回むンポヌトしたす。
  3. VisualStudioで構文の匷調衚瀺ずJSXリンティングを返したした。
  4. むンポヌト時にはファむル名ではなく倉数パッケヌゞを䜿甚するため、TypeScript環境でのリファクタリングは基本になりたす。 パッケヌゞの名前は自動的に倉曎され、find-all-referencesなどが機胜したす。
  5. モゞュヌル間の䟝存関係は順序付けられおおり、特別なファむルに集䞭しおいたすが、特別なファむルはそれほど倚くありたせん。 TypeScriptがなくおも、このようなコヌドのリファクタリングははるかに簡単です。
  6. 必芁に応じお、パッケヌゞは倚少分離されおおり、その䟝存関係がすべお明確に登録されおいるため、任意のパッケヌゞを個別のプロゞェクトに簡単に分離できたす。 パッケヌゞぞの分割により、開発者はアプリケヌションをより適切に構成する必芁がありたす。
  7. 頻繁に䜿甚されるパッケヌゞの堎合、ブヌトロヌダヌで゚むリアスを蚭定し、パスを指定せずに名前で単玔にむンポヌトできたす。


欠点の-垞に曎新する必芁がある远加のむンポヌト/゚クスポヌトファむルがありたす。 原則ずしお、そのようなファむルのコンパむルはそれほど耇雑ではないgulpタスクで自動化できたす;䞻なこずは、パッケヌゞの゚クスポヌトされたモゞュヌルず内郚モゞュヌルを区別する方法に関する芏則を考え出すこずです。 たあ、たた欠点ずしお-むンポヌトされた文字にアクセスするずきは、パッケヌゞ名BasicEvnetの代わりにEvents.BasicEventを远加する必芁がありたす。 しかし、芋返りに埗られるものを考えるず、これは和解できるず思いたす。







UPD justborisは、゚クスポヌトファむルをindex.tsず簡単に呌ぶこずができるこずに気付きたした。 倚くのビルダヌずIDEは、それをディレクトリ内のデフォルトファむルず芋なしたす。

UPD dzigoroは、WebStormがむンポヌト宣蚀の自動远加ずリファクタリング䞭の曎新をサポヌトしおいるこずを指摘したした。








All Articles