みなさんこんにちは!
プロジェクトをAngular 1からReactに移行するために使用した経験とツールを共有したいと思います。
TLTR: Angularコンポーネント(コントローラー+テンプレート)をReactコンポーネントに変換できるモジュールを作成しました。
ホリバーラのためではない
この記事では、なぜ、どのフレームワークが優れているかを証明しません。 はい、React以外にもVue、Angular 6が既にリリースされています。また、Ember、Svelteなども多くあります。一般的に、タスクをどのように解決したかをお伝えしたいと思います。私の経験と経験が誰かに役立つことを願っています。
プロジェクト
それぞれに、別のフレームワーク/ライブラリに切り替える独自の理由があります。 私の会社では、主なプロジェクトが書かれていました Reactがテーブルの下を歩いたとき かなり前に、Angular 1.xがこのために選択されました。 時には痛み(ダイジェストサイクル、ウォッチャーとの魔法、Angularの約束)をもたらしましたが、全体として彼は仕事をしました。
メインプロジェクトのモバイルバージョンを含むすべての新しい関連プロジェクトは、多数のRedux + React + Typescript + CSSモジュールを使用します。 その結果、コンポーネントとスタイルのライブラリが登場し、すべてのプロジェクトが厳密に標準化され、新しいコンポーネントとサブプロジェクトの開発が大幅に加速されました。
メインプロジェクトは、Angular上で並行して実行され続け、サポートにますます時間がかかりました。 既成のコードをそのまま使用することはできません すでに解決済みの問題を新たに解決し、コンポーネントをゼロから作成する必要がありました。 さらに、プロジェクトのメインバージョンとモバイルバージョンをアダプティブレイアウトを備えた1つのプロジェクトに結合する見通しが出てきました。
はい、 ngReactがありますが、プロジェクトを一種の怪物フランケンシュタインに変えたいという特別な欲求はありませんでした。 そのため、プロジェクトをReactに移行して、開発とサポートを簡素化することが決定されました。
何だった
主なプロジェクト
- Angular 1.4.10、angular-ui-router、angular-ui(モーダルウィンドウ、カレンダー)のプロジェクト
- 60/40-タイプスクリプト/ ES2015 +
- 182個のテンプレート、156個のディレクティブ、100個のコントローラー
- 角度モック+テスト用のJest
- LESS(Bootstrap 3のLESSコードを含む)+ BEM
関連プロジェクトとモバイル版
- React 15.x(Preact.js)、React-router
- 100%タイプスクリプト
- テスト用のJest
- コンポーネントライブラリ+ CSSモジュール
ほとんどのビジネスロジック(バリデータ、リクエストの送信、ユーティリティなど)は、NPMモジュールの形式でTypescriptに個別に実装されているため、フレームワークに関係なくプロジェクト間でコードを簡単に再利用できます。
ビジネスに取り掛かる
「私はルーチンとリファクタリングが大好きです!」 - 世界の単一の開発者ではない
リファクタリングは最も興味深い活動ではないことに多くの人が同意すると思います。 したがって、このプロセスを部分的に自動化することにしました。
ReactとAngularのコンポーネントを表面的に比較しても、(もちろん、大幅に簡略化された)式を導出できます。
React.Component = Angular Controller + Angular Directive + Angular Template;
だから、 ng2react-builderが判明しました
ng2react-builder
あなたはおそらく、私がモジュールの命名の達人であることを既に認識しているでしょう。 まあ、それについてではなく...
モジュールでできること
ドキュメントの 例と、テストケースのコンポーネントのさらに良い例を見るのが最善です。
モジュールとコントローラーをモジュールにフィードすることができます(ディレクティブはまだ飛行中です)。出力は、JSXマークアップを含むアセンブルされたReactコンポーネント(React.PureComponentまたはReact.Component)になります。
コントローラーがなければ、単純なステートレスコンポーネント(React.StatelessComponent)を簡単にアセンブルできます。
ng2react-builderすべてのAngular式を有効なJS / JSX構成に変換しようとします:
-
ng-repeat
から、JSX出力を持つネイティブJS.map()
を取得します
<!-- --> <div> <span ng-repeat="item in list as | limitTo:5 as results">{{item.name}}</span> </div> <!-- --> <div> {results.slice(0, 5).map((item, index) => { return <span key={`child-${ index }`}>{item.name}</span> })} </div>
- コンテンツ
{{expression}}
は{{expression}}
に変換され{expression}
- イベントハンドラーと非標準ディレクティブの変換:
<!-- --> <a ng-click="$event.preventDefault(); selectItem(item)">{{item.name}}</a> <my-icon="calendar"><my-icon/>
// ng2rect-builder' directivesToTags: { 'my-icon': { tagName: 'MyReactIcon', valueProp: 'type' } }
<!-- --> <a onClick={(event) => { event.preventDefault(); selectItem(item); }}> {item.name} </a> <MyReactIcon type="calendar"/>
- などなど 。 例とAPIを参照することをお勧めします!
もう1つの特に便利なことは、ディレクティブをJS関数呼び出しに変換する機能です(属性として指定されたディレクティブのみがサポートされるようになりました)。
<!-- --> <span my-directive="some.value"></span>
// ng2rect-builder' directivesToTextNodes: { myDirective: { callee: 'myFunc', calleeArguments: ['arg1'] } }
<!-- --> <span>{myFunc(arg1, 'some.value')}</span>
仕組み
- テンプレート(指定されている場合)はparse5を介して解析され、HTML ASTで作業します。
- ディレクティブ、式、ハンドラーなどのあらゆる種類の正規化と変換を実行します。
- ASTからJSXテンプレートへ
- コントローラー(指定されている場合)は、 TypeScript Compiler APIを使用してASTに解析されます 。
- コントローラーはコンポーネントクラスに変換され、受信したJSXテンプレートに
render
メソッドが追加されrender
- 共通コンポーネントコードはPrettierを介して実行されます
- できた! ファイルを取る...
TypescriptコンパイラAPIを使用する理由
- コントローラーはTypeScriptで記述できます
- 生成されたStateおよびPropsインターフェイスを使用して、TypeScriptでReactコンポーネントを取得します。
奇跡はありません
ああ。 試しなかったように
上記で書いたように、ファイルを取得して手動でリファクタリングを続行する必要がありますが、このモジュールは、特にAngularテンプレートをJSXに変換する際に、日常のタスクに多くの時間を節約しました。
何になった
- メインプロジェクトはTypescriptとReactで完全に書き直されています
- 他のプロジェクトでコンポーネントとコードを再利用するのが簡単になりました
- 新しいテストのリファクタリング/作成。Jestスナップショットを使用してください:)
今後の予定
- LESS + BEMからCSSモジュールへの切り替え
私はあなたがそれを楽しんでいることを願っています、そして私は誰かがリファクタリングプロセスの時間を節約するのを手伝いました;)