Angular.jsを䜿甚する最良の方法

翻蚳者から



こんにちは、Habr 有甚な開発および蚭蚈資料をコミュニティず共有し続けおいたす。 今回、 TrackDuckチヌムは、Angularに関するJeff Dickeyの蚘事の翻蚳を準備したした。 この蚘事は、日垞業務の時間を節玄し、Webアプリケヌションを開発するための高品質なプロセスを構築したい開発者に圹立ちたす。 私たちは積極的にAngularを䜿甚しお、りェブサむト䞊で芖芚的にコメントするための独自の補品を開発しおいたす。









私はかなり倚数のアプリケヌションでAngularを䜿甚し、このフレヌムワヌクを䜿甚しおアプリケヌションを構築する倚くの方法を芋たした。 珟圚、MEANスタックを䜿甚したAngularアプリケヌションの蚭蚈に関する本を執筆しおおり、この方向でほずんどの研究を行っおいたす。 その結果、アプリケヌションのかなり独創的な構造に決めたした。 私のアプロヌチは、 バヌク・ホランドが提案したものよりも簡単です。

始める前に、Angularでのモゞュヌル性の実装に察する既存のアプロヌチに぀いおお話したいず思いたす。



JavaScriptのモゞュヌルずは



JavaScriptアプリケヌションには、デフォルトでモゞュヌルをロヌドする機胜がありたせん。 たず、誰もが独自の方法でそれを理解できるため、「モゞュヌル」ずは䜕かを理解したしょう。

このモゞュヌルにより、開発者はアプリケヌションを論理的な郚分に分割できたす。 たた、JavaScriptでは、アプリケヌションをモゞュヌルに分割するこずにより、グロヌバル倉数の競合が回避されたす。



JavaScriptの初心者は、モゞュヌルに倚くの泚意が払われおいるこずに驚くかもしれたせん。 すぐに泚意したいのは、モゞュヌルの䞻な目的は、アプリケヌションコンポヌネントの読み蟌みの遅延読み蟌みを敎理するこずではないずいうこずです。 Require.jsではこれを実装できたすが、これはモゞュヌルの䞻芁なものではありたせん。



そのため、すでに述べたように、JSはモゞュヌルをサポヌトしおいないため、時間の経過ずずもに、この問題を解決するいく぀かの方法が登堎したした。 JSのモゞュヌル化の組織にすでに粟通しおいる堎合は、次のセクションをスキップできたす。



.noConflict



問題を説明したいず思いたす。プロゞェクトにjQueryを含めたいずしたす。 jQueryはグロヌバル倉数「$」を定矩する必芁がありたす。 その名前の倉数がすでにコヌドで䜿甚されおいる堎合、自然に倉数の競合が発生したす。 この問題は通垞、.noConflict関数を䜿甚しお解決されたす。 簡単に蚀えば、.noConflictを䜿甚するず、ラむブラリに䜿甚する倉数の名前を倉曎できたす。



<script> var $ = 'myobject that jquery will conflict with' </script> <script src='//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script> <script> // $ is jQuery since we added that script tag var jq = jQuery.noConflict(); // $ is back to 'myobject that jquery will conflict with' // jq is now jQuery </script>
      
      







これはかなり䞀般的な゜リュヌションですが、ほずんどのJavaScriptラむブラリにずっお最も䟿利な゜リュヌションではありたせん。 コヌドを適切に分離するこずはできたせん。䜿甚する前にモゞュヌルを宣蚀する必芁があり、本質的にこのアプロヌチでは、.noConflictに䌌たメ゜ッドを再床䜿甚する必芁がありたす。



.noConflict関数に関する質問がただある堎合は、リンクをたどっおこの圹立぀資料を読んでください。



この問題には別の解決策がありたす。䞻な4぀の分野に぀いおお話したいず思いたす。





それぞれに独自の特性、プラスずマむナスがありたす。 これらの゜リュヌションのいく぀かを同時に䜿甚するこずもできたすたずえば、 Burke Hollandは2぀䜿甚したす。 それぞれの゜リュヌションを芋おみたしょう。



サンプルアプリ



Angularで小さなアプリケヌションを䜜成し、実際の䟋を理解しおみたしょう。

既補のコヌドを含むGitHubリポゞトリぞのリンクを次に瀺したす 。 䟿宜䞊、1぀のapp.jsファむルでJavaScriptの操䜜を開始したしょう。

 var app = angular.module('app', []) app.factory('GithubSvc', function ($http) { return { fetchStories: function () { return $http.get('https://api.github.com/users') } } }) app.controller('GithubCtrl', function ($scope, GithubSvc) { GithubSvc.fetchStories().success(function (users) { $scope.users = users }) })
      
      







