echo("備忘録");

IT技術やプログラミング関連など、技術系の事を備忘録的にまとめています。

【Serverless Framework】簡単デプロイとserverless.ymlの記載について その1

概要

近日、仕事でAWSを触っていますが、その関係でServerless Frameworkを触ることになりました。

公式サイト:Serverless Framework

Serverless FrameworkはSAM同様、サーバーレスアプリ開発フレームワーク(正確にはテンプレートモデルに近い。Webアプリなどのフレームワークとはちょっと違う)CLIで、以下のことを行うことができます。

  • 環境(言語)ごとのテンプレートモデルの適用
  • 使用するリソース(Lambda、S3、DymnamoDBなど)の定義
  • コマンドライン上からの一括デプロイ(CloudFormationへの展開)

また、主に下記の点がSAMと異なります。

  • マルチクラウドプラットフォームである。(AWSだけでなく、AzureやGCPなどでも使える)
  • (ローカル環境での)デバッグ実行に、コンテナ(Dockerなど)が不要

があります。

ただ、公式ドキュメントが全編英語で、解説してるサイトもあまり多くなかったので、自分なりに「とりあえずデプロイ」できるところまでをまとめました。

インストール &プロジェクト作成

インストールは公式サイトのトップにもある通り、npm installをするだけです。(「-g」は必要に応じて置き換えてください。)

npm install -g serverless

プロジェクト作成は「serverless create」コマンドで作成します。

  • テンプレート名は言語別のテンプレート名。「aws-nodejs」「aws-python3」「aws-csharp」など。(詳細は公式ページを参照)
  • サービス名はアプリのプロジェクト名(≒アプリ名)。Serverless Frameworkでは「サービス」という扱いになる。
  • プロジェクトフォルダのパスはオプション。このフォルダがない場合、プロジェクト作成時に自動で作成して、そこをプロジェクトのルートにしてくれる。
# 「sls」は「serverless」の省略系。どちらでも実行可。
sls create --template (テンプレート名) --name (プロジェクト名)  --path (プロジェクトフォルダのパス)  
# e.g.  
sls create --template aws-nodejs --name makky12-serverless-fw-app --path makky12-dir

テンプレートファイル(serverless.yml) の定義

※これ以降は、AWSをベースに説明します。(それ以外の場合は、公式ドキュメントを参照)

serverless.ymlは、デプロイされるサービスの定義を行うファイルです。
(SAMのtemplate.ymlに該当)

つまりこの内容が、CloudFormationやLambdaなどの各種機能に設定されます。

ただこの公式ドキュメントのボリュームが大きいので、補足説明がいるなという項目だけ説明します。
(基本的なことは、公式の下記ページに書いてあります。全編英語ですが)

※プロジェクトに最初から入ってるhandler.jsを動かすだけなら、下記を設定してデプロイを実施するだけで、API Gateway経由でブラウザ実行できます。
(項目数は多いですが、ほとんどにデフォルト値が設定されてます。)

  • providerに「region: ap-northeast-1」を設定する。
  • 66 ~ 69行目(「events」~「method:get」)までのコメントを外す

ルート項目(インデントがない項目)

項目名 説明 備考
provider 複数項目で共通で使用する項目の値を設定する 項目別に上書き可能
custom serverless.yml内で使用する変数と値のペアを設定する 変数については後述
package プロジェクトをパッケージする際の設定をする
plugins 外部プラグインを使用する場合、プラグイン名を記入する 公式に書いてないんだけど...
functions Lambda関数の設定をする
resources プロジェクトで使用するリソース(S3/DynamoDBなど)の設定をする

provider項目

項目名 説明 備考
stage dev(開発)/stg(ステージング)など、環境が分かる設定をする 初期値はdev
〇〇name CloudFormation/API Gatewayなどで使用される名前 未指定の場合、デフォルト名がつけられる(プロジェクト名+αなど)
profile credentialを定義済の場合、そのプロファイル名を指定する デプロイの際、設定したプロファイルの認証情報を使用する
deploymentBucket パッケージされたファイルを格納するS3のバケット名を指定する 注意が必要。(後述)
role 全Lambda関数に適用される共通のIAMロールを設定する
iamRoleStatements Lambda関数以外のリソース(S3/DynamoDBなど)のIAMロールの設定をする
environment Lambda関数の環境変数と値のペアを設定する

