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
を無視して外部関数として扱うようにバンドルしてくれる
- webpackで生成したファイルを、
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
3 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
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"allowJs": true
}
}
あまり詳しくないので、こちらを参考にして、ほぼそのままです(^_^;)
5 簡易チャット作成
5-1 サーバ作成
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 ブラウザ側を作成
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Document</title>
<script src="js/client.js" defer></script>
<form><input><button>Send</button></form>
<ul></ul>
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 実行
yarn webpack #dist/server.jsとpublic/js/client.jsが出力
node dist/server.js #サーバ起動
http://localhost:3000/ を開いてsocket.ioがうまく動いていることを確認できました。
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(),
],
// ..
全体ではこうなりました
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
はウォッチモードの時のみ動作してくれます)
yarn webpack -w
を実行すると自動でサーバーが起動し、その後ファイルを変更するとサーバーが再起動され、変更が反映されていることを確認できました。
最後まで読んでいただいてありがとうございました。m(_ _)m