NEM NanoWalletのUtilsをnpmモジュール化する
自分はNEMという暗号通貨が好きで、Javascriptからアドレスを生成したり、トランザクションを発行したりなど色々触って遊んでいました。
NEMはもともとAPIが提供されているので、たいしたスキルを必要とせずにAPIにアクセスすることで簡単に送金が出来たり、素人が何か開発しようとするには非常に敷居の低い暗号通貨です。
その流れでAngular2アプリの開発に興味を持つようになり、Node.jsを調べる内にバックエンドも含めてJavaScriptでなんでも出来てしまうということを知り、今はその辺の勉強も兼ねてNEMのモザイクの交換所でも作ろうかと思っています。
そこで、初めの一歩として、NEMのアドレスを生成したり、トランザクションを発行したり、署名を検証したりする機能を、NanoWalletから移植していきます。
NanoWallet
まずはNanoWalletの構成について整理します。
NanoWalletはNEMのAPIにアクセスすることで、自らサーバを立てることなくNEMのほとんどの機能を使えてしまう優れたアプリケーションです。
AngularJSで作成されていて、実際にトランザクションを発行したり、APIに問い合わせたりする機能の実装は、以下のservices
配下にあります。
今回はその一歩手前で、各種サービスから利用されている以下utils
配下にある機能を、今後自前で開発するサービスなどから簡単に呼び出せるようにしていきます。
今まで.angular-cli.json
のscripts
でそれぞれ読み込んで使っていたのですが、手順をバックエンド側と共通化したいのでnpmモジュール化してみます。
最終的なディレクトリ構成は以下のようになります。
nem-utils │ index.js │ LICENSE │ package.json │ README.md │ └─lib Address.js bip32.js convert.js CryptoHelpers.js helpers.js KeyPair.js nacl-fast.js Network.js nodes.js nty.js Serialization.js sinks.js TransactionTypes.js
リポジトリの作成
git init
で初期化し、git remote add origin
で事前に作成しておいたリモートリポジトリのアドレスを登録。
git pull
で自動生成されたLICENSEとREADME.mdを拾ってきます。
$ mkdir nem-utils $ cd nem-utils $ git init $ git remote add origin https://github.com/tadajamdev/nem-utils.git $ git pull origin master
LICENSEとREADME.mdの中身は適当に作成します。
モジュール作成
ユーティリティ側は極力もとのコードを触らずに、また呼び出し方も同じように呼べるようにという考え方で進めます。
初めに、モジュールの設定をpackage.json
に登録します。
package.json
{ "name": "nem-utils", "version": "0.0.1", "description": "NEM's NanoWallet Utils", "main": "./index.js", "author": { "name": "tadajam", "email": "tadajam.dev@gmail.com" }, "homepage": "https://github.com/tadajamdev/nem-utils", "license": "MIT", "keywords": [ "nem" ], "dependencies": { "crypto-js": "^3.1.9-1" } }
CryptoJSはNanoWalletのソースから拾うのではなく、普通にnpm
でインストールします。
npm install --save crypto-js
lib
配下に各jsファイルを格納して、index.js
ですべてのファイルを読み込みます。
exprts
やらmodule.exports
やらイマイチ理解していないのですが、以下のようにすれば一応動きます。
index.js
exports.Address = require('./lib/Address'); exports.bip32 = require('./lib/bip32'); exports.convert = require('./lib/convert'); exports.CryptoHelpers = require('./lib/CryptoHelpers'); exports.helpers = require('./lib/helpers'); exports.KeyPair = require('./lib/KeyPair'); exports.nacl = require('./lib/nacl-fast'); exports.Network = require('./lib/Network'); exports.nodes = require('./lib/nodes'); exports.nty = require('./lib/nty'); exports.Serialization = require('./lib/Serialization'); exports.sinks = require('./lib/sinks'); exports.TransactionTypes = require('./lib/TransactionTypes');
また、このままだとエラーが出たので、各ユーティリティファイル側を少し修正します。
各ファイルのimport
のところで怒られるので、require
で読み込みます。
また、併せてCryptoJSが必要なファイルでは、同じようにCryptoJSも読み込みます。
/** @module utils/Address */ // import convert from './convert'; // import Network from './Network'; let CryptoJS = require("crypto-js"); let Network = require("./Network"); let convert = require("./convert");
GitHubに公開
git add
でインデックスに追加、git commit
でインデックスに追加されたファイルをコミットし、git push origin master
でリモートリポジトリに反映させます。
$ git add . $ git commit -m "[add]init" $ git push origin master
公開されました。 github.com
npmモジュール公開
npmの公式ページから開発者として登録をします。 www.npmjs.com
以下項目を入力し、登録しました。
- Name
- Public Email
- Username
- Password
npm adduser
でログインし、npm publish
で公開します。
$ npm adduser Username: tadajam Password: Email: (this IS public) tadajam.dev@gmail.com Logged in as tadajam on https://registry.npmjs.org/. $ npm publish
公開されました。 www.npmjs.com
モジュールの利用
Angularのコンポーネントから使用してみます。
まずはインストールします。
$ npm install --save nem-utils
インポートして使用します。
app.component.ts
import { Address, KeyPair, Network } from "nem-utils"; console.log(Address.toAddress(KeyPair.create("").publicKey.toString(), Network.char2Id("N")));
秘密鍵を空文字列で生成した場合のアドレス、NBONKWCOWBZYZB2I5JD3LSDBQVBYHB757WJ2KDEB
が出力されました。
バックエンド側でも同じようにインポートすれば、同じように使えます。
※筆者のモチベーション向上のため、以下NEMアドレスへxemなりシットトークンなりの寄付を受け付けています。
NDY4RH-UZ3CZO-Z53O5H-NEXTEM-7UF5X3-MMDGH4-IMAD
MEANスタック入門(6) MongoDBとの連携
今回はMongoDBのシェルからデータベースを操作する方法と、Node.jsからアクセスする方法についてまとめます。
mongoの使い方とデータベースの作成
ここからはmongo
コマンドを使って、MongoDBのシェルで作業していきます。
mongo
コマンドを実行すると、MongoDBのシェルに入ります。
$ mongo
データベースの準備
初めにデータベースを作成します。
use
コマンドでデータベース名を指定すると、カレントが指定したデータベースに変更になります。
この段階ではsample_db
はまだ追加されず、コレクションやドキュメントを追加した段階で追加されます。
> use sample_db
switched to db sample_db
次に通常のRDBのテーブルにあたる、コレクションを作成します。
> db.createCollection("users") { "ok" : 1 }
show collections
コマンドで実際に作成出来たか確認します。
> show collections
users
最後に、通常のRDBのレコードにあたる、ドキュメントを追加します。
users
コレクションに対して作業するので、db
に続けてdb.users
のようにコレクション名を指定します。
コレクションが存在しなければ、コレクションを新規で作成した上でドキュメントが追加されます。
> db.users.save({id:0, address: "address0"}) WriteResult({ "nInserted" : 1 })
find
で実際にドキュメントが追加されたことを確認します。
> db.users.find() { "_id" : ObjectId("590dbde126111dfac549518e"), "id" : 0, "address" : "address0" }
(参考)データベースの削除
remove
でドキュメントを全削除します。
> db.users.remove({}) WriteResult({ "nRemoved" : 1 })
drop
でコレクションごと削除します。
> db.users.drop() true
dropDatabase
でデータベースごと削除します。
> db.dropDatabase() { "dropped" : "sample_db", "ok" : 1 }
show dbs
で確認すると、データベース一覧から消えています。
> show dbs admin 0.000GB local 0.000GB
ダミーデータの準備
MongoDBのシェルではJavaScriptの構文が使えるので、以下のようなコードを作成してシェルに貼り付けると、まとめてダミーデータが作成出来ます。
use sample_db; for(let i = 0;i < 20; i++) { db.users.save({id:i, address: "address" + i}); }
find
で確認します。
> db.users.find() { "_id" : ObjectId("590dddf0f62e1b1cfe7bf271"), "id" : 0, "address" : "address0" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf272"), "id" : 1, "address" : "address1" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf273"), "id" : 2, "address" : "address2" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf274"), "id" : 3, "address" : "address3" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf275"), "id" : 4, "address" : "address4" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf276"), "id" : 5, "address" : "address5" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf277"), "id" : 6, "address" : "address6" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf278"), "id" : 7, "address" : "address7" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf279"), "id" : 8, "address" : "address8" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf27a"), "id" : 9, "address" : "address9" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf27b"), "id" : 10, "address" : "address10" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf27c"), "id" : 11, "address" : "address11" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf27d"), "id" : 12, "address" : "address12" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf27e"), "id" : 13, "address" : "address13" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf27f"), "id" : 14, "address" : "address14" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf280"), "id" : 15, "address" : "address15" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf281"), "id" : 16, "address" : "address16" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf282"), "id" : 17, "address" : "address17" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf283"), "id" : 18, "address" : "address18" } { "_id" : ObjectId("590dddf0f62e1b1cfe7bf284"), "id" : 19, "address" : "address19" }
Node.jsとMongoDBの連携
今回はMongooseという、Node.jsからMongoDBを操作するためのライブラリを利用します。
まずはMongooseをインストールします。
$ npm install --save mongoose
ここからはこのMongoose経由でMongoDBにアクセスしていきます。
初めにserver
直下にmodels
ディレクトリを作成し、users
コレクション用のusers.model.ts
を作成します。
ここに以下のようにスキーマを定義し、スキーマからモデルをコンパイルします。
users.model.ts
import * as mongoose from "mongoose"; const usersModel: mongoose.Model<mongoose.Document> = mongoose.model( "users", new mongoose.Schema({ id : { type: Number }, address : { type : String } }) ); export { usersModel };
次にMongoDBへの接続について、アプリケーションのエントリポイントであるwww.ts
に追記します。
listenに成功したコールバックの中で、mongoose.connect
を利用してMongoDBに接続します。
接続先はサーバのポート設定を記述したconfig.tsに外部化しておきます。
www.ts
import * as http from "http"; import { app } from "../app"; import { serverPort, mongoUri } from "../config"; import * as mongoose from "mongoose"; const port = process.env.PORT || serverPort; app.set("port", port); const server = http.createServer(app); server.listen(port, () => { mongoose.connect(mongoUri); });
config.ts
export const serverPort: number = 4300; export const mongoUri: string = "mongodb://localhost/sample_db";
apiの実体であるusers.ts
から実際にMongoDBへアクセスします。
先ほど作成したモデルからfind
し、コレクションの全ドキュメントを取得して返します。
users.ts
import { Request, Response, Router } from "express"; import { usersModel } from "../models/users.model"; const usersRouter: Router = Router(); usersRouter.get("/", (request: Request, response: Response) => { usersModel.find({}, function(err, users) { if (err) throw err; response.json({users: users}); }); }); export { usersRouter };
動作確認
これで以下のような一連の流れが完成しました。
おしまい
これで全6回に渡るMEANスタック入門は完了です。 ここからさらにAngular側を掘っていくとか、Express側でRESTfulなAPIを構築していくだとか、色々とやりたいことはありますので、気が向いたらまた書きたいと思います。
最後に、記事に誤っている部分を発見した方や、もっと良い方法をご存じの方はぜひお声がけ下さい。
MEANスタック入門(5) タスクランナーの代わりにnpm-scriptsを使う
ビルドから実行までを自動化するのに、gulpやgruntなどのタスクランナー代わりにnpm-scripts
を使います。
npm-scriptsの設定
開発時
開発時はそれぞれコードの変更を監視して、自動でトランスパイルを走らせます。
Angularをng server
で実行し、Express側のトランスパイルをtsc
で実行します。
また、変更を検知して自動でコンパイルするために別途tsc
を-w
オプション付きで実行し、それによりソースが書き換わった際に自動で再起動するnodemon
を実行します。
コマンドは順を追うと以下の通りです。
$ ng server --proxy-config proxy.conf.json $ tsc -p ./server $ tsc -w -p ./server $ nodemon dist/server/bin/www.js
上記をpackage.json
のscripts
に設定し、npm-run-all
を使って並列実行します。
必要なnpm-run-all
とnodemon
をインストールしておきます。
$ npm install --save-dev npm-run-all $ npm install --save-dev nodemon
サーバ開始前にTypeScriptのトランスパイルを実行させたいので、run-s
を使って直列につなぎます。
次にそれぞれのサーバ開始と監視開始をrun-p
を使って並列に実行します。
Angular側の作業順序はng server
コマンドに任せます。
また、ついでにMongoDBの起動もここでやっておきます。
package.json
"scripts": { "start": "run-s tsc start:p", "tsc": "tsc -p ./server", "start:p": "run-p start:mongo watch:*", "start:mongo": "mongod --config \"C:/MongoDB/Server/3.4/bin/mongodb.config\"", "watch:ng": "ng server --proxy-config proxy.conf.json", "watch:tsc": "tsc -w -p ./server", "watch:nodemon": "nodemon dist/server/bin/www.js" }
npm run
で実行すると、上記手順が一度に実行されます。
$ npm run start
公開用
それぞれ単純にビルドします。
package.json
"scripts": { "build": "run-p tsc build:ng", "build:ng": "ng build --prod" }
同じくnpm run
で実行します。
$ npm run build
これだけでもかなり効率化されました。
MEANスタック入門(4) AngularとExpressの連携
今回はExpressで作成したAPIをAngularから実際に利用しつつ、Angularの基本的な開発方法に触れていきます。
project-name/src/app
配下で作業し、作業後の構成は以下のようになります。
app │ app-routing.module.ts │ app.component.html │ app.component.scss │ app.component.spec.ts │ app.component.ts │ app.module.ts │ ├─components │ └─call-express-api │ call-express-api.component.html │ call-express-api.component.scss │ call-express-api.component.spec.ts │ call-express-api.component.ts │ └─services call-express-api.service.spec.ts call-express-api.service.ts
Serviceの作成
Angularでは、各種APIへのアクセスはServiceから行います。
services
ディレクトリを作成し、Angular CLIのng g service
コマンドで必要ファイルを生成します。
ng g service
コマンドはカレントディレクトリに依存するので、services
ディレクトリまで移動してから実行します。
$ ng g service callExpressApi
実行すると以下の2ファイルが生成されます。
spec
のほうはテスト用なので、call-express-api.service.ts
のほうにAPIにアクセスするgetUsers
メソッドを実装します。
まず、HTTPアクセスに必要なHttp
クラスをインポートしてコンストラクタの引数に指定します。
また、Http.get
はObservable型の値を返すので、Observable.map
を使うためにrxjs/add/operator/map
をインポートします。
call-express-api.service.ts
import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/map'; @Injectable() export class CallExpressApiService { constructor( private http: Http ) { } getUsers() { return this.http.get("api/users") .map(response => response.json()); } }
上記ではapi/users
にアクセスしていますが、ng server
で実行している場合、Angularの簡易サーバとAPIサーバが別のポートで動いているので、Angular側からAPIを呼ぶと404のエラーになります。
また、ポートまで指定してAPIにアクセスした場合も、クロスオリジンのエラーで同じく実行出来ません。
これを回避するには、プロジェクトのルートディレクトリにproxy.conf.json
を作成し、ng server
実行時に--proxy-config
オプションで読み込ませます。
proxy.conf.json
{ "/api": { "target": "http://localhost:4300", "secure": false } }
$ ng server --proxy-config proxy.conf.json
これでポートの差異を意識せず開発出来るようになります。
Componentの作成
Componentはビューの部品のようなもので、各部品毎の表示や動作を定義します。
components
ディレクトリを作成し、Angular CLIのng g component
コマンドで必要ファイルを生成します。
ng g component
コマンドはng g service
と同じくカレントディレクトリに依存するので、components
ディレクトリまで移動してから実行します。
$ ng g component callExpressApi
実行するとcall-express-api
ディレクトリが生成され、その配下に以下4ファイルが生成されます。
- call-express-api.component.html
- call-express-api.component.scss
- call-express-api.component.ts
- call-express-api.component.spec.ts
call-express-api.component.ts
CallExpressApiComponent
クラスを作成し、先ほど作成したCallExpressApiService
を実行して、HTML表示用の変数に代入します。
CallExpressApiService
をインポートしてコンストラクタの引数に指定し、Serviceのインスタンスを生成するためにproviders
で読み込みます。これは、app.module.ts
でグローバルに読み込んでも動きますが、今回はこのComponentだけなのでここで読み込みます。
getUsers
はObservableを返すので、subscribe
メソッドでデータを受け取って変数users
に代入します。
call-express-api.component.ts
import { Component, OnInit } from '@angular/core'; import { CallExpressApiService } from '../../services/call-express-api.service'; @Component({ selector: 'app-call-express-api', templateUrl: './call-express-api.component.html', styleUrls: ['./call-express-api.component.scss'], providers: [CallExpressApiService] }) export class CallExpressApiComponent implements OnInit { users: any; constructor( private callExpressApiService: CallExpressApiService ) { } ngOnInit() { this.callExpressApiService.getUsers().subscribe(u => { this.users = u.users; }); } }
call-express-api.component.html
APIからの返答が代入された変数users
を利用して、内容を表示するHTMLを作成します。
配列を受けて要素の数だけ繰り返し表示させる場合、ngFor
ディレクティブを利用します。*
プレフィックスを付与することでtr
要素がテンプレート化され、そのテンプレートを元にusers
の各要素の内容が表示されます。
call-express-api.component.html
<table border="1"> <tr *ngFor="let user of users"> <td>{{user.id}}</td> <td>{{user.address}}</td> </tr> </table>
ルーティングの設定
初めに表示されるComponentはapp
直下にあるapp.component.html
です。
ここにナビゲーションを用意し、ナビゲーションをクリックするとヘッダーを残してコンテンツ部分が切り替わるような、いわゆるシングルページアプリケーションの構成にします。
routerLink
ディレクティブでURIを指定し、<router-outlet>
タグでコンテンツ表示位置を設定します。
app.component.html
<header> <h1 class="logo"><a href="/">MEAN</a></h1> <nav> <ul> <li><a routerLink="/users">Users</a></li> </ul> </nav> </header> <router-outlet></router-outlet>
Angularアプリをng new
で初めに生成する際、--routing=true
を付けているとapp
直下にapp-routing.module.ts
が生成され、app.module.ts
で既に読み込まれています。
このapp-routing.module.ts
に、ルーティングさせたいURIとComponentを記述します。
app-routing.module.ts
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { CallExpressApiComponent } from './components/call-express-api/call-express-api.component'; const routes: Routes = [ {path: 'users', component: CallExpressApiComponent}, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
動作確認
ng server
で実行している場合のAngular側のテストは、http://localhost:4200にアクセスします。
Usersのリンクをクリックすると、APIのレスポンスを受けてテーブルが表示されます。
ビルド後はdist
ディレクトリのclient
配下のファイルも揃うので、dist/server/bin/www.js
を実行するだけでhttp://localhost:4300からclient
配下のファイルも提供されます。
MEANスタック入門(3) Expressを利用したバックエンド開発
今回はAngular CLIで作成したAngularのディレクトリ階層を足場にして、Expressを活用したバックエンドの開発を行います。
言語はTypeScriptで書いていきますので、トランスパイルの方法などにも触れていきます。
TypeScriptのインストール
基本的にコードはTypescriptで書くのでtypescript
をインストールします。
--save-dev
オプションを指定すると、package.json
のdevDependencies
に書き込まれます。
npm install --save-dev typescript
ローカルインストールしたのでtsc
はnode_modules/.bin/
配下にあります。
node_modules/.bin/
にパスを通しておくか、以下のように実行します。
$ node_modules/.bin/tsc
ここから先はパスを通した前提で進めます。
Expressのインストールとバックエンドの実装
まずはexpress
とリクエストデータを処理するためのbody-parser
をインストールします。
--save
オプションを指定すると、package.json
のdependencies
に書き込まれます。
$ npm install --save express body-parser
ルートディレクトリにserver
ディレクトリを作成し、以下のような構成にします。
server │ app.ts │ config.ts │ tsconfig.json │ ├─bin │ www.ts │ └─routes users.ts
エントリポイントはbin
配下のwww.ts
です。
server
直下のapp.ts
とconfig.ts
を参照します。
www.ts
import * as http from "http"; import { app } from "../app"; import { serverPort } from "../config"; const port = process.env.PORT || serverPort; app.set("port", port); const server = http.createServer(app); server.listen(port);
設定ファイルconfig.ts
にポート番号を記載します。
config.ts
export const serverPort = 4300;
www.ts
の中でhttp.createServer
に渡しているapp.ts
には、サーバーでリクエストを受け取った時の処理を書きます。
ルーティングはここで実行し、実際の処理はroutes
配下のファイルに振ります。
ちなみに開発中にAngularをng server
で実行している場合はdist/client
は空なので、ルートにアクセスしても404になります。
app.ts
import * as express from "express"; import * as path from "path"; import { json, urlencoded } from "body-parser"; import * as compression from "compression"; import { usersRouter } from "./routes/users"; const app: express.Application = express(); app.disable("x-powered-by"); app.use(json()); app.use(compression()); app.use(urlencoded({ extended: true })); app.use(express.static(path.join(__dirname, "../client"))); app.use("/api/users", usersRouter); app.get("/", (req, res) => { res.sendFile(path.join(__dirname, '../client/index.html')); }); export { app };
users.ts
を作成してapiの実体を書きます。
ここでは/api/users
にGETでアクセスがあった場合、ダミーデータのjsonを返すようにします。
users.ts
import { Request, Response, Router } from "express"; const usersRouter: Router = Router(); let users = {users: [ { id: 0, address: "NA6IF2OMBSTK2NEMXMYDQYXT32IGPKHSMULWLAKE" }, { id: 1, address: "NDSNEM2HC4IEPQXGVDOWYMJ2MIPENUXN6HFJDHYZ" } ]}; usersRouter.get("/", (request: Request, response: Response) => { response.json(users); }); export { usersRouter };
トランスパイルとサーバーの実行
これでロジックは完成なので、トランスパイルの設定をserver
直下のtsconfig.json
に書きます。
outDir
で出力先を設定します。
tsconfig.json
{ "compilerOptions": { "declaration": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, "lib": ["es6", "dom"], "module": "commonjs", "moduleResolution": "node", "outDir": "../dist/server", "target": "es6", "typeRoots": [ "../node_modules/@types" ] } }
tsc
は-p
オプションで上記で作成したtsconfig.json
の位置を指定して実行します。
$ tsc -p ./server
トランスパイルされたwww.jsを実行すると、config.ts
に設定したポートでサービスが提供されます。
$ node dist/server/bin/www.js
動作確認
http://localhost:4300/api/usersにアクセスすると、apiからレスポンスが返ってきます。
これでExpress側の準備は一旦完了です。
MEANスタック入門(2) Angularを利用したフロントエンド開発
今回はAngular CLIを利用したAngularのHello World的な内容になります。
Angular CLIのインストール
Angular2アプリの開発には、必須という訳ではありませんがAngular CLIを利用するのがおすすめです。
ディレクトリ構成を自動的に整えてくれますし、各種Componentのひな型の生成、簡易サーバによる高速なプレビューなど、非常に効率的に開発出来ます。
今後も基本的にAngular CLIで生成されたディレクトリを足場にして以降の開発を進めていきます。
まずはangular-cli
をインストールします。
$ npm install -g @angular/cli $ ng -v @angular/cli: 1.0.1 node: 6.9.4 os: win32 x64
Angular2アプリの作成と実行
次にAngular2アプリを作成します。
CSSではなくSCSSなどの言語を利用したい場合は--style
オプションで切り替え、ルーティングモジュール付きで生成する場合は--routing
オプションで設定します。
ルーティングモジュールはapp.module
に直接書くケースもあるようですが、別ファイルに分けたほうが後々開発しやすいと思うので、true
で実行します。
$ ng new project-name --style=scss --routing=true
作成したアプリをng server
コマンドで実行します。
$ cd project-name
$ ng server
実行するとプロジェクトがビルドされ、簡易サーバが立ち上がります。
動作確認
http://localhost:4200にアクセスすると、動作が確認出来ます。
同時にソースを監視するようになっているので、コードを書き換えるたびに自動的にリビルドされて非常に便利です。
Angular2アプリのビルド
実行中のアプリを本番環境用にビルドします。
デフォルトだと、ビルドされたファイルはdist
ディレクトリに配置されます。
後ほどdist
ディレクトリをサーバ側と共有する予定なので、.angular-cli.json
のapps
にあるoutDir
を書き換えて出力先を変更します。
"outDir": "dist/client"
ng build
でビルドします。
--prod
オプションを付けると公開用にminifyされたファイルが生成されます。
$ ng build --prod
これでAngular2側の準備は一旦完了です。
MEANスタック入門(1) MEANスタックとは
Angularにハマってしばらく色々と実験していたものの、フロントエンド開発だけではやれないことが出てきたので、バックエンド開発も含めて一通り触ってみようと思い立ちました。
当然のようにMEANスタックに辿り着き、関連する様々な記事を読んでみましたが、イマイチ最新かつ全体を網羅した良い感じの記事に出会えませんでした。 例えば、Angularが古いAngularJSであったり、Angular CLIを使っていなかったり、また、TypeScriptではなかったり。
今更AngularJSは使いたくありませんし、Angular CLIを使いたいので、そうなるとフロントエンドもバックエンドもTypeScriptで統一したいです。ただ、資料がないということは、もしかしたら主流の構成じゃないのかもしれませんが。。
結構サイトによってフォルダ構造などもまちまちで、何が本当に最適な手法かは分からなかったのですが、GitHubなどを見ながら正解を探し求め、最終的にとりあえず辿り着いたそれっぽい結論を、自分用の備忘録も兼ねてまとめておきます。
前提知識
筆者の事前知識は以下のような状況なので、ほぼ入門者と変わらないと思われます。
- JavaScriptは割と昔から触ったことがあった。
- TypeScriptや、いわゆるモダンJavaScriptには最近出会った。
- 最近AngularJSを初めて触り、その流れでAngular2を調べ始めた。
- Angularに触るまでNode.jsは触ったことがなかった。
- ExpressやMongoDBは今回初めて触った。
よって、とりあえず動かしてみるというレベルであれば、前提となる知識はJavaScriptを理解している程度で良いかと思います。
MEANスタックとは
MEANスタックとは、MongoDB、Express、Angular、Node.jsの頭文字をとったもので、4つを組み合わせてバックエンドからフロントエンドまで全部JavaScriptで開発してしまおうというものです。
複数の言語を行き来しなくて良いというのはかなり魅力的です。
MongoDB
JSONやJavaScriptと親和性が高い、NoSQL型ドキュメント指向データベース。
Express
Node.js上で動作するWEBアプリケーションのフレームワーク。 MEANスタックで利用される場合には、主にAPIの実装などバックエンド開発を担う。
Angular
フロントエンドのフレームワーク。モダンJavaScriptの教科書とも言われ、数年ぶりにJavaScriptに触るというような人にはもってこいの教材。
Node.js
サーバーサイドJavaScriptの実行環境。
事前準備
Node.jsのインストール
OSによってまちまちだと思うので、以降はNode.jsはすでに入っている前提で進めます。
入っていなければ公式からインストールします。
パスが通ってなければ通しておきます。
自分がインストールしたバージョンは以下です。
$ node -v
v6.9.4
MongoDBのインストール
同じく、以降はMongoDBはすでに入っている前提で進めます。
入っていなければ公式からインストールします。
インストールフォルダ(自分の環境だとC:/MongoDB/Server/3.4/bin
)にパスを通しておきます。
インストールしたバージョンは以下です。
$ mongod --version db version v3.4.4 git version: 888390515874a9debd1b6c5d36559ca86b44babd OpenSSL version: OpenSSL 1.0.1u-fips 22 Sep 2016 allocator: tcmalloc modules: none build environment: distmod: 2008plus-ssl distarch: x86_64 target_arch: x86_64
データベースは任意のディレクトリに保存出来るので、bin
直下にmongodb.config
を作成して、データベースの保存場所を指定します。
mongodb.config
dbpath=C:/MongoDB/data
上記を指定してmongod
を起動します。
$ mongod --config "C:/MongoDB/Server/3.4/bin/mongodb.config"
これでデータベースが起動しました。
次回からは実際にMEANスタックを利用した開発に入っていきます。