package項目

項目名 説明 備考
include/exclude パッケージされるファイルとして含めたい/除きたいファイルを指定 ワイルドカードによる再帰的指定可能。tsconfig.jsonの同盟項目と同じ
excludeDevDependencies excludeDevDependenciesのモジュールを自動で除外するか デフォルトはtrue
artifact 自分でパッケージをする際のパッケージファイルの置き場? include/exclude設定関係なく、deploy時にパッケージファイルから除外される
individually Lambda関数単位でのパッケージを行うかどうか

functions項目

※functionsの子要素には、デプロイされるLambda関数のfunction名を記載する。下記はその子要素(functionsの孫要素)

項目名 説明 備考
handler 実行する関数。[ファイル名.exports名]形式で記載
events Lambda関数を実行するトリガーとなるイベントの種類 http(API Gateway)/s3/Alexa Skillなど
reservedConcurrency この関数を同時並行で実行できる数?
environment この関数に定義する環境変数と値のペア

resources項目

※resources要素には「Resources」-「リソース定義名」までは決め打ちになる。(「serverless.ymlのサンプル」参照)
下記は「リソース定義名」の子要素になる。(=resourcesのひ孫要素)
※Propertiesの子要素は、Typeごとに異なる。CloudFormationのテンプレートを参照。

項目名 説明 備考
Type リソースのタイプ。DynamoDB/S3など [ファイル名.exports名]形式で記載 AWS::S3::Bucketのように、CloudFormation形式で記載
Properties リソースタイプ別の詳細設定 S3ならバケット名など。(設定項目はリソースにより異なる)

serverless.ymlのサンプル

app: makky12-serverless-app

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
frameworkVersion: ">=1.0.0"

custom:  
  author : makky12  

provider:
  name: aws
  runtime: nodejs10.x  
  stage: dev
  region: ap-northeast-1
  stackName: makky12-serverless-app
  apiName: makky12-serverless-app-dev
  deploymentBucket:
    name: makky12-serverless-app-dev-bucket
    serverSideEncryption: AES256
  deploymentPrefix: makky12
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "s3:ListBucket"
      Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ]  }
    - Effect: "Allow"
      Action:
        - "s3:PutObject"
      Resource:
        Fn::Join:
          - ""
          - - "arn:aws:s3:::"
            - "Ref" : "ServerlessDeploymentBucket"
            - "/*"

package:
  exclude:
    - exclude-dir/readmme.txt

functions:
  greeting:
    handler: handler.greeting
    events:
      # httpはAPI Gatewayがトリガになるイベント。  
      # corsはクロスオリジン制約に関する設定。
      - http:
          path: users/create
          method: get
          cors: true

  environment:
    NENGO: Reiwa

resources:
  Resources:
    makky12Bucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: makky12-bucket
    makky12Table:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: makky12Table
        AttributeDefinitions:
          - AttributeName: e-mail
            AttributeType: S
        KeySchema:
          - AttributeName: e-mail
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1

と、なんか書いてたらものすごく長くなってしまいましたので、本当はデプロイやserverless.ymlの変数仕様についても書く予定だったのですが、それはその2に書きます。

【Microsoft】de:code2019体験記その2 面白かったセッション紹介

概要

前回、de:code2019の「C# ドキドキ・ライブコーディング対決」を自分でも実施しましたが、今回は純粋に面白かったセッションの紹介をしようと思います。

Xamarin.Forms アプリケーション設計パターン

マイクロソフトの大田 一希氏(かずきさん)のセッション。
Xamarin.Formsの新機能や、設計&作成時のパターンなどについて、詳しく解説していただきました。

また、デモもあり、動作しているところを実演していただける...
はずだったんですよね。

マイクロソフトのこういう大きいイベントでは、どなたか一名は必ず本番で悲劇に見舞われるのですが...今回はかずきさんだったようです。(意味深)

とはいえ、楽しませて頂きましたし、僕もその気持ちは痛いほどわかりますからね。(てか何で、起こって欲しくないときに限って、確実に起こるんでしょうね、フリーズって。)

Windows 10 対応のデスクトップアプリを作る技術

