🛠️

WindowsでZenn CLIが動かないのを解決

に公開

ローカル執筆環境の構築

ZennにはWeb上のエディタで記事作成する方法とは別に、Zenn CLIというツールを使ってGitHubリポジトリと連携させることによりローカルのエディタで作成する方法があります。
Zennで発信し始めるにあたり、Webエディタではなく、使い慣れたローカル環境で執筆・管理したいと考えました。主な理由は以下の2点です。

  1. 記事も資産としてGit管理したい
    アプリのコードと同様に、記事もバージョン管理し、ローカルとGitHubに完全なバックアップを保持したい。またZennがサービス終了したり他のサービスへ移行することになったとしても、記事テキストと画像が手元に残るようにしたい。
  2. 開発ワークフローと統合したい
    普段の開発で使っているVSCode内で執筆から公開まで完結させたい。

当初は普段メモツールとして利用しているObsidianとの連携も目指したものの、技術的な問題(後述)により一部断念。最終的にVSCode (WSL接続) + Git + Zenn CLI を中心とした、執筆ワークフローを構築できたので、そこまでに至る試行錯誤の経緯をまとめます。

Step 0: GitHubリポジトリの準備

Zenn CLIを使うには、まず記事を管理するためのGitHubリポジトリが必要です。今回はソロプレナーとしての活動用のOrganizationを作成し、以下の構成にしました。

  1. GitHub Organizationの作成

    • take-lab-dev というOrganizationを作成
  2. Privateリポジトリの作成

    • 作成した take-lab-dev Organization内に、zenn-contents という名前でPrivateリポジトリを作成。
    • Privateにした理由は、将来的にZennで有料記事を販売する可能性を考慮したため。Publicリポジトリにしてしまうと、有料記事のMarkdown原文が誰でも読めてしまうので。公開するような範囲はZennの記事で見れるのでPublicにする必要はないかと。

これでGitHub側の準備は完了。次はZenn CLIのセットアップです。

Step 1: Windows + Node.jsでのinit失敗

まずは公式からでているZenn CLIをインストールするに従い、PowerShell で作業を開始。当時の私の環境は Node.js v22.17.0 でした。

# GitHubからリポジトリをクローン (Google Driveの外に)
git clone https://github.com/take-lab-dev/zenn-contents.git
cd zenn-contents

Zenn CLIの初期化コマンドを実行すると、いきなり以下のエラーが発生。

> npx zenn-cli init
Need to install the following packages:
zenn-cli@0.2.8
Ok to proceed? (y) y

node:internal/url:1479
    throw new ERR_INVALID_FILE_URL_PATH('must be absolute');
    ^

TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must be absolute
    at getPathFromURLWin32 (node:internal/url:1479:11)
    at fileURLToPath (node:internal/url:1510:35)
    at C:\Users\xxxx\AppData\Local\npm-cache\_npx\213677bf7f5a4f63\node_modules\zenn-cli\dist\server\zenn.js:272:1660
    at C:\Users\xxxx\AppData\Local\npm-cache\_npx\213677bf7f5a4f63\node_modules\zenn-cli\dist\server\zenn.js:293:2027
    at Object.<anonymous> (C:\Users\xxxx\AppData\Local\npm-cache\_npx\213677bf7f5a4f63\node_modules\zenn-cli\dist\server\zenn.js:293:2031)
    at Module._compile (node:internal/modules/cjs/loader:1730:14)
    at Object..js (node:internal/modules/cjs/loader:1895:10)
    at Module.load (node:internal/modules/cjs/loader:1465:32)
    at Function._load (node:internal/modules/cjs/loader:1282:12)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14) {
  code: 'ERR_INVALID_FILE_URL_PATH'
}

Node.js v22.17.0

initコマンドは、articlesbooksといったフォルダを作るだけの単純なはずなのに。。。

Step 2: Node.jsバージョン比較

