33
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DockerでTypeScript×Node.js×Expressの環境構築

Last updated at Posted at 2021-05-30

やること

Node.jsとExpressの環境構築をDocker上で行います。
また、TypeScriptでの開発を行うためにTypeScript環境のインストールも行います。

まずNode.js×Expressの環境構築後、TypeScriptをインストール、設定します。

準備

Docker Desktopのインストール

こちらからDocker Desktopをインストールします。
Mac/Windows/Linuxに対応しています。

VSCodeのインストール

こちらからVSCodeをインストールします。
他のエディタでも問題ないですが、諸々使いやすいのでおススメします。
MacやLinuxをお使いの方であればvimでも問題ありません。

Node.js×Expressの環境構築

以下、ホスト上の作業は :file_folder: 、Dockerコンテナ上の作業は :whale2: で表します。

:file_folder: ディレクトリ作成

ルートディレクトリ及びソース格納用のsrcディレクトリを作成します。
もちろん、エクスプローラやFinderで直接作成しても問題ありません。

# ルートディレクトリ作成
$ mkdir docker-app

# フォルダ移動
$ cd docker-app

# ソース格納用ディレクトリ作成
$ mkdir src

:file_folder: docker-compose.ymlの作成

Dockerでの環境構築には基本的にDockerfiledocker-compose.ymlの2つが必要です。
それぞれの主な役割は以下の通りです。

  • Dockerfile
     用いるDockerイメージ(例えばNode.jsやApache、Java等動作に必要なパッケージ等)について記述するファイル。
     公開されているDockerイメージをそのまま使う場合は必要なく、カスタマイズしたい場合に作成する。

  • docker-compose.yml
     コンテナの定義やマッピングするポート等コンテナに関する設定を記述するファイル。
     必ず記述する。

今回、Node.jsは公開されているイメージを使用するため、Dockerfileは作成しません。
まずdocker-compose.ymlを作成します。
※下記のコマンドはWindowsでは使用できないため、エクスプローラやVSCode上で作成してください。

# ファイル作成
$ touch docker-compose.yml

# ファイルを開く
$ vim docker-compose.yml
docker-compose.yml
version: '3'
services:
    app:
        # 起動イメージ
        image: node:16
        # 環境変数
        environment:
            - DEBUG=app:*
        tty: true
        # ホスト側のポート:コンテナのポート
        ports:
            - '3000:3000'
        # ホスト側のsrcをコンテナのappにマウント
        volumes:
            - ./src:/app
        # 起動時のカレントフォルダ
        working_dir: /app
        # 起動後に実行するコマンド
        command: npm start

重要な箇所は # ホスト側のsrcをコンテナのappにマウントの部分で、通常Dockerコンテナを停止するとコンテナ上で作成した各種ファイルは削除されますが、上記の記述を行うことでコンテナ起動時に再度ファイルがマウント(反映)されます。

また、Dockerコンテナ上で作成・変更したファイルもこちらに記述した場所に反映されます。

基本、ホスト上とコンテナ上でファイルの同期をとるための記述と考えればOKです。

:file_folder: Dockerコンテナ起動

docker-compose.ymlを作成できたので、早速Dockerコンテナを起動します。

# Node.jsコンテナを起動
$ docker-compose run --rm app /bin/bash

docker-composeコマンドにはrun、up、build等があります(違いはこちら等を参照)。
runの場合は単一コンテナのサービスに対して1回コマンドを実行します。

上記ではappコンテナ(Node.jsコンテナ)でbashを起動しています。

rmオプションはDockerコンテナ停止時にコンテナを削除する機能で、停止したコンテナが残り続ける問題を解決するためのオプションです。

:whale2: Expressアプリケーション作成

上記起動がうまくいけば、Dockerコンテナ上でbashが起動した状態になります。
Node.jsコンテナが起動しているので、早速Expressをインストールしていきます。

# express-generatorでひな形を生成
root@2e490c20618c:/app# npx express-generator

※npxコマンドはpackage.jsonに定義されていないものでも実行可能なコマンド。
上記コマンドを実行すると、routeやviewフォルダ、package.jsonapp.js等が作成されます。
コンテナ上で作成されると同時に、ホスト上のsrc配下にも同じフォルダやファイルがこの時点で作成されます。

次に、package.jsonに記述されている依存パッケージをインストールします。
さらにこのままだと、ホスト上で変更したソースコードを反映させるために毎回コンテナの再起動が必要になるため、ソースコードの変更を検知して必要な時にアプリケーションを再起動するnodemonをインストールする。

# 依存パッケージをインストール
root@2e490c20618c:/app# npm install
# nodemonをインストール
root@2e490c20618c:/app# npm install -D nodemon

インストールが完了したらCtrl+Dキーを押下してコンテナを停止します。

