睡眠とパソコン

このブログに書かれていることは全てフィクションです

はてなブログでテーマを自作しようと思ったらnpm startが動かない問題の解決法

目次



前置き

blog.hatena.ne.jp

はてなブログでは利用するテーマを上記テーマストアの中から選ぶことができますが、気に入るものがない場合、自分でCSSを書いて作成することも可能です。

help.hatenablog.com

テーマを自作する手順は上記『デザインテーマ制作の手引き』にて詳細に説明されていますし、ひな型となるテーマも公開されていますので、比較的簡単に自作できると思われます。

しかし僕の環境では『デザインテーマ制作の手引き』の通りに開発を進めても npm startが機能しない問題に遭遇したので、その解決法を備忘録がてら記事にしておきます。

先に断っておきますと、今回「解決法」と呼んでいるのは「ベンダープレフィックスの自動追加機能をオフにすることで、一旦はエラーが出ないようにした」という付け焼刃的な手法なので、完全な解決法ではありません。先に謝っておきます。



環境

  • OS: Windows 10

調べた範囲では、今回遭遇したのはWindows OS特有の問題らしいです。他のOSでは試していないので言い切る事はできませんが…。



遭遇した問題

ひな型テーマのGitHubリポジトリのREADMEに、テーマを開発する際の手順が詳細にが書かれています。

READMEによりますと、リポジトリ内のpackage.jsonと同じ階層でnpm startコマンドを実行することにより、SCSSファイルの監視と自動コンパイルを行えるらしいです。らしいのですが、僕の環境ではここでエラーが発生しました。

エラー発生時のログは下記のようなものです。

> hatena-blog-theme-boilerplate@2.0.0 prestart 
> npm run build 
> hatena-blog-theme-boilerplate@2.0.0 build C:\Users\frog\Desktop\hatena theme\Hatena-Blog-Theme-Boilerplate 
> npm-run-all scss autoprefixer 
> hatena-blog-theme-boilerplate@2.0.0 scss C:\Users\frog\Desktop\hatena theme\Hatena-Blog-Theme-Boilerplate 
> sass scss/boilerplate.scss build/boilerplate.css --style=expanded --source-map 
> hatena-blog-theme-boilerplate@2.0.0 autoprefixer C:\Users\frog\Desktop\hatena theme\Hatena-Blog-Theme-Boilerplate 
> postcss --use autoprefixer -r build/boilerplate.css 
internal/modules/cjs/loader.js:1149 
      throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath); 
      ^ 
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: C:\Users\frog\Desktop\hatena theme\Hatena-Blog-Theme-Boilerplate\node_modules\postcss-cli\index.js 
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1149:13) 
    at Module.load (internal/modules/cjs/loader.js:977:32) 
    at Function.Module._load (internal/modules/cjs/loader.js:877:14) 
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12) 
    at internal/main/run_main_module.js:18:47 { 
  code: 'ERR_REQUIRE_ESM' 
} 
npm ERR! code ELIFECYCLE 
npm ERR! errno 1 
npm ERR! hatena-blog-theme-boilerplate@2.0.0 autoprefixer: `postcss --use autoprefixer -r build/boilerplate.css` 
npm ERR! Exit status 1 
npm ERR! 
npm ERR! Failed at the hatena-blog-theme-boilerplate@2.0.0 autoprefixer script. 
npm ERR! This is probably not a problem with npm. There is likely additional logging output above. 
npm ERR! A complete log of this run can be found in: 
npm ERR!     C:\Users\frog\AppData\Local\npm-cache\_logs\2022-06-18T10_35_13_933Z-debug.log 
ERROR: "autoprefixer" exited with 1. 
npm ERR! code ELIFECYCLE 
npm ERR! errno 1 
npm ERR! hatena-blog-theme-boilerplate@2.0.0 build: `npm-run-all scss autoprefixer` 
npm ERR! Exit status 1 
npm ERR! 
npm ERR! Failed at the hatena-blog-theme-boilerplate@2.0.0 build script. 
npm ERR! This is probably not a problem with npm. There is likely additional logging output above. 
npm ERR! A complete log of this run can be found in: 
npm ERR!     C:\Users\frog\AppData\Local\npm-cache\_logs\2022-06-18T10_35_13_961Z-debug.log

上から順にログを追うに、sass scss/boilerplate.scss build/boilerplate.css --style=expanded --source-mapコマンドの実行まではうまくいっているのですが、postcss --use autoprefixer -r build/boilerplate.css でエラーが発生しているみたいです。



