Skip to content

Commit

Permalink
fix: node:fsに統一
Browse files Browse the repository at this point in the history
  • Loading branch information
azu committed Jul 21, 2024
1 parent 1afe34e commit 75211ce
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 30 deletions.
8 changes: 4 additions & 4 deletions source/use-case/nodecli/argument-parse/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,13 @@ $ node main.js one two=three four
また、文字列の配列として渡されるため、フラグのオンオフのような真偽値を受け取るときにも不便です。
そのため、アプリケーションでコマンドライン引数を扱うときには、一度パースして扱いやすい値に整形するのが一般的です。

今回は、Node.jsの標準モジュールである`node:util`モジュールの[parseArgs][]という関数を使ってコマンドライン引数をパースしてみましょう。
今回は、Node.jsの標準モジュールである[`node:util`モジュール][][parseArgs][]という関数を使ってコマンドライン引数をパースしてみましょう。
文字列処理を自前で行うこともできますが、このような一般的な処理はNode.jsの標準モジュールやサードパーティ製のライブラリを使うことで簡単に実装できます。

### ECMAScriptモジュールを使う {#esmodule}

今回のユースケースでは、`node:util`モジュールを利用するにあたって、基本文法で学んだ[ECMAScriptモジュール][]を使います。
`node:util`モジュールは、次のように`import`文を使ってインポートできます。