:file_folder: nodemonに関する設定変更

nodemonをコンテナ起動時のデフォルトコマンドに設定するため、package.jsonのscriptsとdocker-compose.ymlのcommandを以下のように変更します。

package.json
"scripts": {
  "dev": "nodemon ./bin/www",
  "start": "node ./bin/www"
},
docker-compose.yml
# 起動後に実行するコマンド
command: npm run dev

:file_folder: Expressアプリケーション起動

ここまでできれば、この時点で一旦jsでアプリケーション起動が可能なので、コンテナを起動します。
upコマンドで複数コンテナを一度に起動できるため、基本的にはこのコマンドを使います。

# Expressアプリケーションを起動
$ docker-compose up

ブラウザからhttp://localhost:3000にアクセスします。
下記のような初期画面が表示されていれば成功です。

express2.PNG

TypeScriptの環境構築

:file_folder: Dockerコンテナ起動

Dockerコンテナを起動して、TypeScriptをインストールします。

# Node.jsコンテナを起動
$ docker-compose run --rm app /bin/bash

:whale2: TypeScriptインストール

次に、TypeScriptやExpress、インポートしてるパッケージの型定義をインストールしてtsconfigを作成します。

# TypeScriptと型定義をインストール
root@2e490c20618c:/app# npm install -D typescript @types/express @types/cookie-parser @types/morgan @types/http-errors
# tsconfig作成
root@2e490c20618c:/app# npx tsc --init

この段階で、ホスト側にもtsconfig.jsonが作成されますので、ここからホスト側でTypeScript用の設定をします。
Ctrl+DでDockerコンテナを停止します。

:file_folder: 出力先フォルダ設定

tscコマンドでTypeScriptからJavaScriptにコンパイルされますが、デフォルトではtsファイルと同じ階層にjsが作成されます。
tsファイルとjsファイルが同階層に作成されると、管理が煩雑になるためdistフォルダを作成し、そこに出力されるようにします。

# 出力先フォルダ作成
$ mkdir dist

distフォルダに出力されるようにするため、tsconfig.jsonのoutDirを以下のように書き換えます。
また、今回jsファイルと共存させるため、allowJsも有効にします。

tsconfig.json
"allowJs": true,       /* Allow javascript files to be compiled. */
"outDir": "./dist",    /* Redirect output structure to the directory. */

次に、Expressが起動した際に参照する先をdistフォルダに変更するため、binフォルダのwwwの該当部分を以下のように書き換えます。

www
/**
 * Module dependencies.
 */

var app = require('../dist/app');
var debug = require('debug')('app:server');
var http = require('http');

:file_folder: TypeScriptソースコード作成

まず、app.js及びroutesフォルダ配下のindex.jsの拡張子をtsに書き換えます。
さらにこのままでは一部のソースがTypeScriptコンパイルに失敗するので、app.ts及びindex.tsの該当の部分を型定義を追加するために下記のように書き換えます。
index.tsはパスの指定をdist配下からではなく、プロジェクトルートからの相対パスにしたいため、__dirnameを削除します(コンパイルされるのはtsファイルのみのため、publicフォルダやviewフォルダに格納される静的ファイルはdist配下に格納されない)。

app.ts
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index'); // 変更箇所
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join('views'));  // 変更箇所
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join('public')));  // 変更箇所

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req: any, res: any, next: any) {  // 変更箇所
  next(createError(404));
});

// error handler
app.use(function(err: any, req: any, res: any, next: any) {  // 変更箇所
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;
index.ts
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req: any, res: any, next: any) {  // 変更箇所
  res.render('index', { title: 'Express' });
});

module.exports = router;

:file_folder: TypeScriptコンパイル自動化設定

現段階では、ホスト側でtsファイルを書き換えた際、Dockerコンテナ起動時に手動でコンパイルを行う必要があるため、自動化します。
そのために、コンテナ起動時のコマンドを指定するdocker-compose.ymlのcommandを書き換えます。
コンパイルしてからnodemonを起動するようにします。

docker-compose.yml
# 起動後に実行するコマンド
command: sh -c 'npx tsc; npm run dev'

:file_folder: Expressアプリケーション起動

ここまでで、一通りの環境構築完了です。
コンテナを起動しましょう。

# Expressアプリケーションを起動
$ docker-compose up

ブラウザからhttp://localhost:3000にアクセスします。
下記のような初期画面が表示されていれば成功です。

express2.PNG

この後一度Ctrl+Dでコンテナを停止し、index.tsのtitle等を書き換え、再度コンテナを立ち上げた際に変更が反映できていれば成功です!

参考

DockerでNode.jsアプリケーションを開発する (1) Express.jsをコンテナ内で動かす
TypeScript+Expressの快適な開発環境を作ってみた

33
31
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?