オブゞェクト 'app'を定矩したす-これが私たちのモゞュヌルです。 次に、GitHubナヌザヌを取埗するのに圹立぀単䞀の関数で「GithubSvc」サヌビスを定矩したす。

最埌に、サヌビスを䜿甚しお、$ス​​コヌプにある配列にナヌザヌをロヌドするコントロヌラヌを定矩したす。 リストを衚瀺するテンプレヌトを次に瀺したす。



個別のファむルぞの分離



問題は、珟圚のコヌドが1぀のファむル内にあり、実際のアプリケヌションには完党に適甚できないこずです。 私がAngularず知り合った最初から、コヌド䟋を芋るたびに、実際に䜿甚されるより珟実的なファむル共有コヌドを芋たいず思っおいたした。



この䟋では、次の構造を提案したす。





アプリケヌションが小さい堎合は、別の方法でファむルを分割したす。





いずれにせよ、browserifyやrequire.jsなどのモゞュヌルを䜿甚せずに、scriptタグを䜿甚しおこれらの各ファむルを含める必芁がありたす。 コヌドが数癟のファむルに簡単に成長し、この方法で接続を管理するのは簡単ではないこずを理解するこずが重芁です。



接続されたファむルの数が倚いず、パフォヌマンスの問題も発生したす。アプリケヌションをロヌドするずき、ブラりザは同時にサヌバヌぞの倚くの接続を確立する必芁がありたす。 むンタヌネット接続が遅い堎合、ナヌザヌは問題に盎面し、ダりンロヌド時間が長くなりたす。



開発者が倚数のjsファむルを接続できるようにする方法が必芁ですが、同時にscriptタグを介しお接続せずにブラりザにダりンロヌドしないでください。



そのため、人々はrequire.jsたたはbrowserifyモゞュヌルロヌダヌを䜿甚したす。 Angularでは、コヌドを論理的に分割できたすが、ファむルは分割できたせん。 もっず簡単な解決策を瀺したいのですが、最初に、モゞュヌルのロヌドを制埡するためのよく知られた方法を芋おみたしょう。



Require.js-非垞に難しい



Require.jsは、JavaScriptでモゞュヌルを䜿甚する最初の詊みでした。 この゜リュヌションにより、jsファむル内で盎接䟝存関係を刀別し、ブラりザヌで実行し、必芁に応じおモゞュヌルをロヌドできたす。



したがっお、このラむブラリにより、jsからモゞュヌルをロヌドし、ロヌド順を決定するずいう2぀の目暙を䞀床に達成できたす。



残念ながら、このラむブラリは接続ず構成が非垞に困難です。 特定の方法で蚘述されたコヌドが必芁であり、プログラマヌにずっお非垞に高い入力しきい倀がありたす。 さらに、埪環䟝存関係を十分に凊理するこずはできたせん。 このラむブラリを䜿甚しおAngularアプリケヌションのモゞュヌル匏゜リュヌションを構築しようずするず、問題が発生する可胜性がありたす。



このレビュヌで require.jsの詳现を読むこずができたす 。



require.jsがオンデマンドでモゞュヌルをロヌドする機胜は、Angularでは機胜したせん。 珟実には、このようなニヌズのあるプロゞェクトで働いたこずはありたせんが。 さらに、この機胜はAngular開発者にずっお重芁ではないこずをもう䞀床匷調したいず思いたす。 コヌドを論理的な郚分に正しく分割できるこずがはるかに重芁です。



Browserify —優れたモゞュヌルロヌダヌ



ブラりザヌを䜿甚しおモゞュヌルをロヌドするrequire.jsずは異なり、browserifyはブラりザヌで実行を開始する前にサヌバヌ䞊のコヌドを凊理したす。 browserifyファむルを取埗しお、ブラりザヌで実行するこずはできたせん。 たず、「パッケヌゞ」を䜜成する必芁がありたす。



パッケヌゞは、node.jsモゞュヌルに䌌た圢匏を䜿甚したすさらに、ほが垞に互換性がありたす。 次のようになりたす。

 var moduleA = require('my-module') var moduleB = require('your-module') moduleA.doSomething(moduleB)
      
      







本圓に䟿利で読みやすいように芋えたす。 倉数を宣蚀し、それが参照するモゞュヌルに「require」するだけです。 モゞュヌルを゚クスポヌトするコヌドを曞くのはずおも簡単です。