<!-- doctest:disable -->
```js
// `node:util`モジュールを、utilオブジェクトとしてインポートする
Expand Down Expand Up @@ -109,14 +108,14 @@ import { key } from "./lib.cjs";

### コマンドライン引数からファイルパスを取得する {#get-file-path}

`node:util`パッケージを使って、コマンドライン引数として渡されたファイルパスを取得しましょう。
`node:util`モジュールを使って、コマンドライン引数として渡されたファイルパスを取得しましょう。
このCLIアプリケーションでは、処理の対象とするファイルパスを次のようなコマンドの形式で受け取ります。

```shell
$ node main.js ./sample.md
```

コマンドライン引数をパースするためには、`node:util`パッケージの`parseArgs`関数を利用します。
コマンドライン引数をパースするためには、`node:util`モジュールの`parseArgs`関数を利用します。

<!-- doctest:disable -->
```js
Expand Down Expand Up @@ -183,6 +182,7 @@ SyntaxError: Cannot use import statement outside a module
[Node.js]: https://nodejs.org/
[アプリケーション開発の準備]: ../../setup-local-env/README.md
[ECMAScriptモジュール]: ../../../basic/module/README.md
[`node:util`モジュール]: https://nodejs.org/api/util.html
[parseArgs]: https://nodejs.org/api/util.html#utilparseargsconfig
[Node.jsプロジェクトのセットアップ]: ../helloworld/README.md#setup-nodejs-project
[^1]: [package.json and file extensions](https://nodejs.org/api/packages.html#packagejson-and-file-extensions)
Expand Down
49 changes: 23 additions & 26 deletions source/use-case/nodecli/read-file/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
author: laco
description: "Node.jsの`fs`モジュールを使ったファイルの読み込みについて学びます。"
description: "Node.jsの`node:fs`モジュールを使ったファイルの読み込みについて学びます。"
sponsors: []
---

Expand All @@ -9,47 +9,44 @@ sponsors: []
前のセクションではコマンドライン引数からファイルパスを取得して利用できるようになりました。
このセクションでは渡されたファイルパスを元にMarkdownファイルを読み込んで、標準出力に表示してみましょう。

## `fs`モジュールを使ってファイルを読み込む {#read-file-by-fs}
## `node:fs`モジュールを使ってファイルを読み込む {#read-file-by-fs}

前のセクションで取得できるようになったファイルパスを元に、ファイルを読み込みましょう。
Node.jsでファイルの読み書きを行うには、標準モジュールの[`fs`モジュール][]を使います。
Node.jsでファイルの読み書きを行うには、標準モジュールの[`node:fs`モジュール][]を使います。
まずは読み込む対象のファイルを作成しましょう。`sample.md`という名前で`main.js`と同じ`nodecli`ディレクトリに配置します。

[import title:"sample.md"](src/sample.md)

### `fs`モジュール {#fs-module}
### `node:fs`モジュール {#fs-module}

`fs`モジュールは、Node.jsでファイルの読み書きを行うための基本的な関数を提供するモジュールです。
`node:fs`モジュールは、Node.jsでファイルの読み書きを行うための基本的な関数を提供するモジュールです。

`fs`モジュールは同期形式と非同期形式の両方が提供されています。
同期APIと非同期APIはどちらも`fs`モジュールに含まれていますが、
非同期形式のAPIは`fs/promises`というモジュール名でも参照できるようになっています。
この書籍では分かりやすさのために、非同期形式のみのAPIを提供する`fs/promises`モジュールを利用します。
`node:fs`モジュールは同期形式と非同期形式の両方が提供されています。
同期APIと非同期APIはどちらも`node:fs`モジュールに含まれていますが、
非同期形式のAPIは`node:fs/promises`というモジュール名でも参照できるようになっています。
この書籍では分かりやすさのために、非同期形式のみのAPIを提供する`node:fs/promises`モジュールを利用します。

Node.jsの標準モジュールは`node:fs`のように`node:`プリフィックスをつけてインポートできます。
プリフィックスを付けない`fs`でもインポートできますが、npmからインストールしたサードパーティ製のモジュールとの区別が明確になるため、付けておくことが推奨されます。

次のコードは、ECMAScriptモジュールの`import * as`構文を使って、`fs/promises` モジュール全体を`fs`オブジェクトとしてインポートしています。
次のコードは、ECMAScriptモジュールの`import * as`構文を使って、`node:fs/promises` モジュール全体を`node:fs`オブジェクトとしてインポートしています。

<!-- doctest:disable -->
```js
// fs/promisesモジュール全体を読み込む
import * as fs from "node:fs/promises";
```

もちろん、次のように名前付きインポートを使って、`fs/promises`モジュール全体ではなく一部のAPIだけを利用することもできます。
もちろん、次のように名前付きインポートを使って、`node:fs/promises`モジュール全体ではなく一部のAPIだけを利用することもできます。

<!-- doctest:disable -->
```js
// fs/promisesモジュールからreadFile関数を読み込む
import { readFile } from "node:fs/promises";
```

`fs/promises`の非同期APIは、モジュール名からもわかるようにPromiseを返します。
`node:fs/promises`の非同期APIは、モジュール名からもわかるようにPromiseを返します。
ファイルの読み書きといった非同期処理が成功したときには、返された`Promise`インスタンスがresolveされます。
一方、ファイルの読み書きといった非同期処理が失敗したときには、返された`Promise`インスタンスがrejectされます。

次のサンプルコードは、指定したファイルを読み込む`fs/promises``readFile`メソッドの例です。
次のサンプルコードは、指定したファイルを読み込む`node:fs/promises``readFile`メソッドの例です。

<!-- doctest:disable -->
```js
Expand All @@ -63,7 +60,7 @@ fs.readFile("sample.md").then(file => {
});
```

そして、次のサンプルコードは、同じく指定したファイルを読み込む`fs`モジュールの`readFileSync`メソッドの例です。
そして、次のサンプルコードは、同じく指定したファイルを読み込む`node:fs`モジュールの`readFileSync`メソッドの例です。
Node.jsでは非同期APIと同期APIがどちらもあるAPIには、分かりやすく`Sync`がメソッド名の末尾に含まれています。

<!-- doctest:disable -->
Expand All @@ -79,11 +76,11 @@ try {
```

Node.jsはシングルスレッドなので、他の処理をブロックしにくい非同期形式のAPIを選ぶことがほとんどです。
Node.jsには`fs/promises`モジュール以外にも多くの非同期APIがあるので、非同期処理に慣れておきましょう。
Node.jsには`node:fs/promises`モジュール以外にも多くの非同期APIがあるので、非同期処理に慣れておきましょう。

### readFile関数を使う {#use-readFile}

それでは`fs/promises`モジュールの`readFile`メソッドを使って`sample.md`ファイルを読み込んでみましょう。
それでは`node:fs/promises`モジュールの`readFile`メソッドを使って`sample.md`ファイルを読み込んでみましょう。
次のように`main.js`を変更し、コマンドライン引数から取得したファイルパスを元にファイルを読み込んでコンソールに出力します。

[import title:"main.js"](src/main-1.js)
Expand Down Expand Up @@ -134,11 +131,11 @@ ENOENT: no such file or directory, open 'notfound.md'

## [コラム] Node.jsのエラーファーストコールバック {#node-error-first-callbak}

Node.jsが提供する`fs`モジュールは同期APIと非同期APIを提供するという話を紹介しました。
Node.jsが提供する`node:fs`モジュールは同期APIと非同期APIを提供するという話を紹介しました。
歴史的な経緯もあり、Node.jsではPromiseとエラーファーストコールバックの2種類の非同期APIを提供しているケースもあります。

`fs/promises`モジュールでは、`readFile`メソッドは、Promiseを返す非同期APIでした。
一方で、`fs`モジュールにも`readFile`メソッドがあり、このAPIはエラーファーストコールバックを扱う非同期APIです。
`node:fs/promises`モジュールでは、`readFile`メソッドは、Promiseを返す非同期APIでした。
一方で、`node:fs`モジュールにも`readFile`メソッドがあり、このAPIはエラーファーストコールバックを扱う非同期APIです。

<!-- doctest:disable -->
```js
Expand All @@ -159,10 +156,10 @@ fs.readFile("sample.md", (err, file) => {

[エラーファーストコールバック][]については、[非同期][]の章でも紹介しています。
エラーファーストコールバックは、PromisesがECMAScriptに入るES2015より前においては、非同期な処理を扱う方法として広く使われていました。
Node.jsの多くのモジュールは、ES2015より前に作られているため、`fs`モジュールのようにエラーファーストコールバックを扱うAPIもあります。
Node.jsの多くのモジュールは、ES2015より前に作られているため、`node:fs`モジュールのようにエラーファーストコールバックを扱うAPIもあります。

一方で、Promiseが非同期APIの主流となったため、Node.jsにもPromiseを扱うためのAPIが追加されました。
しかし、すでにエラーファーストコールバックを提供する同じ名前のメソッドがあったため、`fs`に対して`fs/promises`のようにモジュールとして分けて扱えるようになっています。
しかし、すでにエラーファーストコールバックを提供する同じ名前のメソッドがあったため、`node:fs`に対して`node:fs/promises`のようにモジュールとして分けて扱えるようになっています。
また、Node.jsではエラーファーストコールバックを受け取る非同期APIをPromiseを返す非同期APIへとラップする`util.promisify`というメソッドも提供しています。

Node.jsでは、歴史的な経緯からエラーファーストコールバックとPromiseのAPIがどちらも提供されていることがあります。
Expand All @@ -171,11 +168,11 @@ Promiseを扱うAPIには、他のPromiseを扱う処理との連携のしやす

## このセクションのチェックリスト {#section-checklist}

- `fs/promises`モジュールの`readFile`関数を使ってファイルを読み込んだ
- `node:fs/promises`モジュールの`readFile`関数を使ってファイルを読み込んだ
- UTF-8形式のファイルの中身をコンソールに出力した
- `readFile`関数の呼び出しにエラーハンドリング処理を記述した

[`fs`モジュール]: https://nodejs.org/api/fs.html
[`node:fs`モジュール]: https://nodejs.org/api/fs.html
[Buffer]: https://nodejs.org/api/buffer.html
[promisify]: https://nodejs.org/api/util.html#utilpromisifyoriginal
[非同期]: ../../../basic/async/README.md
Expand Down

0 comments on commit 75211ce

Please # to comment.