上に続き、再びかずきさんのセッション。
UWPとかWPFとか、その他についての情報でした。

てか、UWPって敬遠気味だったんですが、すごい進化してるんですね。
デモを見てて、すごくおもしろそうでした。

何事も、食わず嫌いはいけませんね。ホントに

エンジニアの人生設計 ~どのようにキャリアを描いていけばよいのか~

MSのテクノロジーセンター長(要はめちゃくちゃ偉い人)、澤円さんのセッション。
僕がde:code2019で一番聞きたかったのがこのセッション。

いや、事前に一番人気と聞いていましたが(しかも澤さん本人から!)、想像以上でした。 (さすがに参加者が多かったとはいえ、前のセッション開始時から行列ができてたのは、このセッションだけです)

しまいには部屋に収まりきらず、急遽別会場を用意して、それでも収まりきらない...という大盛況ぶり。

さすが「プレゼンの神」の異名は伊達じゃないなあ、と思いました。

さて内容は、技術とは一切関係はないのですが、いわば「人生を豊かに」そして「幸せに生きるには」という、非常に重要なテーマです。

そして重要なのは、

  • 自己分析&自分に合ったことをする
  • キャリアの定期的な見直し&ポートフォリオの公開
  • ビジネスのつながりを積極的に構築する(Twitter&LinkedInなどで)
  • 睡眠だけは、絶対おろそかにしてはダメ!

という、分かっているんだけど、なかなか出来ないことの重要性を改めて教えてくれる、ありがたい内容でした。

...僕も幸せになりたいなあ。

結論

個人的は、やはり勉強会に限らず、たとえ東京の勉強会・イベントであっても、出来る限りこういうイベントは参加しておくべきだなあ、と感じました。

確かに出費は痛いんですが、色々な人と出会えたり、新しい技術を知ることが出来るのは大きいですし、何よりモチベーションの上がり方が半端ないです。

来年も、ぜひde:codeに参加したいなあ、と思いました。

...てなことを、現在(2019/6/13 21時ちょうど)AWS Summitに向かう新幹線の中で書いてます。

【Microsoft】de:code2019体験記その1 C#で令和元年を表示する

概要

先日、マイクロソフトのde:code2019に参加してきました。

本当に素晴らしいセッションを通して勉強することが多く、行って正解だったと思います。
それにこういうイベントで知見が広まると、モチベーションも上がりますね。

あと、某スペシャルゲストも、本当にスペシャルな人でしたからね。

そんな中で「C# ドキドキ・ライブコーディング対決 @ de:code - ONLY C#!! Blazor Web 開発バトル」というセッションがありました。

私は残念ながら拝聴できなかったのですが、「その場で与えられたお題に対して、即興で時間内にプログラミングして動かす」というものです。
ちなみにお題は「C#で令和元年を表示する」だったようです。

「じゃあ自分でやったら、何分かかる?」ということで、やってみました。

結果

とりあえず僕が思いついたのは、下記のコード。
(WinFormアプリとして動くのは確認済です。)

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
  
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
  
        private void button1_Click(object sender, EventArgs e)
        {
            var Ymd = textBox1.Text;
            var listNengoPeriod = new List<NengoPeriod>();
  
            listNengoPeriod.Add(new NengoPeriod(new DateTime(2019, 5, 1), "令和"));
            listNengoPeriod.Add(new NengoPeriod(new DateTime(1989, 1, 7), "平成"));
            listNengoPeriod.Add(new NengoPeriod(new DateTime(1926, 12, 26), "昭和"));
            listNengoPeriod.Add(new NengoPeriod(new DateTime(1912, 7, 30), "大正"));
            listNengoPeriod.Add(new NengoPeriod(new DateTime(1868, 1, 25), "明治"));
  
            var resultNengo = String.Empty;
  
            if (DateTime.TryParse(Ymd, out var dt))
            {
                var nengo = (from n in listNengoPeriod
                             where n.getPeriod <= dt
                             orderby n.getPeriod descending
                             select n).FirstOrDefault<NengoPeriod>();
  
                resultNengo = nengo == null ? "明治より前" : nengo.getNengo;
            }
  
            var message = string.IsNullOrEmpty(resultNengo) ? "指定した年月日が不正です。" : $"{Ymd} は、{resultNengo} です。";
            MessageBox.Show(message);
        }
    }
  
    class NengoPeriod
    {
        public NengoPeriod(DateTime period, string nengo)
        {
            this.getPeriod = period;
            this.getNengo = nengo;
        }
  
        public DateTime getPeriod { get; }
        public string getNengo { get; }
    }
}