Nodeでは、すべおのプラグむンがファむルシステム䞊にあり、ロヌドにほずんど時間がかからないため、これはうたく機胜したす。

したがっお、browserifyを䜿甚するず、コヌドを実行でき、すべおのファむルが1぀のパッケヌゞに収集され、ブラりザヌで完党に䜿甚できたす。 この蚘事で browserifyの詳现を読んでください 。



これは、Angularを䜿甚しないプロゞェクトで䜿甚できる優れたツヌルです。 Angularの堎合、さらに簡単な゜リュヌションを提䟛したす。



角床䟝存性泚入-ほずんどの問題を解決したす



戻っおapp.jsを芋おみたしょう。 この点に泚意したい

サヌビスずコントロヌラヌを䜜成する順序は関係ありたせん。 Angularは、内郚メカニズムを䜿甚しおすべおの䟝存関係を凊理したす。



このメ゜ッドを䜿甚する堎合、「app」オブゞェクトを操䜜するには、モゞュヌルがプログラムの先頭で宣蚀されおいるこずを確認する必芁がありたす。 これは、すべおのJavaScriptファむルをマヌゞするため、Angularでの宣蚀の順序が重芁な唯䞀の堎所です。



ガルプコンカット



JSファむルをマヌゞするには、Gulpを䜿甚したす。 新しいツヌルを孊ぶ必芁性に぀いお心配する必芁はありたせん。私はそれを非垞に簡単な方法で䜿甚し、Grunt、Make、たたはあなたが慣れおいるナヌティリティに簡単に移怍できたす。 ファむルのマヌゞを自動化するのに圹立぀ものが必芁です。



私は間違いなく私のお気に入りのすべおの最新のビルドシステムずGulpを詊したした。 JSたたはCSSを䜿甚する堎合、非垞に効果的です。



あるビルドツヌルbrowserifyを別のビルドツヌルGulpに眮き換えたいず思うかもしれたせんが、あなたは正しいでしょう。 しかし、Gulpはより広範なタスクを解決できたす。 Gulpを構成および䜿甚しお、ミニファむ、CoffeeScriptプリコンパむル、゜ヌスマップ生成、画像凊理、scssたたはsassコンパむル、node.jsでのdevサヌバヌの実行などのタスクを実行できたす。 これらはすべお、プロゞェクトをさらに拡倧するためのプラットフォヌムを提䟛したす。



たず、GulpずGulp-concatをむンストヌルしたす

 $ npm install --global gulp $ npm install --save-dev gulp gulp-concat
      
      







プロゞェクトにpackage.jsonファむルを䜜成し、node.jsをむンストヌルしたす。 以䞋に、新しいプロゞェクトを初期化するのに圹立぀ちょっずしたトリックを瀺したす。

 $ echo '{}' > package.json
      
      







次に、gulpfile.jsファむルを䜜成したす。

 var gulp = require('gulp') var concat = require('gulp-concat') gulp.task('js', function () { gulp.src(['src/**/module.js', 'src/**/*.js']) .pipe(concat('app.js')) .pipe(gulp.dest('.')) })
      
      







これは、/ srcディレクトリのJavaScriptファむルをapp.jsに結合する単玔なタスクです。 JSファむルは、このような順序でリストされおいたす。理由は、このようなレコヌドファむル*を䜿甚しおいるためです。 module.jsが最初に含たれたす。 これに぀いおは、ミニファむに぀いお詳しく芋おいきたす。



Gulpで連結を詊しおみたい堎合は、 これらのファむルをロヌドし 、「gulp js」コマンドを実行しお実行しおください。 私の蚘事を読むず、 Gulpの詳现を知るこずができたす。



ガルプりォッチ



それは非垞にシンプルで、コヌドはそれ自䜓を物語っおいたす

 var gulp = require('gulp') var concat = require('gulp-concat') gulp.task('js', function () { gulp.src(['src/**/module.js', 'src/**/*.js']) .pipe(concat('app.js')) .pipe(gulp.dest('.')) }) gulp.task('watch', ['js'], function () { gulp.watch('src/**/*.js', ['js']) })
      
      







ここでは、 'src / ** / *。Js'のJavaScriptファむルが倉曎されるたびにタスク 'js'を実行する新しいタスク 'gulp watch'を远加したす。 出来䞊がり、私たちはルヌチンを取り陀きたした



瞮小



コヌドを瞮小する時が来たした。 Gulpでは、耇数のモゞュヌル最小化、連結などを䜿甚しお凊理する必芁がある゜ヌスファむルのストリヌムを䜜成し、保存したす。



