発生した不具合
最初に、qiita.com を参考にして、
$ mkdir -p sample
$ cd sample
$ yo chrome-extension-kickstart-typescript
$ npm install --save-dev typescript
$ npm install --save-dev gulp@3.9.0
$ npm run dev:chrome
のようにしたところ、
$ npm run dev:chrome
> sample@0.0.0 dev:chrome D:\webext\sample
> gulp --watch --vendor=chrome
[08:33:12] Requiring external module babel-core/register
fs.js:27
const { Math, Object } = primordials;
^
ReferenceError: primordials is not defined
at fs.js:27:26
at req_ (D:\webext\sample\node_modules\natives\index.js:143:24)
at Object.req [as require] (D:\webext\sample\node_modules\natives\index.js:55:10)
at Object.<anonymous> (D:\webext\sample\node_modules\vinyl-fs\node_modules\graceful-fs\fs.js:1:37)
at Module._compile (internal/modules/cjs/loader.js:955:30)
at Module._extensions..js (internal/modules/cjs/loader.js:991:10)
at Object.require.extensions.<computed> [as .js] (D:\webext\sample\node_modules\babel-register\lib\node.js:152:7)
at Module.load (internal/modules/cjs/loader.js:811:32)
at Function.Module._load (internal/modules/cjs/loader.js:723:14)
at Module.require (internal/modules/cjs/loader.js:848:19)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! sample@0.0.0 dev:chrome: `gulp --watch --vendor=chrome`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the sample@0.0.0 dev:chrome 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\testuser\AppData\Roaming\npm-cache\_logs\2020-01-11T06_33_12_337Z-debug.log
調査
Node.js v12 と gulp.js 3 は相性が悪いらしい?!
とりあえず
「ReferenceError: primordials is not defined」で検索してみると、
stackoverflow.com
に行き当たる。
こちらの回答によると、
- gulp.js を version 4 にする
- Node.js のバージョンを v12 未満へ下げる
のいずれかで対応できるらしい。
1. の gulp.js のバージョンを変える方は、3→4 の変更に対応してソースコードも変更が必要になると思われるので手間がかかりそうだったため、2. の方法を試してみる。
nvm-windows で Node.js のバージョンを 10.18.1 LTS にしてみると、確かに動作するようになった。
Node.js v12 & gulp.js 3 のまま使いたいな……
できれば Node.js や gulp.js のバージョンを変えずに使う方法はないか、と調べていると、
https://timonweb.com/posts/how-to-fix-referenceerror-primordials-is-not-defined-error/timonweb.com
に行き当たる。
要は、gulp.js が利用している graceful-fs のバージョンが古いのが悪いらしい。
$ npm list graceful-fs
で調べてみると、他はほとんどが "graceful-fs@4.2.3" を使っているのに対し、gulp(及び
gulp が依存しているパッケージ)については
+-- gulp@3.9.0
| `-- vinyl-fs@0.3.14
| +-- glob-watcher@0.0.6
| | `-- gaze@0.5.2
| | `-- globule@0.1.0
| | `-- glob@3.1.21
| | `-- graceful-fs@1.2.3
| `-- graceful-fs@3.0.12
のように、確かに古いバージョン("graceful-fs@1.2.3"、"graceful-fs@3.0.12")を使っている。
そういえば、yo chrome-extension-kickstart-typescript 実行時にも
npm WARN deprecated graceful-fs@1.2.3: please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js
のような警告が出ていた。これによれば、graceful-fs 4 以降を使うようにすれば良さげ。
上記の記事を参考に、npm-shrinkwrap.json を
{
"dependencies": {
"graceful-fs": {
"version": "^4.x.x"
}
}
}
の内容で作成した後、改めて npm install 後に npm run dev:chrome をすると、
$ rm package-lock.json
$ npm install
$ npm run dev:chrome
すると、今度はエラーになると起動することができた。
ただし、この方法だと、
- npm install --save-dev でパッケージを入れたりすると、最初に指定した "dependencies" が維持されないため、再度 npm-shrinkwrap.json を上記内容に書き換えた上で npm install を実行しなおす必要がある
ということで、やや保守性に欠ける。
特定のパッケージが依存関係にあるパッケージだけバージョンを指定したい
要望としては
- gulp が依存している graceful-fs のみ、バージョンを指定したい
- メンテナンスは最小限(意識するのは初回のみ)としたい(パッケージの追加時等に影響無いようにしたい)
となる。
調べてみると npm の代わりに Yarn を使用し、『選択的な依存関係の解決(Selective dependency resolutions)』機能を使えばできそう(package.json に "resolutions" フィールドを追加)。
"resolutions": {
"gulp/**/graceful-fs": "^4.x.x"
}
この方針で調整したのが、こちらの手順になる。
参考:npm で Yarn の "resolutions" っぽいことはできないか?
一応、npm 用にそういうパッケージも存在する模様。
github.comただ、試してみた限りでは
- 階層指定("gulp/**/graceful-fs" 等といった書き方)はできない
- "scripts"セクションに"preinstall"を追加するのは、一度 npm install を実行後にする必要あり
いったん npm install してから(package-lock.json が作成されてから)でないと、npm-force-resolutions がエラーになる
- パッケージの追加時等でpackage-lock.jsonが更新された際には、npm install をやり直す必要あり
のような感じで、今ひとつ使い勝手が良くないように感じた。
ざっくりとか見ていないため、誤解しているかもしれない