Node.jsとは何か ─ ブラウザとの決定的な違い
そもそも Node.js は何者?
一言でいうと「ブラウザの外で JavaScript を動かすための実行環境(ランタイム)」です。
- 中身は主に
- Google Chrome と同じ V8 JavaScriptエンジン
- 非同期I/Oまわりなどを提供する libuv などのネイティブライブラリ
- これをまとめて、OS上で
- ファイル操作
- ネットワーク通信
- プロセス管理
などができるようにしたものが Node.js です。
よく使われる用途:
- Web API サーバ(REST / GraphQL など)
- CLIツール(ビルドツール、コード整形、Lint、スクリプト)
- バッチ処理、スクリプト自動化
- 開発用ツール(Webpack, Vite, ESLint…など、ほとんど Node 製)
ブラウザとの環境差分
同じ JavaScript でも 環境(ホスト)が違うと、使える API が変わります。
ブラウザにあって Node にないもの(代表例)
window/document/navigatorなど- DOM操作(
document.querySelectorなど) alert,confirm,prompt<canvas>/ WebGL, Geolocation(※一部Node向けライブラリはあるが別物)
→ Node.js には DOM がないので、
「画面を直接いじる」「ボタンがクリックされたら…」といった処理はできません。
Node にあって ブラウザにないもの(代表例)
- ファイルシステム:
fsモジュール - ネットワークソケット:
net,http,httpsなど - プロセス情報:
process(環境変数、引数、終了コード…) - OS情報:
osモジュール(CPU数、メモリ量 など) - パス操作:
pathモジュール
→ サーバ側・CLI側の処理は Node のお仕事 というイメージです。
どちらも「イベントループ+非同期I/O」で動く
ブラウザのJSは
- シングルスレッド
- イベントループ+タスクキュー+マイクロタスクキュー
で動いていました。
Node.js も基本は同じ考え方で、
- メインスレッド上で JS を実行
- ネットワークやファイルI/Oは libuv のスレッドプールで非同期にやってもらう
- 完了したらイベントループ経由でコールバックや Promise を実行
という構造です。
なので「非同期処理の書き方(Promise / async/await)はブラウザと同じ」で、
対象API(DOMかfsか)が違うだけ、と捉えると理解しやすいです。
Node.jsのグローバルオブジェクト
global と globalThis
ブラウザでは「グローバルオブジェクト」は通常 window でしたが、
Node.js では global がそれに相当します。
// Node.js 環境で
console.log(global);ただし、最近の標準仕様では 環境を問わない「共通のグローバル」 としてglobalThis が導入されました。
- ブラウザ:
window === globalThisが基本 - Node.js:
global === globalThis
→ 「どの環境でも動くコード」を書くなら globalThis を使うのが綺麗です。
globalThis.foo = 123;
console.log(globalThis.foo); // 123
console.log(global.foo); // Nodeでは同じものを参照※ ただし「グローバルに何でも作成する」のは設計上あまり良くないので、
実務的にはモジュールスコープを大事にするのがよいです。
process オブジェクト ─ Nodeの「実行プロセス」情報
process は Node に特有の 「いま動いているプロセス」の情報や操作 をまとめたオブジェクトです。
代表的なプロパティ・メソッド:
process.argv(コマンドライン引数)
node script.js foo bar// script.js
console.log(process.argv);たとえば上のように実行すると、出力はイメージとして:
[
"/usr/local/bin/node", // Node実行ファイル
"/path/to/script.js", // 実行中スクリプトのパス
"foo",
"bar"
]process.argv[2]以降が、ユーザが渡した引数- CLIツールを作るときの基本となる情報です
process.env(環境変数)
MY_NAME=COCCO node script.js// script.js
console.log(process.env.MY_NAME); // "COCCO"- APIキーや接続先URLなど機密性のある情報を「コードに直書きせず」環境変数で渡すのが一般的
process.env.NODE_ENV === "production"かどうかで挙動を変えたりもよくあります
process.cwd()(カレントディレクトリ)
console.log(process.cwd()); // 現在の作業ディレクトリ(カレントディレクトリ)- ファイルパスを相対パスで扱いたい時に基準として使ったりします
process.exit([code])(プロセス終了)
console.log("処理中...");
if (何か致命的なエラー条件) {
console.error("致命的エラー");
process.exit(1); // エラー終了コードで終了
}
console.log("ここには到達しない");0:正常終了0以外:異常終了(慣習的に1が多い)
CLIツールでは終了コードによって「成功 / 失敗」を他のプロセスに知らせます。
5. process.stdout / process.stderr
process.stdout.write("標準出力に書く\n");
process.stderr.write("エラー出力に書く\n");console.logは内部的にstdoutを使っているイメージ- ログとエラーの出力先を明確に分けたい場面で直接使うこともあります
Node.jsでの簡単なCLIスクリプト例
Hello, CLI
- 適当なフォルダで
hello.jsを作る:console.log("Hello from Node.js!"); - ターミナルで:
node hello.js
→ コンソールに Hello from Node.js! と表示されます。
ポイント:
- これは「ブラウザのコンソール」ではなく、OSのターミナルに出ている
- JSコードは同じでも、「どこに何を出しているのか」がブラウザと違う
引数を取るスクリプト
greet.js:
// greet.js
const args = process.argv.slice(2); // 2つ飛ばしてユーザ引数だけ取得
const name = args[0] ?? "World";
console.log(`Hello, ${name}!`);実行例:
node greet.js
# => Hello, World!
node greet.js COCCO
# => Hello, COCCO!process.argvをslice(2)して、["COCCO"]のようにして扱うのが定番??(Null合体演算子)は「未指定ならデフォルト」を書くのにちょうど良い
簡単なオプション解析
実務では yargs, commander などのライブラリを使うことが多いですが、
仕組み自体は単純です。
// cli.js
const args = process.argv.slice(2);
// 例: ["--name", "COCCO", "--debug"]
let name = "World";
let debug = false;
for (let i = 0; i < args.length; i++) {
if (args[i] === "--name") {
name = args[i + 1];
i++;
} else if (args[i] === "--debug") {
debug = true;
}
}
if (debug) {
console.log("Debug mode ON");
}
console.log(`Hello, ${name}!`);node cli.js --name COCCO --debug
# => Debug mode ON
# => Hello, COCCO!「Node.jsでCLIが作れる」という感覚がここで一気に掴めるはずです。
簡単な標準入力の読み取り
// echo.js
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => {
console.log("あなたが入力したのは:", chunk.trim());
});node echo.js
# ここで文字を打って Enter すると、そのまま返ってくるstdinにdataイベントリスナを付けて、入力が来たら処理する- ブラウザの
addEventListenerとは「対象とイベント名」が違うだけで、
発想としてはかなり近いのが分かると思います。
Node.js とモジュール
古くからの CommonJS(require / module.exports)
従来、Node 独自のモジュールシステムは CommonJS でした:
// add.js
function add(a, b) {
return a + b;
}
module.exports = { add };// main.js
const { add } = require("./add");
console.log(add(1, 2));近年の ES Modules(import / export)
最近の Node では、ブラウザと同じ ES Modules (ESM) も使えます。
package.jsonに"type": "module"を書く- ファイル拡張子を
.mjsにする など、いくつかのルールあり
// add.mjs
export function add(a, b) {
return a + b;
}// main.mjs
import { add } from "./add.mjs";
console.log(add(1, 2));ここを掘り下げると長くなるので、
「Nodeには歴史的に CommonJS があり、今はESMも使える」 くらいの認識でOKです。
(実務で触るときに、プロジェクト設定に合わせて import / require を選ぶ、という流れになります)
コメント