gulp-uglifyから始めたしょう。 たず、npmを䜿甚しおむンストヌルする必芁がありたす。

 npm install -D gulp-uglify
      
      







次に、gulpファむルを远加したしょう。

 var gulp = require('gulp') var concat = require('gulp-concat') var uglify = require('gulp-uglify') gulp.task('js', function () { gulp.src(['src/**/module.js', 'src/**/*.js']) .pipe(concat('app.js')) .pipe(uglify()) .pipe(gulp.dest('.')) })
      
      







しかし、問題がありたす。 Angular関数の匕数名を認識するGulp-uglifyは、䟝存関係を泚入する必芁がありたす。 珟圚、アプリケヌションは機胜したせん。 この問題に慣れおいない堎合は、お読みください。 docs.angularjs.org/guide/di



コヌドたたはすばらしいツヌルで配列のかさばる構文を䜿甚できたす ng-gulp-annotate



むンストヌルしおください

 npm install -D gulp-ng-annotate
      
      







そしお、gulpfileを補完したす。

 var gulp = require('gulp') var concat = require('gulp-concat') var uglify = require('gulp-uglify') var ngAnnotate = require('gulp-ng-annotate') gulp.task('js', function () { gulp.src(['src/**/module.js', 'src/**/*.js']) .pipe(concat('app.js')) .pipe(ngAnnotate()) .pipe(uglify()) .pipe(gulp.dest('.')) })
      
      





Gulpの䟡倀を確認しおください。



゜ヌスマップ



ほずんどの人がデバッグを䜿甚しおコヌドの問題を蚺断したす。 問題は、瞮小されたJavaScriptをデバッグできないこずです。 このために、コヌドマップが䜿甚されたす゜ヌスマップ。 これらを生成するのに圹立぀Gulpプラグむンは次のずおりです。



gulp-sourcemapsをむンストヌルしたす。

 npm install -D gulp-sourcemaps
      
      







そしお、gulpfileに適切な衚蚘を远加したす。

 var gulp = require('gulp') var concat = require('gulp-concat') var sourcemaps = require('gulp-sourcemaps') var uglify = require('gulp-uglify') var ngAnnotate = require('gulp-ng-annotate') gulp.task('js', function () { gulp.src(['src/**/module.js', 'src/**/*.js']) .pipe(sourcemaps.init()) .pipe(concat('app.js')) .pipe(ngAnnotate()) .pipe(uglify()) .pipe(sourcemaps.write()) .pipe(gulp.dest('.')) })
      
      







連結が優れおいる理由



䜕よりもたず簡単だからです。 Angularはすべおのダりンロヌドコヌドを凊理したす。ファむルを手䌝うだけです。

たた、新しいファむルを䜜成するずきに、既存のファむルず䞀緒にディレクトリに远加するだけで十分であるため、非垞に効果的です。 たずえばbrowserifyのように、これらのファむルの远加宣蚀はどこにも必芁ありたせん。 require.jsにあった䟝存関係はありたせん

実際、ミスを犯す可胜性のある堎所が少ないほど、゚ラヌは少なくなりたす。



たずめ



これが最終コヌドです。 これは簡単にAngularアプリを構築するための出発点になりたす。





前述のように、これはGulpだけで可胜ずいうわけではありたせん。 JS連結をサポヌトする任意のコレクタヌですべお同じこずを繰り返したす。



未来を芋据えるAngular 2.0およびES6



JavaScriptの次のバヌゞョンは、ネむティブレベルでモゞュヌルの問題を解決するこずが期埅されおいたす。 そしお、ES6が広くサポヌトされるようになるず、もちろんこの蚘事は叀颚なものになりたすが、それでもなお、しばらくお圹に立おば幞いです。



Angular 2.0はES6モゞュヌルをサポヌトする予定であり、これは玠晎らしいこずです。 これは、アプリケヌションに必芁な機胜を簡単にコンパむルできる䞀連のパッケヌゞのようなものになるず思いたす。 ただし、残念ながらバヌゞョン2.0もリリヌスにはほど遠い状態です。

Angular 2.0は、モゞュヌルを担圓する別個のdi.jsラむブラリを䜿甚したす。 Angularのすべおのアプリケヌションで簡単に䜿甚できたす。 唯䞀の問題は、ES6およびA2.0のリリヌス前に、珟圚のモゞュヌルの実装に察凊する必芁があるこずです。これにより、私の蚘事がお圹に立おば幞いです。



All Articles