上記コード完成にかかった時間は、30分でした。

なお、実際の登壇者がコード完成までにかかった時間は、たったの5分とのこと。
(細かいバグはあったようですが)

いや、カップ麺の待ち時間程度でこれを完成させちゃうって、本当すごいな~、と思いました。
(しかも実際は、トークをしながらとかですからね。)

やはりすごい人はいるんだなあ、と改めていい刺激になりました。

てか、対峙する価値のない人なんて適当にスルーして、その分こういう方々とご一緒させて頂ける時間に割くべきですね、本当に。

※体験記その2は、また後日。

【Javascript】非同期処理の待ち時間にアニメーションを表示する

概要

Webやスマホアプリで、何か非同期処理を行っている際に画面に表示される、くるくる回ったりするアニメーション(正式にはなんていうの...Xamarin.Formsの「Activity Indicator」です)を表示する方法です。

f:id:Makky12:20190517200801g:plain

作成方法

まず「画像はどうするの」となりますが、これは「Loader Generator」というサイトで、簡単に作成&ダウンロードできます。
※サイズ・回転速度・色など、いろいろ細かいところまで調整でき、便利です。

実際に表示する方法

これは、実際にサンプルを見た方が早いと思いますので、ソースを。
(ソース自体は、そこまで難しい内容ではないので、説明は省略)

/* ------------------------------
 非同期処理を実行する関数
 ------------------------------ */
function asyncFunc() {  

    // Loading 画像を表示
    dispLoading("処理中...");
   
    // 非同期処理(例)
    $.ajax({
      async : true,
      url : "http://xxx.com/yyy/zzz",
      type:"GET",
      dataType:"json"
    })
    // 通信成功時
    .done(function(data) {
      alert("成功しました");
    })
    // 通信失敗時
    .fail( function(data) {
      alert("失敗しました");
    })
    // 処理終了時
    .always( function(data) {
      // Loading 画像を消す
      removeLoading();
    });  
}  
    
/* ------------------------------
 表示用の関数
 ------------------------------ */
function dispLoading(msg){
  // 引数なしの場合、メッセージは非表示。
  if(msg === undefined ) msg = "";
  
  // 画面表示メッセージを埋め込み
  var innerMsg = "<div id='innerMsg'>" + msg + "</div>";  
  
  // ローディング画像が非表示かどうかチェックし、非表示の場合のみ出力。
  if($("#nowLoading").length == 0){
    $("body").append("<div id='nowLoading'>" + innerMsg + "</div>");
  }
}
 
/* ------------------------------
 表示ストップ用の関数
 ------------------------------ */
function removeLoading(){
  $("#nowLoading").remove();
}  
#nowLoading {
  display: table;
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  background-color: #fff;
  opacity: 0.8;
}
 
#innerMsg {
  display: table-cell;
  text-align: center;
  vertical-align: middle;
  padding-top: 140px;
  z-index:100;
  background: url("表示するくるくる画像のURL]") center center no-repeat;
}

ポイント

  • 非同期処理開始したら「#NowLoading」及び「#innerMsg」のタグを埋め込み、終了したら削除する。
  • 「#NowLoading」のタグは、body直下の子要素にする。
  • z-indexは、モーダルなどを表示する場合は、大きい値にしておく。
    • モーダルのz-indexとの兼ね合いで非表示になることがある。
  • 「#NowLoading」のタグは、もちろんHTMLに記載してもOK。
    • その場合、visibility:visible(hidden)などで制御する。

と、また簡単になりましたが、今回はこの辺で。

【Javascript】非同期処理のPromiseやasync/awaitについて その2

前回はPromiseについて書きましたが、その続きで今回はasync/awaitについて。

【参考】
async/await 入門(JavaScript)

asyncとは

非同期関数を定義する関数宣言のこと。
async関数は、以下の動作をする。

  • Promiseを返す
  • 値をreturnすると、Promiseはそれをresolveする。
  • エラーなどをスローすると、Promiseはそれをrejectする。
  • 関数内部でawaitを使用できる。
