機能:企業開発(メインブラウザー-IE、Webサーバー-IIS、環境-Windows); それは部分的なリファクタリングですが、Webパーツの再設計です(レガシーコード、既存のUXの方向性があります)。
理由と目標:目標は、問題と新しい要件(ポストバック後のページ全体の更新、フォームの再送信、複雑なナビゲーションなど)を解決することが不可能/複雑であるため、Webコンポーネントのアーキテクチャを再設計する(ASP.NET Forms + WCFの現在のバージョン)フォーム内のデータに関する問題)。
説明されているものはすべて個人的な経験に基づいています(または、その不在-1か月前、名前とNode.jsとAngularについて何も知りませんでした)。 記事の簡単な説明に興味がある場合は、始めましょう。
新しいアーキテクチャ(当時ASP.NET MVCを使用しようとしていた)を探している最中に、channel9「 Visual Studio 2017を使用したAngular 2.xを使用したWebアプリの構築 」とそのテキストバリエーションのビデオに出会いました。 公式のAngularウェブサイトを並行して読んだ後、私は染み込んで試してみて、次のプラスを発見しました:
- モダンな(場所によっては多すぎる)人気のあるテクノロジー。
- VisualStudio(Typescriptによる)フロントエンドフレームワークに適しています。
- モジュラーアーキテクチャ。
- 多くの困難なく、書かれたテストプログラムは主要な問題を解決しました(MVCで解決できなかった問題を含む)。
当然、欠点もありました。
- ブラウザのエラーはポリフィル/シムで処理されますが、Visual Studioコンソールでのデバッグ中にjavascriptに一定の例外があります(作業に影響はないようですが、プログラムの一般的な複雑さでこれがどのように現れるかを知っている人);
- レガシーパーツ(WCFサービス)との通信の難しさ:Coreと.NET Frameworkは完全には互換性がありません(Core 2.0でこの状況を改善すると約束されています)。
- IISでの展開の追加の困難/機能。
- すぐに使用できる複雑な構成:何が、どのように、なぜ機能するのかが明確ではないため、変更が困難です。
- (前の段落から)バージョンと既存の構成へのバインド。
そこで、公式のVisual Studio 2015クイックスタートガイドに基づいて、簡単なWebApi + Angular 2プロジェクトテンプレートを読み、理解し、見つけました。 このテンプレートに基づいて、私は自分でプロジェクトを変更し始めました(以下のGitHubのリンクから完全なコードを読むことができます)。
- 不要なnpmパッケージ-テストに関連するすべて(カルマ、分度器など)を削除しました。最小限の起動には必要ありません。
- Angular 4.xに更新されました。
package.json最終オプション
{ "name": "angular-quickstart", "version": "1.0.0", "description": "QuickStart package.json from the documentation for visual studio 2017 & WebApi", "scripts": { "build:prod": "webpack --config config/webpack.prod.js --colors --progress", "build": "webpack --colors", "build:vendor": "webpack --config config/webpack.vendor.ts --colors", "typings": "typings install" }, "keywords": [], "author": "", "license": "MIT", "dependencies": { "@angular/common": "^4.1.3", "@angular/compiler": "^4.1.3", "@angular/core": "^4.1.3", "@angular/forms": "^4.1.3", "@angular/http": "^4.1.3", "@angular/platform-browser": "^4.1.3", "@angular/platform-browser-dynamic": "^4.1.3", "@angular/router": "^4.1.3", "bootstrap": "^3.3.7", "core-js": "^2.4.1", "jquery": "1.12.4", "moment": "^2.18.1", "rxjs": "^5.4.0", "zone.js": "^0.8.12" }, "devDependencies": { "@types/node": "^6.0.46", "@types/core-js": "^0.9.41", "angular2-template-loader": "^0.6.2", "awesome-typescript-loader": "^3.1.3", "css-loader": "^0.28.4", "extract-text-webpack-plugin": "^2.1.0", "file-loader": "^0.11.1", "html-loader": "^0.4.5", "raw-loader": "^0.5.1", "script-loader": "^0.7.0", "style-loader": "^0.18.1", "typescript": "~2.3.4", "webpack": "^2.6.1", "webpack-merge": "^4.1.0" } }
- すべてのコードを3つのパッケージ(ベンダー、ポリフィル、アプリ)に分割してsystemjsをwebpackに変更しました-これまでのところ、自動(再)アセンブリおよびアクセラレーターなし(平均的なラップトップでは完全なアセンブリに15秒かかります)
webpack.config.js共通:
module.exports = { entry: { 'polyfills': './app/polyfills.ts', 'vendor': './app/vendor.ts', 'app': './app/main.ts' }, resolve: { extensions: ['.ts', '.js'] }, module: { rules: [ { test: /\.ts$/, use: [ { loader: 'awesome-typescript-loader', options: { configFileName: helpers.root('', 'tsconfig.json') } }, { loader: 'angular2-template-loader' } ] }, { test: /\.html$/, use: [{ loader: 'html-loader', options: { minimize: false, removeComments: false, collapseWhitespace: false } }] }, { test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, loader: 'file-loader?name=dist/assets/[name].[hash].[ext]' }, { test: /\.css$/, exclude: helpers.root('app'), loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader?sourceMap' }) }, { test: /\.css$/, include: helpers.root('app'), loader: 'raw-loader' } ] }, plugins: [ new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable) // Workaround for angular/angular#11580 for angular v4 new webpack.ContextReplacementPlugin( /angular(\\|\/)core(\\|\/)@angular/, helpers.root('./app'), // location of your src {} // a map of your routes ), new webpack.optimize.CommonsChunkPlugin({ //order is important: //The CommonsChunkPlugin identifies the hierarchy among three chunks: app -> vendor -> polyfills. //Where Webpack finds that app has shared dependencies with vendor, it removes them from app. //It would remove polyfills from vendor if they shared dependencies, which they don't. name: ['app', 'vendor', 'polyfills'] }), ] };
開発者:module.exports = webpackMerge(commonConfig, { devtool: 'source-map', output: { path: helpers.root('dist'), publicPath: '/', filename: '[name].js', chunkFilename: '[id].chunk.js' }, plugins: [ new ExtractTextPlugin('[name].css') ] });
- IEとVSの言及された例外に対処しようとしました:webpackがshim / polyfillスクリプトで何かをしていることを発見し、元のバージョンへのリンクを使用すると、例外が消えます
index.html<!DOCTYPE html> <html> <head> <title>Angular.io QuickStart</title> <base href=/ > <meta charset=UTF-8> <meta name=viewport content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="./dist/vendor.css" /> </head> <body> <my-app>Loading App</my-app> <script src="node_modules/core-js/client/shim.min.js"></script> <!--<script src="node_modules/es6-shim/es6-shim.min.js"></script> <script src="node_modules/core-js/client/shim.js"></script> <script src="node_modules/zone.js/dist/zone.js"></script>--> <script type="text/javascript" src="./dist/polyfills.js"></script> <script type="text/javascript" src="./dist/vendor.js"></script> <script type="text/javascript" src="./dist/app.js"></script></body> </html>
- ブートストラップとjQueryが追加されました。
- プログラムの構造が複雑になり、公式のスタイルガイドに従うようになりました。
- サービスおよび単一コンポーネントのコアモジュール(header.componentなど)。
- 共通コンポーネント用の共有モジュール。
- サイトの個別の独立した領域を表すいくつかの機能モジュール。
スクリーンショット
- APIと通信するためのWebApiコントローラーとAngularサービスを追加しました
api.service.ts@Injectable() export class ApiService { private apiUrl: string; constructor(private http: Http) { this.apiUrl = "/api"; } private setHeaders(): Headers { const headersConfig = { 'Content-Type': 'application/json', 'Accept': 'application/json' }; return new Headers(headersConfig); } private formatErrors(error: any) { return Observable.throw(error.json()); } get(path: string, params: URLSearchParams = new URLSearchParams()): Observable<any> { return this.http.get(`${this.apiUrl}${path}`, { headers: this.setHeaders(), search: params }) .catch(this.formatErrors) .map((res: Response) => res.json()); } //put(path: string, body: Object = {}): Observable<any> { // return this.http.put(...); //} //post(path: string, body: Object = {}): Observable<any> { // return this.http.post(...); //} //delete(path): Observable<any> { // return this.http.delete(...)); //} }
使用例:export class HomeSiteComponent { title = "I'm home-site component with WebApi data fetching"; public ctrlData: DummyData[]; constructor(apiService: ApiService) { apiService.get('/Dummier/Get').subscribe(result => { this.ctrlData = <DummyData[]>result; }); } } interface DummyData { clientData: string; serverData: string; }
- 完全なIISですべてを展開しようとしました-すべてが機能します。 彼はプロジェクトをIIS Expressに戻しました。
- Web.configにURL書き換えルールを追加してルーティングを構成しました。 これで、サーバーはAPIリクエストを受け入れて処理し、他のすべての新しいリクエストをAngularにリダイレクトします。 Angular自体が、クライアント側のナビゲーション(「ページ404」を含む)を担当します。
ルーティングconst routes: Routes = [ { path: 'welcome', component: WelcomeComponent }, //Component w/o Menu item { path: 'home', loadChildren: () => HomeSiteModule }, //Feature Modul with own Routing { path: 'area1', loadChildren: () => Area1SiteModule }, //Feature Modul with own Routing { path: '', redirectTo: 'home', pathMatch: 'full' }, //Empty Route { path: '**', component: PageNotFoundComponent } //"404" Route ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], }) export class AppRoutingModule { }
Web.Config:<system.webServer> ... <rewrite> <rules> <rule name="WebApi Routes" stopProcessing="true"> <match url="^api/" /> <action type="None" /> </rule> <rule name="Angular Routes" stopProcessing="true"> <match url=".*" /> <conditions logicalGrouping="MatchAll"> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> </conditions> <action type="Rewrite" url="/" /> </rule> </rules> </rewrite> </system.webServer>
まだやるべきこと:
- Webpackアセンブリを自動化します。
- ベンダーパッケージを毎回再構築しないように、アセンブリを2つの部分に分割します。
- Windows認証を追加する
- WebApiを既存のWCFサービスにリダイレクトします。
最終ドラフトはGitHubにあります ( commit commit 74e54cfの執筆時点 )。
私は質問に答えて、「なぜそうなのか、ある種のビジネスではない」というトピックについて議論したいと思います。