酢日報

ch3coohの日報。このブログはひっそりと運営しています

2017-07-12 ch3cooh

焼肉食べた。

仕事

サーバー講習会

nodeのインストール

$ nodebrew install-binary v6.11.0
$ nodebrew use v6.11.0
$ node -v
v6.11.0

npmのインストール

$ npm install -g npm

(黒いツリーが表示される)

$ npm -v
5.2.0

Angularのインストール

$ npm install -g @angular/cli

Angular/cliでアプリの雛形を作る。

$ cd /Users/ch3cooh/Desktop/temp 
$ ng new sample
installing ng
$ cd sample
$ ng serve
** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200 **
Hash: 4db181c8f24a06db10a7                                                    - Time: 7644ms

ブラウザで確認するとアプリが立ち上がっている。

f:id:ch3cooh393:20170712142548p:plain

WebStromでプロジェクトを開いた。

e2eはテスト。

node_modulesはライブラリ群。pacage.jsonに記載されているライブラリをインストールするので、node_modulesを消してもnpm installすることで再度インストールすることができる。CocoaPodsやGradleみたいなもの。

src/appがソースコード。

app.component.tsのapp部分を変更すると、変更がブラウザにも通知される。

export class AppComponent {
  title = 'neko';
}

express

$ npm install --save express body-parser
+ express@4.15.3
+ body-parser@1.17.2
updated 2 packages in 9.754s

npm installに--saveがつけるとモジュールがpackage.jsonに追加される。

server.jsとapi.jsを追加する。

server.js
// Get dependencies
const express = require('express');
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');

// Get our API routes
const api = require('./server/routes/api');

const app = express();

// Parsers for POST data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// Point static path to dist
app.use(express.static(path.join(__dirname, 'dist')));

// Set our api routes
app.use('/api', api);

// Catch all other routes and return the index file
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist/index.html'));
});

/**
 * Get port from environment and store in Express.
 */
const port = process.env.PORT || '3000';
app.set('port', port);

/**
 * Create HTTP server.
 */
const server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */
server.listen(port, () => console.log(`API running on localhost:${port}`));
api.js
const express = require('express');
const router = express.Router();

/* GET api listing. */
router.get('/', (req, res) => {
  res.send('api works');
});

module.exports = router;

f:id:ch3cooh393:20170712145032p:plain

expressのサーバーを起動する。

$ ng build

ビルドがdistにまとまりました。サーバーにアップロードするのはこのdistディレクトリ。

$ node server.js
API running on localhost:3000

http://localhost:3000/apiにアクセスするとさっきおいたserver/routes/apiの結果が表示される。

ビルド&起動が面倒なのでそれについてはあとで説明。

axios

axiosは非同期処理をおこなう。

$ npm install --save axios
+ axios@0.16.2
added 2 packages in 7.305s

api.jsを更新する。

api.js

onst express = require('express');
const router = express.Router();

// declare axios for making http requests
const axios = require('axios');
const API = 'https://jsonplaceholder.typicode.com';

/* GET api listing. */
router.get('/', (req, res) => {
  res.send('api works');
});

// Get all posts
router.get('/posts', (req, res) => {
  // Get posts from the mock api
  // This should ideally be replaced with a service that connects to MongoDB
  axios.get(`${API}/posts`)
    .then(posts => {
      res.status(200).json(posts.data);
    })
    .catch(error => {
      res.status(500).send(error)
    });
});

module.exports = router;

ng build && node server.js でビルドとサーバー起動を同時におこなう。

http://localhost:3000/api/posts にアクセスすると、https://jsonplaceholder.typicode.com/のjsonのモックを返すのが確認できた。

f:id:ch3cooh393:20170712150638p:plain

このjsonファイルをngで表示させる。

コントローラーを追加する

コントローラーを生成する。

$ ng generate component posts
installing component
  create src/app/posts/posts.component.css
  create src/app/posts/posts.component.html
  create src/app/posts/posts.component.spec.ts
  create src/app/posts/posts.component.ts
  update src/app/app.module.ts