// 普通こんな書き方しませんが、サンプルということで。  
function main() {  
    
    const even = checkEven(2);
  
    // この場合、コンソールには「偶数です」と表示される。
    even.then((message) => {
        console.log(message);
    }).catch((err) => {
        console.log(err.message);
    });
  
    const odd = checkEven(1);
  
    // この場合、コンソールには「奇数です!」と表示される。
    odd.then((message) => {
        console.log('偶数です');
    }).catch((err) => {
        console.log(err.message);
    });
}
  
async function checkEven(num) {
    if(num % 2 === 0) {
        // resolve('偶数です')と同じ。
        return '偶数です';
    } else {
        // reject('奇数です!')と同じ。
        throw new Error('奇数です!');
    }
}

awaitとは

  • Promiseを返す関数について、Promiseの結果(resolveやreject)が返されるまで、処理を待つ。
    • 同期処理みたいな動作になる。
  • awaitを付けた場合、戻り値に格納されるのはresolve、あるいはrejectされた値となる。
  • rejectされたのがエラー場合、そのエラーが発生する。(catch()処理などを実施する必要あり)
  • async関数内でのみ使用できる。

先程の関数を、awaitを使って書くと、こうなります。

async function main() {  
    
    // この場合、messageにはresolve値の「偶数です」が格納されるので、  
    // それがそのまま表示される。
    try {
        const even = await checkEven(2);
        console.log(even);
    } catch(err) {
        console.log(err.message);
    }
  
    // この場合、checkEvenからErrorがスローされるので、コンソールには  
    // err.message(「奇数です!」)が表示される。
    try {
        const odd = await checkEven(1);
        console.log(odd);
    } catch(err) {
        console.log(err.message);
    }
}
  
async function checkEven(num) {
    if(num % 2 === 0) {
        // resolve('偶数です')と同じ。
        return '偶数です';
    } else {
        // reject('奇数です!')と同じ。
        throw new Error('奇数です!');
    }
}

await使用時の注意点

  • awaitは基本的に「resolveの値がないと、それ以降の処理ができない」際に使用する。(下記など)
    • ファイルの内容を取得する
    • DBのあるテーブルのレコードを取得する
  • awaitは先述の通り「Promiseの結果が返されるまで、処理を待つ」動作。
    • async関数だからと言って、なんでもawaitすればいいわけではない。
    • 使い方を間違えると、レスポンス時間の遅延につながる。(下記ソース)
async function main() {  
    
    // funcVal1~funcVal3が「それぞれ処理に5秒かかる」場合、  
    // awaitで直列処理してしまうと、main()が終わるのに15秒かかってしまう。  
    try {
        const val1 = await funcVal1();
        const val2 = await funcVal2();
        const val3 = await funcVal3();
    } catch(err) {
    }
  
    // この場合、await は使わず、Promise.all()を使って並列処理すれば  
    // main()が終わるのは5秒で済む。
    const func1 = funcVal1();
    const func2 = funcVal2();
    const func3 = funcVal3();
  
    Promise.all([func1, func2, func3]).then(([val1, val2, val3]) => {
        // すべて正常終了した際の処理
    }).catch((err) => {
        // どれか一つでもErrorがスローされた際の処理
    });
}

また急ぎ足気味になってしまいましたが、今日はこの辺で。

【Javascript】非同期処理のPromiseやasync/awaitについて その1

Promiseについて

Promiseとは、

  • 非同期処理を制御するためのしくみ
  • ES2015以降で使用可能

メリット

その1. コードが簡潔になり、見やすくなる。(個人差あり)

例えば、非同期関数func1〜func3があったとして、下記の制約がある場合、

  • func2はfunc1の結果が必要
  • func3はfunc2の結果が必要

一般的なコールバック関数を使用した場合、ソースは下記のようになる。
(典型的な「コールバック地獄」というやつです)
※しかもエラー処理を省略してるので、エラー処理も書いたらもっと煩雑になる...

function main() {  
    func1((err, data) => {
        func2(data, (err2, data2) => {
            func3(data2, (err3, data3) => {
                console.log(data3);
            });
        });
    });
}