エラーメッセージではPATHがおかしいとしか書かれていないため原因が特定できず、まず疑ったのはNode.jsのバージョンでした。バグによる特定バージョンと互換性問題がある可能性を疑い、Node Version Manager (nvm-windows) を導入し、バージョンを切り替えながら試しました。

  • Node.js v22.21.0 (LTS最新版)
> rm -r .\node_modules\
> rm .\package-lock.json
> nvm use lts
Now using node v22.21.0 (64-bit)
> npm install zenn-cli
added 1 package, and audited 2 packages in 1s

found 0 vulnerabilities

> npx zenn-cli init
node:internal/url:1489
    throw new ERR_INVALID_FILE_URL_PATH('must be absolute', url);
    ^

TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must be absolute
    at getPathFromURLWin32 (node:internal/url:1489:11)
    at fileURLToPath (node:internal/url:1613:35)
    at C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:272:1660
    at C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:293:2027
    at Object.<anonymous> (C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:293:2031)
    at Module._compile (node:internal/modules/cjs/loader:1706:14)
    at Object..js (node:internal/modules/cjs/loader:1839:10)
    at Module.load (node:internal/modules/cjs/loader:1441:32)
    at Function._load (node:internal/modules/cjs/loader:1263:12)
    at TracingChannel.traceSync (node:diagnostics_channel:328:14) {
  code: 'ERR_INVALID_FILE_URL_PATH',
  input: file:///home/runner/work/zenn-editor/zenn-editor/node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
}

Node.js v22.21.0
  • Node.js v20.19.5
    ※zenn-cli@0.2.8を使うならNode.jsはv22以上を使えと怒られている
> rm .\package-lock.json
> rm -r .\node_modules\ 
> nvm use 20            
Now using node v20.19.5 (64-bit)
> npm install zenn-cli  
npm warn EBADENGINE Unsupported engine {
npm warn EBADENGINE   package: 'zenn-cli@0.2.8',
npm warn EBADENGINE   required: { node: '>=22.0.0' },
npm warn EBADENGINE   current: { node: 'v20.19.5', npm: '10.8.2' }
npm warn EBADENGINE }
added 1 package, and audited 2 packages in 658ms

found 0 vulnerabilities

> npx zenn-cli init     
node:internal/url:1459
    throw new ERR_INVALID_FILE_URL_PATH('must be absolute');
    ^

TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must be absolute
    at getPathFromURLWin32 (node:internal/url:1459:11)
    at fileURLToPath (node:internal/url:1490:35)
    at C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:272:1660
    at C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:293:2027
    at Object.<anonymous> (C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:293:2031)
    at Module._compile (node:internal/modules/cjs/loader:1521:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1623:10)
    at Module.load (node:internal/modules/cjs/loader:1266:32)
    at Module._load (node:internal/modules/cjs/loader:1091:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12) {
  code: 'ERR_INVALID_FILE_URL_PATH'
}

Node.js v20.19.5
  • Node.js v25.0.0
    ※v24の最新版にするつもりが、latestで指定したらv25だった
> rm .\package-lock.json
> rm -r .\node_modules\ 
> nvm install latest    
25.0.0
Downloading node.js version 25.0.0 (64-bit)... 
Extracting node and npm...
Complete
Installation complete.
If you want to use this version, type:

> nvm use 25
Now using node v25.0.0 (64-bit)

> npm install zenn-cli  
added 1 package, and audited 2 packages in 590ms

found 0 vulnerabilities

> npx zenn-cli init     
node:internal/url:1490
    throw new ERR_INVALID_FILE_URL_PATH('must be absolute', url);
    ^

TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must be absolute
    at getPathFromURLWin32 (node:internal/url:1490:11)
    at fileURLToPath (node:internal/url:1614:35)
    at C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:272:1660
    at C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:293:2027
    at Object.<anonymous> (C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:293:2031)
    at Module._compile (node:internal/modules/cjs/loader:1759:14)
    at Object..js (node:internal/modules/cjs/loader:1892:10)
    at Module.load (node:internal/modules/cjs/loader:1479:32)
    at Module._load (node:internal/modules/cjs/loader:1298:12)
    at TracingChannel.traceSync (node:diagnostics_channel:328:14) {
  code: 'ERR_INVALID_FILE_URL_PATH',
  input: file:///home/runner/work/zenn-editor/zenn-editor/node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
}

Node.js v25.0.0
  • Node.js v24.10.0
> nvm install 24    
Downloading node.js version 24.10.0 (64-bit)... 
Extracting node and npm...
Complete
Installation complete.
If you want to use this version, type:
nvm use 24.10.0
> nvm use 24
Now using node v24.10.0 (64-bit)

> npm install zenn-cli
added 1 package, and audited 2 packages in 669ms

found 0 vulnerabilities

> npx zenn-cli init     
node:internal/url:1490
    throw new ERR_INVALID_FILE_URL_PATH('must be absolute', url);
    ^

TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must be absolute
    at getPathFromURLWin32 (node:internal/url:1490:11)
    at fileURLToPath (node:internal/url:1614:35)
    at C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:272:1660
    at C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:293:2027
    at Object.<anonymous> (C:\zenn-contents\node_modules\zenn-cli\dist\server\zenn.js:293:2031)
    at Module._compile (node:internal/modules/cjs/loader:1760:14)
    at Object..js (node:internal/modules/cjs/loader:1893:10)
    at Module.load (node:internal/modules/cjs/loader:1480:32)
    at Module._load (node:internal/modules/cjs/loader:1299:12)
    at TracingChannel.traceSync (node:diagnostics_channel:328:14) {
  code: 'ERR_INVALID_FILE_URL_PATH',
  input: file:///home/runner/work/zenn-editor/zenn-editor/node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
}

Node.js v24.10.0

Node.js v20, v22, v24, v25npx zenn-cli initは同じERR_INVALID_FILE_URL_PATHエラーで失敗。
この時点で、Node.jsのバージョンが直接の原因ではないと判断しました。
Zenn CLIも古いのを試すというのも考えられるが、キリがなく、今後もその古いバージョンを固定して使い続けるというのは嫌だったので試さず。

Step 3: エラーログの中のLinuxパス

エラーログをよく見返すと、よくわからないものを発見(v22.21.0, v24, v25で失敗した際のログ)。

code: 'ERR_INVALID_FILE_URL_PATH',
input: file:///home/runner/work/zenn-editor/zenn-editor/node_modules/.pnpm/open@10.2.0/node_modules/open/index.js

input: file:///home/runner/work... これはLinuxのファイルパスです。私はWindowsで作業しています。

zenn-cli またはその依存パッケージ(エラーログを見ると open というパッケージのよう)が開発・ビルドされた環境(おそらくGitHub ActionsのようなCI/CD環境)の絶対パスが、何らかの理由でパッケージのコード内にハードコード(埋め込み)されてしまっている可能性があり、Windows環境を正しく考慮していない形でLinuxのパスを参照しようとしてエラーになっているのではないか?という仮説に至りました。

Step 4: 【解決策】WSL (Windows Subsystem for Linux) の導入

もし原因がWindowsのパス処理の問題なら、zenn-cliが期待するであろうLinux環境で動かせば解決するはずです。そこで、WSL 2 (Ubuntu) を導入することにしました。

1. WSLのインストール
管理者権限でPowerShellを開き、wsl --installを実行。PC再起動後、Ubuntuのユーザー名とパスワードを設定。

2. VSCode - WSL 拡張機能
VSCodeにMicrosoft公式の「WSL」拡張機能をインストールし、VSCodeをWSL環境に接続。これでVSCodeのターミナルがUbuntuになりました。

Step 5: WSL環境での再挑戦

WSLのLinux環境を手に入れたので、VSCodeのターミナルを立ち上げ、再度zenn-cliのセットアップに挑戦しました。