npm startについて

普段npmコマンドを使わない人のために、npm startって何ぞ? という説明をしておきます。分かっている方は次の見出しまで飛ばして頂いて結構です。

package.jsonが存在する階層でnpm run hogeコマンドを実行すると、package.jsonの中のscriptsに書かれた処理を実行できます。

"scripts": {
    "prestart": "npm run build",
    "start": "npm-run-all -p watch server",
    "build": "npm-run-all scss autoprefixer",
    "scss": "sass scss/boilerplate.scss build/boilerplate.css --style=expanded --source-map",
    "autoprefixer": "postcss --use autoprefixer -r build/boilerplate.css",
    "server": "browser-sync start -c bs-config.js",
    "watch": "chokidar \"scss/\" -c \"npm run build\""
  }

例えばHatena-Blog-Theme-Boilerplate(ひな型テーマ)と一緒に配布されているpackage.jsonの中のscriptsは、上記内容になっています。(version 2.0.0現在)

よって、このpackage.jsonにおいては、npm run startnpm run buildnpm run scssなどが使えます。つまり、複雑な処理に名前をつけ、簡単に呼び出すための機能というわけです。

npm run startは特殊なコマンドで、このコマンドを実行するだけでprestartの処理を実行した後にstartの処理を実行できます。また、npm startnpm run startと同じ動きをします。npm run startはよく使うので、短く書けるnpm startを使うのが普通だと思います。

したがって、上記package.jsonにおいては、npm startコマンドを実行すると、prestartの処理(npm run build)→startの処理(npm-run-all -p watch server)の順で実行されます。

それぞれの処理内容を見てみると、prestartではbuildが、startではwatchとserverが呼び出されていますので、npm startコマンドを実行することで、build→watch→serverの順で処理が実行されます。



エラーを解消する (付け焼刃)

Hatena-Blog-Theme-Boilerplate内のpackage.jsonを確認したうえで、再びエラー発生時のコンソールを見てみます。

> hatena-blog-theme-boilerplate@2.0.0 prestart 
> npm run build 
> hatena-blog-theme-boilerplate@2.0.0 build C:\Users\frog\Desktop\hatena theme\Hatena-Blog-Theme-Boilerplate 
> npm-run-all scss autoprefixer 
> hatena-blog-theme-boilerplate@2.0.0 scss C:\Users\frog\Desktop\hatena theme\Hatena-Blog-Theme-Boilerplate 
> sass scss/boilerplate.scss build/boilerplate.css --style=expanded --source-map 
> hatena-blog-theme-boilerplate@2.0.0 autoprefixer C:\Users\frog\Desktop\hatena theme\Hatena-Blog-Theme-Boilerplate 
> postcss --use autoprefixer -r build/boilerplate.css 
internal/modules/cjs/loader.js:1149 
      throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath); 
      ^ 
...

上から読んでいくと、prestartが実行される→(prestartの中の) buildが実行される→(buildの中の) scssが実行される→ (buildの中の) autoprefixerを実行→エラー となっています。つまり、原因はautoprefixerである事が分かります。

じゃあautoprefixerって何ぞ? と思いググってみると、どうやら自動でベンダープレフィックスをつけてくれるPostCSSのプラグインらしい。まあ個人ブログでベンダープレフィックスを気にしなくても良いか… と思い、autoprefixerを使わないようにする方向で修正を施すことにしました。

ここまで来ればあとは簡単で、autoprefixerを呼び出さないようpackage.jsonを書き換えれば良いだけです。

"scripts": {
    "prestart": "npm run build",
    "start": "npm-run-all -p watch server",
    "build": "npm-run-all scss",
    "scss": "sass scss/boilerplate.scss build/boilerplate.css --style=expanded --source-map",
    "server": "browser-sync start -c bs-config.js",
    "watch": "chokidar \"scss/\" -c \"npm run build\""
  }

例えば上記のように書き換えることで、npm startコマンドを実行してもエラーを吐かず、無事SCSSを使ったテーマ開発を開始できたのでした。(ベンダープレフィックスを捨てたので無事ではない)



何としてでもautoprefixerを使いたい人向け補足

github.com

npmのIssuesにこのエラーに関係するものがありました。autoprefixerを使用する時にオプション -b \"last 10 versions\” をつけると動くらしいのですが、僕の環境ではこのオプションをつけても動きませんでした。

ベンダープレフィックス、あるに越したことはないので、もし同じエラーを解決できた人がいましたらコメント等で教えて頂けると幸いです。