これがPromiseを使えば、例えばこうなります。

// resolveの引数は、正常終了した際の戻り値。  
// rejectの引数は、エラー発生した際の戻り値。

function funcPromise1() {
    return new Promise(function(resolve, reject) {
        func1((err, data) => {
            if(!err) {
                resolve(data);
            } else {
                reject(err);
            }
        });
    });
}  

function funcPromise2(data) {
    return new Promise(function(resolve, reject) {
        func2(data, (err, data2) => {
            if(!err) {
                resolve(data2);
            } else {
                reject(err);
            }
        });
    });
}  

function funcPromise3(data2) {
    return new Promise(function(resolve, reject) {
        func3(data2, (err, data3) => {
            if(!err) {
                resolve(data3);
            } else {
                reject(err);
            }
        });
    });
}  

function main() {  
    funcPromise1.then((data) => {return funcPromise2(data);})  
        // resolveされた場合、then()の引数にはresolveの引数が格納される。  
        // rejectされた場合、catch()の引数にはrejectの引数が格納される。
        .then((data2) => { return funcPromise3(data2); })
        .then((data3) => { console.log(data3); })
        .catch((err) => { console.log(err); });
}

funcPromise1~funcPromise3の関数定義は増えましたが、ソース自体は見やすくなったと思います。

エラー処理が簡潔になる

(先程のソースで若干ネタバレしてますが)func1〜func3のいずれかでエラーが発生しても、Promiseなら最後の「catch(err)」でまとめてエラー処理ができます。

これがコールバック関数の場合、こうなります。
(クッソ見にくい...というか、try~catchを使った場合、全体を囲ってtry~catchではエラー捕捉ができない(=毎回外側にthrowしなくちゃいけない)ので、もっと大変なことに。)

function main() {  
    func1((err, data) => {
        if(!err) {
            func2(data, (err2, data2) => {
                if(!err2) {
                    func3(data2, (err3, data3) => {
                        if(!err3) {
                            console.log(data3);
                        } else {
                            console.log(err3);
                        }
                    });
                } else {
                    console.log(err2);
                }
            });
        } else {
            console.log(err2);
        }
    });
}

非同期処理の並行実行の制御ができる

Promiseを使った場合、例えば複数の非同期処理を同時実行した場合に、下記のような処理が可能です。

    
function main() {  
    // Promise.race()は、引数の非同期処理のうち、
    // いずれか1個の処理が完了したら次へ進む
    Promise.race([funcPromise, funcPromise2, funcPromise3])
         // 最初に終わった処理がresolveの場合、thenの引数dataに
         // その処理のresolve値が格納される。
         // また最初に終わった処理がrejectの場合、catchの引数errに
         // その処理のreject値が格納される。
        .then((data) => { console.log(data); })
        .catch((err) => { console.log(err); });
  
    // Promise.all()は、引数の非同期処理がすべて終了するまで次へ進まない。
    Promise.all([funcPromise, funcPromise2, funcPromise3])
        // 引数data~data3には、それぞれfuncPromise~funcPromise3の
        // resolve値が格納される。(すべてresolveしないとthen()は実行されない)
        .then(([data, data2, data3]) => { 
            console.log(data); 
            console.log(data2);
            console.log(data3);
        })
        // いずれか1つでもrejectされた場合、最初にrejectされた値の
        // reject値が格納される。
        .catch((err) => { console.log(err); });
}

そして、話はasync/awaitにつながる訳ですが、それはまた後日。

【TypeScript】TypeScriptのインストールと各種環境設定

現在仕事でnode.jsを使用しており、「勉強も兼ねてTypeScriptを導入しよう!」と思い導入したので、その際のメモ。1

前提

参考ページ

packege.jsonの作成

  1. ターミナルソフト(「コマンドプロンプト」とか)を起動。
  2. package.jsonを作成したいフォルダ(アプリケーションのルートフォルダなど)にカレントフォルダを移動。
  3. 下記コマンドを実行。
> npm init
  • ここでは「npm init」の詳細は割愛。
  • 質問事項については、名前以外は「yes」にしておいてOK。(後で変更可能)

TypeScriptのインストール

  • ターミナルソフトで、インストール先フォルダをカレントフォルダにする。(package.jsonと同じで良いなら不要)
  • 下記コマンドを実行。