1. Node.js LTS (v22) のインストール (WSL内)

# nvmのインストール (初回のみ)
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

# ターミナル再起動
$ nvm install --lts # 最新LTS(v22)をインストール
$ nvm use --lts
$ node -v
v22.21.0

2. Zennリポジトリの準備 (WSL内)

$ cd ~  # ホームディレクトリへ移動
$ git clone https://github.com/take-lab-dev/zenn-contents.git
$ cd zenn-contents
$ npm install zenn-cli  # ローカルにzenn-cliをインストール
added 1 package in 2s

3. 運命の init コマンド (WSL内)
ここまでは順調。ここで失敗しなければ・・・

$ npx zenn-cli init

🎉  Done!
  早速コンテンツを作成しましょう

👇  新しい記事を作成する
$ npx zenn new:article

👇  新しい本を作成する
$ npx zenn new:book

👇  投稿をプレビューする
$ npx zenn preview

Done! やはりWindowsのパス処理が原因だったようです。

ちなみにWSL環境のディレクトリをWindowsのエクスプローラで開くのは

\\wsl$

または

`\\wsl.localhost\Ubuntu`

をアドレスバーでたたけばよい。

番外:Obsidian連携の検討

当初の目標だったObsidian連携も試みました。

既存Vaultの活用

普段使っているObsidianのVaultはGoogle Drive上に構築しています。ここにGitHubで連携するGit環境を構築してZenn記事投稿システムは構築できるのかをはじめに検討していました。

結論として、GitやGoogle Driveがそれぞれ同期するのにロックしたりすると、同期が失敗したり、ゴーストファイルが出来たり、最悪ファイルが壊れたりしないかということを懸念して断念。どちらにせよ、上記のWindowsパスの問題もあり難しかったかと。

新規Vaultをローカルドライブ上に作成

Windows版Obsidianから \\wsl$ パスを使ってWSL上の zenn-contents フォルダをVaultとして開こうとしてみると、ロード中にエラーが発生し開けない。

Error: EISDIR: illegal operation on a directory, watch '¥¥wsl.localhost¥Ubuntu¥home¥・・・

EISDIR: 「それはファイルではなく、ディレクトリ(フォルダ)」というエラー。

illegal operation on a directory, watch: Obsidianが「zenn-contents」フォルダ内の変更を監視(watch)しようとしたところ、「フォルダ全体を監視する」という操作が(WindowsとLinuxの境界をまたぐせいで)不正な操作だと判断され、失敗した様子。

WSL上にObsidianをインストールする方法もあるようですが、そこまで複雑にする必要はないと判断し、Obsidianはアイデア出し・下書き専用、外部にアウトプットするための清書以降はVSCode (WSL接続) で行うというワークフローに落ち着きました。

まとめ:WindowsでのNode.jsツール利用とWSL

今回の経験から学んだことは以下の通りです。

  • GitHub準備は簡単: Organization作成、Privateリポジトリ作成は特に問題ない。
  • Windows固有の問題: 特にファイルパスの扱いは、Linux前提で作られたツールで問題を起こしやすい。
  • WSLの有効性: WSLは、このようなWindows固有の問題を回避し、Linuxツールを安定して動作させるための強力なソリューションとなる。
  • エラーログの重要性: 最初に試したバージョンでは出ずに違うバージョンで現れた input: file:///home/runner/... のような小さな情報が、原因究明の大きな手がかりになった。
  • ObsidianとWSL: Windows版ObsidianからWSL Vaultを直接開くことはできなさそう。

Windows環境でNode.js系のCLIツールが原因不明のエラーで動かない場合、GitHub等の準備はそのままに、WSL環境での実行を試してみる価値は非常に高そうです。


次回は、このWSL環境をベースに構築した、VSCode+Gitによる具体的なZenn執筆ワークフローについてまとめます。 → Zenn執筆環境をVSCode(WSL)+Gitで構築

Discussion