app.module.ts を修正。ルーターを追加する。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { PostsComponent } from './posts/posts.component';
import {RouterModule} from "@angular/router";

// Define the routes
const ROUTES = [
  {
    path: '',
    redirectTo: 'posts',
    pathMatch: 'full'
  },
  {
    path: 'posts',
    component: PostsComponent
  }
];

@NgModule({
  declarations: [
    AppComponent,
    PostsComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(ROUTES) // Add routes to the app
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

ルートアクセスで posts にリダイレクト、postsにアクセスされるとPostsComponentを表示する

メイン画面の下側にPostsComponentを表示する

src/app/app.component.html にアクセスする

<div style="text-align:center">
  <h1>
    Welcome to {{title}}!!
  </h1>
</div>

<router-outlet></router-outlet>

<router-outlet></router-outlet>は何をしているのか。

なるほど。ブラウザに表示されているのはずっとapp.component.html のままで、

<router-outlet></router-outlet>を置いた部分はコンポーネントによって置き換えられる。さっきはルートのコンポー年とがPostCompoenentだったので、posts.component.htmlの内容がそっくりと表示されている。

ビルドがめんどくさい問題

package.json

  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },

を書き換える。

  "scripts": {
    "ng": "ng",
    "start": "ng build && node server.js",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },

npm startでビルドとサーバー実行をおこなえるようになった。

サービス

さっきまではコンポーネント。次はサービスというモジュール。サービスとはDIです

$ ng generate service posts
installing service
  create src/app/posts.service.spec.ts
  create src/app/posts.service.ts
  WARNING Service is generated but not provided, it must be provided to be used

app.module.tsに追加。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from "@angular/router";

import { AppComponent } from './app.component';
import { PostsComponent } from './posts/posts.component';
import { PostsService } from "./posts.service";

// Define the routes
const ROUTES = [
  {
    path: '',
    redirectTo: 'posts',
    pathMatch: 'full'
  },
  {
    path: 'posts',
    component: PostsComponent
  }
];

@NgModule({
  declarations: [
    AppComponent,
    PostsComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(ROUTES) // Add routes to the app
  ],
  providers: [PostsService],
  bootstrap: [AppComponent]
})
export class AppModule { }

src/app/posts.service.ts

import { Injectable } from '@angular/core';

@Injectable()
export class PostsService {

  constructor() { }

}
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class PostsService {

  constructor(private http: Http) { }

  // Get all posts from the API
  getAllPosts() {
    return this.http.get('/api/posts')
      .map(res => res.json());
  }

}

@Injectable()がDIできるという宣言。

src/app/posts/posts.component.ts

import { Component, OnInit } from '@angular/core';
import { PostsService } from '../posts.service'; //add

@Component({
  selector: 'app-posts',
  templateUrl: './posts.component.html',
  styleUrls: ['./posts.component.css']
})
export class PostsComponent implements OnInit {

  // instantiate posts to an empty array
  posts: any = []; //add

  constructor(private postsService: PostsService) { }

  ngOnInit() {
    // Retrieve posts from the API //add
    this.postsService.getAllPosts().subscribe(posts => {
      this.posts = posts;
    });
  }

}

src/app/posts/posts.component.html

<div class="container">
  <div class="row" *ngFor="let post of posts">
    <div class="card card-block">
      <h4 class="card-title">{{ post.title }}</h4>
      <p class="card-text">{{post.body}}</p>
      <a href="#" class="card-link">Card link</a>
      <a href="#" class="card-link">Another link</a>
    </div>
  </div>
</div>

src/index.htmlにbootstrapを追加する。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Sample</title>
  <base href="/">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.css">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>

メモ:あとでWebStormを買う。

趣味開発

Android版ikatomo2の言語ファイルを整えた。ポーランド語とチェコ語が追加されると聞いたけれど、モノトーン氏の検証によると有志が製品ページから持って来たものじゃないかという話だった。

各言語の名前を抽出しているのでまとめてGitHubにアップして共有したい。イカツールを増やしたい。