> npm install --g typescript

テストソースの作成

カレントフォルダに「test.ts」というファイルを作成し、下記ソースを書く。

class Student {
    fullName: string;
    constructor(public firstName: string, public middleInitial: string, public lastName: string) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
        console.log(this.fullName);
    }
}
  
let student = new Student('Leon', 'Scott', 'Kenedy');

その後、ターミナルソフトで下記コマンドを入力。

> tsc test.ts

問題なければ、下記の状態になるはず。

  • ターミナルにカレントフォルダのみが表示される。
  • カレントフォルダに、test.jsファイルが作成される

あとは、test.jsをnode.jsで実行し、下記結果が表示されればOK.

> node test  
Leon Scott Kenedy

その他

ブラウザ(クライアント)側javascript作成時の注意

もちろんTypeScriptでブラウザ側のjavascriptを作成することも可能。
ただしブラウザ側は、「node.jsの「require」(=TypeScriptの「import」)が使用できないため、そのままでは外部ファイルやライブラリをできない、という問題がある。

そこで、この問題を解決する必要があるが、その1つが「browserify」というモジュール。

これは、

  • require先のjsファイルの内容も、まとめて1ファイルにまとめてしまう、というモジュール。
  • require先jsファイルがさらにrequireしている..などの場合でも、依存関係のあるjsファイルをまとめて1つにしてくれる。
  • 結果、requireが不要になるので、ブラウザ側でもrequire先のjsdファイルを使用できる。

手順としては、

  • npmコマンドでインストールして、
> npm install -g browserify
  • 統合先のjsファイルを「-o」オプションで指定して、
> browserify test.js -o bundle.js
  • 最後に、作成された統合先のjsファイルをHTMLなどに埋め込めばOK。
> <script src="bundle.js"></script>
  • 大元のjsファイル(色々requireしているファイル)を「test.js」とします。
  • 統合先ファイルに命名ルールはないですが、通例として「bundle.js」とするようです。

※もちろん、「browserify」以外にも対応策はいろいろありますので、興味があれば探してみてください。

型定義ファイルの作成

「型定義ファイル」とは、

  • 「各種モジュールをTypeScriptで使用可能にする」ためのファイル。
  • Javascriptで記載されてるモジュールを、TypeScriptに変換するためのもの。
  • 型定義ファイルを用意すると、VSCodeでインテリセンスなどが使用可能になる。
  • 型定義ファイルは、下記のコマンドでインストール可能。
> npm install -save @types/(モジュール名) 

※各モジュールの型定義ファイルのインストールコマンドは、下記サイトで検索可能です。

tsconfig.jsonの設定(2019/5/5追記)

tsconfig.jsonとは、

  • TypeScriptや、そのコンパイル時の各種設定を定義するためのファイル。
  • プロジェクトのルートフォルダ(=package.jsonと同じ場所)に保存することで、設定が有効になる。
  • tsconfig.jsonを作成するには、プロジェクトのルートフォルダで下記コマンドを実行すればOK。
> tsc --init 
定義 説明
module モジュール関連のコードをどの方式として扱うか(Common.js, umdなど)
target JavaScriptのバージョン(ES5, ES2015など)
noImplicitAny 型未定義の変数などをエラーとするか(trueならエラー、falseならany型にする。)
strict 型厳格な方チェックを行うか(trueなら実施する。)
outDir コンパイル後のjsファイルの保存先フォルダ(未指定ならtsconfig.jsonがあるフォルダ)
rootDir tsファイルの保存先のルートフォルダ(未指定ならtsconfig.jsonがあるフォルダ)
esModuleInterop common.jsモジュールとESモジュール互換的に扱えるようにするかどうか
strictNullChecks nullやundefinedのチェックを厳格にする(number型の初期値にnullを代入不可、など)
sourceMap souuceMapを作成するかどうか(TypeScriptコード上でブレークポイント設定など、デバッグ可能になる)
exclude tsファイルの保存先として除外するフォルダ(ここで指定したrootDir以下の全フォルダ内の*.tsファイルが、コンパイル対象になる)

とりあえず、今回はこの辺で。


  1. 仕事ではjavascriptを直で書いてます。