Help us understand the problem. What is going on with this article?

webpack4でTypeScript、Socket.IOの環境を作成してみた

More than 1 year has passed since last update.

javascriptを趣味で勉強しているものです。間違いありましたら指摘お願いします

自分が作成したコード

1 インストール

yarn add socket.io express
yarn add -D typescript @types/socket.io @types/socket.io-client @types/express @types/node webpack webpack-cli ts-loader webpack-node-externals
  • socket.io
    • socket.io本体、Nodeサーバーで動く機能とブラウザで動く機能の両方がインストールされる
  • express
  • typescript
  • @types/socket.io
    • socket.io のNodeサーバーで動く機能の型定義
  • @types/socket.io-client
    • socket.io のブラウザで動く機能の型定義
  • @types/express
    • expressの型定義
  • @types/node
    • nodeのhttpモジュールを使用しているところ用の型定義
  • webpack
  • webpack-cli
  • ts-loader
  • webpack-node-externals
    • webpackで生成したファイルを、node bundle.jsと実行する場合にnode_modulesのファイルを一緒にバンドルしている必要はないので、node_modulesを無視して外部関数として扱うようにバンドルしてくれる

2 フォルダ構成

このようなフォルダ構成で作成してみました。

.
├ dist/ # webpackでバンドルしたファイルを出力(nodeサーバー用)
├ node_modules/
├ package.json
├ public/  # 静的ファイルを置く
│ ├ index.html
│ └ js/ # webpackでバンドルしたファイルを出力(ブラウザ用)
├ src/ # 実際に作業するファイル
│ ├ client/
│ │ └ index.ts
│ └ server/
│   └ index.ts
├ tsconfig.json
├ webpack.config.js
└ yarn.lock

Screen Shot 2019-06-09 at 11.png

3 webpack.config.js

webpack.config.js
const nodeExternals = require("webpack-node-externals");

module.exports = [{
    // ブラウザで動く機能をバンドル
    mode: "development",
    entry: {
        client: "./src/client/index.ts",
    },
    output: {
        filename: "[name].js",
        // expressでpublicフォルダ配下を静的に読む込むように設定するので、そこに出力する
        path: `${__dirname}/public/js`,
    },
    module: {
        rules: [{
            test: /\.ts$/,
            use: "ts-loader",
            exclude: /node_modules/,
        }]
    },
    resolve: {
        extensions: [".ts", ".js"]
    },
}, {
    // Nodeサーバーで動く機能をバンドル
    mode: "development",
    entry: {
        server: "./src/server/index.ts",
    },
    target: "node",
    node: {
        // expressを使うときにはこの設定をしないと失敗します
        // 参考:https://medium.com/@binyamin/creating-a-node-express-webpack-app-with-dev-and-prod-builds-a4962ce51334
        __dirname: false,
        __filename: false,
    },
    externals: [nodeExternals()],
    module: {
        rules: [{
            test: /\.ts$/,
            use: "ts-loader",
            exclude: /node_modules/,
        }]
    },
    resolve: {
        extensions: [".ts", ".js"]
    },
}];

socket.ioはnodeサーバーで動く機能とブラウザで動く機能があるため、設定を分ける必要があります。
設定ファイルを2つにするとかでもいいのですが、今回は↑のようなやり方で2つの設定を書きました。

複数の設定をエクスポートする
参考:https://webpack.js.org/configuration/configuration-types/#exporting-multiple-configurations

4 tsconfig.json

tsconfig.json
{
    "compilerOptions": {
      "outDir": "./dist/",
      "noImplicitAny": true,
      "module": "es6",
      "target": "es5",
      "allowJs": true
    }
}

あまり詳しくないので、こちらを参考にして、ほぼそのままです(^_^;)

5 簡易チャット作成

5-1 サーバ作成

src/server/index.ts
import * as express from "express";
import * as http from "http";
import * as socketio from "socket.io";

const app: express.Express = express();
const server: http.Server = http.createServer(app);
const io: socketio.Server = socketio(server);

app.use(express.static("public"));

io.on("connection", (socket: socketio.Socket) => {
    socket.on("hoge_message", (msg: string) => {
        io.emit("hoge_message", msg);
    });
});

