■ 追記
2020年02月11日にid:SWIMATH2さんが対応して下さり、generator-chrome-extension-kickstart-typescript v4.4.1 以降では、Node.js 12 でも元の手順のままで正常動作するようになった模様です。
以下は古い情報となります。
勉強を兼ねてブラウザ拡張機能をTypeScriptで書いてみようと、swimath2.hatenablog.com の generator-chrome-extension-kickstart-typescript を試してみたところ、Node.js v12 ではそのままでは動作しませんでした。
試行錯誤の末にとりあえず動くようになったので、覚え書きとして手順等を書いておきます。
対策(お急ぎの方はこちらだけお読みください)
試行環境
- Windows 10 Pro バージョン 1903(Microsoft Windows [Version 10.0.18362.535])
- Git for Windows version 2.24.1.windows.2 (※手順はGit BASH上で実施)
- Node.js v12.14.1 LTS (npm 6.13.4)
- Yarn 1.21.1
- Yeoman / yo 3.1.1
- generator-chrome-extension-kickstart-typescript a5d5fc8 on 2 Sep 2017(※2020/01/11時点の最新版 )
# Node.js v12.14.1 LTS および Yarn 1.21.1 は、それぞれインストーラをダウンロードしてインストール済 $ node -v && npm -v v12.14.1 6.13.4 $ yarn -v 1.21.1 # yo および generator-chrome-extension-kickstart-typescript を npm もしくは yarn にて global インストール #$ npm install -g yo generator-chrome-extension-kickstart-typescript $ yarn global add yo generator-chrome-extension-kickstart-typescript $ yo --version 3.1.1
手順
1. 拡張機能用のプロジェクト作成
拡張機能用のフォルダを作り(例では sample)chrome-extension-kickstart-typescript を --skip-install 付きで実行$ mkdir -p sample $ cd sample # --skip-install を付けて、npm による自動インストールを抑制 $ yo chrome-extension-kickstart-typescript --skip-install
2. package.json 編集
$ vi ./package.json
- "devDependencies" フィールド中、"gulp" のバージョンを "3.9.0" に固定
3.9.1だと "Failed to load external module @babel/register" のような警告が出るからだが、その後 fallback されるため、このバージョンダウンは必須ではない - 同フィールドに、"typescript" : "^3.x.x" を追加
2020/01/11時点では Version 3.7.4 が入った - "resolutions" フィールドを作成し、"gulp" 下の "graceful-fs" のバージョンとして "^4.x.x" を指定
Yarn の Selective dependency resolutions 用設定
※差分例
--- ./package.json.orig 2020-01-11 14:33:14.473509100 +0900 +++ ./package.json 2020-01-11 14:44:36.316563000 +0900 @@ -32,7 +32,7 @@ "chromereload": "0.x.x", "debounce": "1.x.x", "del": "3.x.x", - "gulp": "3.x.x", + "gulp": "3.9.0", "gulp-bump": "2.x.x", "gulp-cache": "0.x.x", "gulp-clean-css": "^3.x.x", @@ -57,6 +57,10 @@ "vinyl-named": "1.x.x", "webpack": "3.x.x", "webpack-stream": "3.x.x", - "yargs": "^8.x.x" + "yargs": "^8.x.x", + "typescript": "^3.x.x" + }, + "resolutions": { + "gulp/**/graceful-fs": "^4.x.x" } }
3. パッケージのインストール
yarn install で必要な全パッケージをインストール$ yarn install
4. 動作確認
動作するかどうかを yarn run で確認$ yarn run dev:chrome
※ 正常動作したときの例
yarn run v1.21.1 $ gulp --watch --vendor=chrome [14:56:00] Requiring external module babel-core/register [14:56:07] Using gulpfile D:\webext\sample\gulpfile.babel.js [14:56:07] Starting 'build'... [14:56:07] Starting 'clean'... [14:56:07] Finished 'clean' after 3.37 ms [14:56:07] Starting 'manifest'... [14:56:07] Starting 'scripts'... [14:56:07] Starting 'styles:css'... [14:56:07] Starting 'styles:less'... [14:56:07] Starting 'styles:sass'... [14:56:07] Starting 'pages'... [14:56:07] Starting 'locales'... [14:56:07] Starting 'images'... [14:56:07] Starting 'fonts'... [14:56:07] Starting 'chromereload'... [14:56:07] Starting 'livereload-server' [14:56:07] Finished 'styles:css' after 32 ms [14:56:07] Finished 'styles:less' after 26 ms [14:56:07] Finished 'styles:sass' after 26 ms [14:56:07] Starting 'styles'... [14:56:07] Finished 'styles' after 20 μs [14:56:07] Finished 'pages' after 27 ms [14:56:07] Finished 'fonts' after 26 ms [14:56:07] Finished 'manifest' after 264 ms [14:56:07] Finished 'locales' after 237 ms [14:56:07] Finished 'images' after 237 ms ts-loader: Using typescript@3.7.4 and D:\webext\sample\tsconfig.json [14:56:10] Finished 'scripts' Hash: 941f7e8c10f53a4b8956 Version: webpack 3.12.0 Time: 2076ms Asset Size Chunks Chunk Names background.js 6.83 kB 0 [emitted] background [0] multi ./app/scripts/background.ts 28 bytes {0} [built] [1] ./app/scripts/background.ts 254 bytes {0} [built] [14:56:10] webpack is watching for changes
経緯
発生した不具合
最初に、qiita.com を参考にして、
$ mkdir -p sample $ cd sample $ yo chrome-extension-kickstart-typescript # 試行のためとりあえず問にはすべて[Enter] $ 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 をすると、
# package-lock.json は npm-shrinkwrap.json と排他なため、消しておく $ rm package-lock.json # パッケージのインストール $ npm install # ※このとき、npm-shrinkwrap.json も更新されることに注意 # 開発環境を起動 $ 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 をやり直す必要あり
のような感じで、今ひとつ使い勝手が良くないように感じた。
ざっくりとか見ていないため、誤解しているかもしれない
その他
generator-chrome-extension-kickstart 及び主な fork の状況
- generator-chrome-extension-kickstart-typescript は generator-chrome-extension-kickstart の fork(4.4.0 (7109375 on 3 Aug 2017) から)
- generator-chrome-extension-kickstart は TypeScript 対応版の fork 後も更新されている(最新版:b6d1067 on 9 Jan 2018、リリース最新:4.4.2 (5b8c0fa on 13 Oct 2017))
- TypeScript 対応版(a5d5fc8 on 2 Sep 2017(※2020/01/11時点の最新版 ))が fork され、さらに Preact に対応した generator-chrome-extension-kickstart-typescript-preact もある(最新版:9caa42f on 23 Jan 2019)