server.listen(3000, () => console.log("listening on *:3000"));

expressでサーバを作成し、publicフォルダ配下を静的ファイルとしてアクセスできるようにします。

5-2 ブラウザ側を作成

public/index.html
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Document</title>
<script src="js/client.js" defer></script>
<form><input><button>Send</button></form>
<ul></ul>
src/client/index.ts
import * as io from "socket.io-client";
const socket: SocketIOClient.Socket = io();

const form: HTMLFormElement = document.querySelector("form");
const input: HTMLInputElement = document.querySelector("input");
const ul: HTMLUListElement = document.querySelector("ul");

form.addEventListener("submit", (e: Event) => {
    e.preventDefault();
    socket.emit("hoge_message", input.value);
    input.value = "";
});

socket.on("hoge_message", (msg: string) => {
    ul.insertAdjacentHTML("beforebegin", `<li>${msg}</li>`);
});

5-3 実行

bash
yarn webpack #dist/server.jsとpublic/js/client.jsが出力
node dist/server.js #サーバ起動

http://localhost:3000/ を開いてsocket.ioがうまく動いていることを確認できました。

vdWDonVtHX.gif

6 ファイル監視

6-1 webpack -w

yarn webpack -wとウォッチモードで実行すれば、ファイルを監視してくれて、ファイルに変更を加えるたびにバンドルし直してくれますね。
しかしそれだけだと、サーバーの方のファイルは変更するたびに、Ctrl+Cでサーバーを切り、もう一度server.jsを実行しないと変更が反映されません。なのでnodemonを使ってみます。

6-2 nodemonを使う

nodemonを使えば、サーバー側のファイルを変更するたびに自動でサーバーを再起動してくれます。

yarn add -D nodemon-webpack-plugin

webpack.config.jsに設定を追加します

const NodemonPlugin = require("nodemon-webpack-plugin");

// ..

    plugins: [
        new NodemonPlugin(),
    ],

// ..

全体ではこうなりました

webpack.config.js
const nodeExternals = require("webpack-node-externals");
const NodemonPlugin = require("nodemon-webpack-plugin");

module.exports = [{
    // ブラウザで動く機能をバンドル
    mode: "development",
    entry: {
        client: "./src/client/index.ts",
    },
    output: {
        filename: "[name].js",
        // expressでpublicフォルダ配下を静的に読む込むように設定するので、そこに出力する
        path: `${__dirname}/public/js`,
    },
    module: {
        rules: [{
            test: /\.ts$/,
            use: "ts-loader",
            exclude: /node_modules/,
        }]
    },
    resolve: {
        extensions: [".ts", ".js"]
    },
}, {
    // Nodeサーバーで動く機能をバンドル
    mode: "development",
    entry: {
        server: "./src/server/index.ts",
    },
    target: "node",
    node: {
        // expressを使うときにはこの設定をしないと失敗します
        // 参考:https://medium.com/@binyamin/creating-a-node-express-webpack-app-with-dev-and-prod-builds-a4962ce51334
        __dirname: false,
        __filename: false,
    },
    externals: [nodeExternals()],
    module: {
        rules: [{
            test: /\.ts$/,
            use: "ts-loader",
            exclude: /node_modules/,
        }]
    },
    plugins: [
        new NodemonPlugin(),
    ],
    resolve: {
        extensions: [".ts", ".js"]
    },
}];

この状態でyarn webpack -wとします。(※nodemon-webpack-pluginはウォッチモードの時のみ動作してくれます)

91w2XiusLF.gif

yarn webpack -wを実行すると自動でサーバーが起動し、その後ファイルを変更するとサーバーが再起動され、変更が反映されていることを確認できました。


最後まで読んでいただいてありがとうございました。m(_ _)m

okumurakengo
人が作ってくれたご飯食べるときに何も言わずに食べるのは、ちょっとダメらしいという話を聞いたことがあるので、「あ、うめ、あ、うめ」って言いながら食ってたら、すごい変な人と思われてしまってしまった/初心者です、あまりわかっていません
https://bokete.jp/user/okumurakengo
qiitadon
Qiitadon(β)から生まれた Qiita ユーザー・コミュニティです。
https://qiitadon.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away