Denoプラグインが普通のTypeScriptプロジェクトに干渉する

VSCodeにDenoプラグインをインストールすると、普通のTypeScriptのプロジェクトでlibの解決ができなくなったりするなど、干渉していました。だいたい問題ないのですけど、たまたまブラウザ環境のグローバル変数の型が解決できなくて困ってました。

const selection = window.getSelection();

こんなのとか、

(node as HTMLElement).appendChild(div);

こんなのでエラー。

前者はtsconfig.jsonにlib: ["dom"]を加えるように示唆までしてくれますが、当然そんなことはやってるって。後者はHTMLElementを@types/reactの方に見に行き、その定義が空っぽなのでアウト。ググっても解決方法見つからなく困ってたところで、独立したまっさらなVSCode環境作って確かめたら問題なく動いたので、やっと気がつきました。プラグインが悪いのだと。そしてそいつはDenoプラグインだと。

プラグインワークスペース単位で無効にできるので、それですぐに解決。Denoはたまに書くためにこのプラグイン自体は大変有用なので残します。

f:id:masataka_k:20191101203617p:plain

このプラグイン詳細画面によると、はっきりと"This extension works using VS Code's built-in version of TypeScript."って書いてありました。いくらtsconfig.jsonにlibを設定しても反映しないはずですね(しかし前のエントリで紹介したtypeRootsやemitDecoratorMetadataの設定は効いてたのでまるっきり見てない訳でもなく、単純な問題じゃなさそう。typeRootsはDenoプラグインを外せば記述の必要もなくなった)。また、Denoプラグインダウンロード回数がたった2016回しかない中で、同じVSCodeで普通のTypeScriptを利用したlibdom.d.tsを参照してもらわないと困るようなプロジェクトをやらない限りぶつからない問題なのでググっても出てこないわけだ。少なくともこの2016回のうち2回は私だし。

vscode typescript tsconfig.json lib dom window document global ts2584 ... この辺のキーワードでググっても出てこないです。今調べたら deno plugin conflict あたりでも全く出てこなかった。世界初のハマりかもしれない。

NestJSの設定で漏れるとダメなやつ

つまらないところでハマったので、未来の私のために備忘。NestJSCLIを使わずに手でプロジェクトを作ったとき、tsconfig.jsonに以下をいれないとダメ。

// tsconfig.json
{
    "compilerOptions": {
        "target": "es5",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
    }
}
  • experimentalDecorators をいれないと、未来で仕様変わるかも?と警告が出てトランスパイル止められる。これは絶対気がつくので問題なし。
  • emitDecoratorMetadata をいれないと、一見したところトランスパイルも実行も問題なく動くように見えるけど、@Injectableが解決されずサイレントにundefinedで全滅。NestJSのIoTには実行時にTypeScriptの型を保持するというこのオプションが必要。NestJSのガイドの通りにreflect-metadataパッケージを追加 していたけど、emitDecoratorMetadataはガイドに書いてなかった。

VSCodeでJest

最近はどうしてもコード書く機会が少ないので、JetBrains製品のサブスクリプションを維持するのを諦めてこれまで食わず嫌いだったVSCodeに移行したのですが、改めてコード書き始めるとちょいちょいハマったのでメモっておかねば。for 未来の私。

課題

TypeScript + Jestが今までの作法で動かなかった。

解決

必要パッケージを追加する。本体に必要なパッケージ群は別に、Jestで必要なものたちは...

$ yarn add typescript jest ts-jest @types/jest

http://mk.hatenablog.com/archive/2019/05/17

おなじみts-jestはpreset一発で細々としたjest設定が終わり超楽。ドキュメントによるとプリセットは混在する.jsの処理の違いで複数用意されている。テストコードがTypeScriptオンリーなら値は"ts-jest"。そういえばこれ、前にやりました

// package.jsonの関係あるとこだけ抜粋
{
    "jest": {
        "preset": "ts-jest"
    },
    "devDependencies": {
        "@types/jest": "^24.0.19",
        "jest": "^24.9.0",
        "ts-jest": "^24.1.0",
        "typescript": "^3.6.3"
    }
}

ここで問題発生。VSCodeのIntellisenseが期待通りに動作せず、グローバルスコープの、describe・it・jestの名前解決ができない。WEBを調べるとプロジェクトルートにjsconfig.jsonを書けとか見つけたので、VSCodeのドキュメントの該当ページにあたって設定してみたりするも改善しない。

その後にtsconfig.jsonを試行錯誤する中で、以下が当たりだった。 "typeRoots": [ "./node_modules/@types" ] で型ファイルを明示的に取り込んでる。非グローバルはimportでコード上に明示されるのでそもそもに解決できるけど、暗黙となってしまうグローバルの型はここで探索する。これまで経験してきたJetBrains製品(CLion、WebStorm、GoLand)では、"types": [ "jest", "node" ] で読み込んでたのだけど、現在の私のVSCode環境ではそれが上手くなく、 ”typeRoots" にプロジェクトローカルなパス設定となった。もちろん "types" でも方法はあるのだと思うが、こちらの方が堅い上に万一の追加パッケージに柔軟なように考えるのでいいかな。

さらに "types"では、アプリケーション本体に必要なパッケージ群で複数取り込まれていた @types/node で重複エラーが出るという謎動作が出た。パッケージ識別名で捉えるのではなくパスで誤解なく指示するのは、こちらの解決にも効いてる。

// tsconfig.jsonの現在
{
    "compilerOptions": {
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "lib": [ "es6", "esnext" ],
        "module": "commonjs",
        "target": "es5",
        "sourceMap": true,
        "strict": true,
        "typeRoots": [ "./node_modules/@types" ]
    },
    "exclude": [ "node_modules" ]
}

ちなみにlambdaアプリケーションをwebpackでビルドしているので上記その他の設定です。

追記 2019/11/1

これ、Denoプラグインのせいだった。プラグイン外せばtypeRootsではなくこれまでのtypesを利用する設定でもOK。

VSCodeでdeno

愛用するGoLandのサブスクリプションが切れてしまいました。すでにGoLand乗り換えの際にWebStormは捨ててたので、JetBrainsのIDEは無くなった。継続すればいい話なのですが、最近は違う種類の仕事で時間取られて開発作業に関わることが少なく、あってもAtomで仕様書いたりSketchでワイヤー引いたりする程度だったので維持するのをやめました。

そんな中でdenoのプラグインVSCodeにあると本家サイトに書いてあったのを見て、VSCodeにしようかなと思います。退路を断つためAtomはアンインストール。VSCodeを入れて、チュートリアルサイトの学習動画を見て、会社にあったSoftware Design 4月号のVSCode特集をナナメ読み中。

f:id:masataka_k:20190727131558p:plain

プラグインで、deno対応を入れたら、ちゃんとdeno独特なimportを解決してくれました。node上のTypeScriptと異なるのはここだけなのでもう問題ない。デバッガは...どうなるのかな。テスト書けばいいとはいえブレイクポイント置いてインクリメンタルデバッグもできたら最高なのだが。

denoがHomeBrew入りしてたよ

たまにbrew upgradeを打ってますが、今日たまたま気がついた。denoがHomeBrewのFormulaeになってました。何度かあった破壊的変更も最近はなく、手元で書いた自分的便利ツール群が元気にdenoで動いています。

$ brew info deno
deno: stable 0.9.0 (bottled)
Command-line JavaScript / TypeScript engine
https://deno.land/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/deno.rb
==> Dependencies
Build: llvm ✘, ninja ✘, node ✔, rust ✘
==> Requirements
Required: macOS >= 10.11==> Analytics
install: 753 (30 days), 826 (90 days), 1,031 (365 days)
install_on_request: 751 (30 days), 824 (90 days), 1,029 (365 days)
build_error: 0 (30 days)

enzymeがまたしばらくみないうちに変わってた

mk.hatenablog.com

前回は15ヶ月ぶりでしたが、さらに今回は5ヶ月後。enzymeのセットアップ周りが改善されて過去の面倒な作業がなくなってる。ついでにts-jestもちょっと変わってる。

// enzyme.setup.js
const enzyme =  require('enzyme');
const Adapter = require('enzyme-adapter-react-16');

enzyme.configure({ adapter: new Adapter() });

こんなセットアップファイルを用意します。enzymeのサイトの通り。ES6だと動く環境選ぶので、ES5が間違いない。

// package.json
{
    "scripts": {
        "test": "jest",
    },
    "jest": {
        "preset": "ts-jest",
        "moduleNameMapper": {
            "@/(.+)": "<rootDir>/src/$1"
        },
        "setupFilesAfterEnv": [
            "./enzyme.setup.js"
        ]
    },
    "devDependencies": {
        "@types/enzyme": "^3.9.2",
        "@types/jest": "^24.0.13",
        "@types/ramda": "^0.26.8",
        "@types/react": "16.8.17",
        "enzyme": "^3.9.0",
        "enzyme-adapter-react-16": "^1.13.0",
        "jest": "^24.8.0",
        "react-test-renderer": "^16.8.6",
        "ts-jest": "^24.0.2",
        "typescript": "^3.4.5"
    },
    "dependencies": {
        "ramda": "^0.26.1",
        "react": "^16.8.6",
        "react-dom": "^16.8.6"
    }
}

必要なところだけ絞ると、上記の感じ。JSDomを引っ張ってくるような細かな作業が一切なくなってました。jest.moduleNameMapperは、tsconfig.jsonで似たようなことを書いてあるにも関わらず設定を引いてくれないので、こちらでも書いてます。

が、しかし。これはCreate React App(CRA)を用いてない場合。CRAは色々やってくれて便利で、テスト環境も整えてくれているのだけどそれだけではすまない場合もある。Enzymeの場合がそれ。

CRAを利用している場合

Enzymeに限らず、Jestのセットアップファイルは、src/setupTest.tsもしくはsetupTest.jsで書いておくと、react-scriptsが無設定で引っ掛けてくれる。楽チンな一方で、jest.moduleNameMapperなどの仮想で絶対パスを作る機能はreact-scriptsによって利用禁止にされている。CRAはほぼ無設定でReactのボイラープレートを整えてくれて、さらにその後の開発環境にもなってくれているけど、こういったところでブラックボックスや謎仕様はあるので悩ましくなってきました。

denoの開発速度が上がってきた

denoの開発速度が上がってきた。

github.com

毎週マイナー上げてくって。これまでTypeScriptのコンパイラ設定が不可能だったのだけど、出たばかりの0.4.0からtsconfig.jsonを指定できるようになってました。それ以前に破壊的改変があって、先の紹介コードはCLIが変わったために動かなくなっちゃった。これらは大きい変更ですが、今後は何はなくともどんどんマイナー上げてくって言うので想像するに、そろそろ1.0.0への着地が見えてきたってことなのかな?GW入ってから尿路結石が発症して痛くて、アナウンスや議論を追わずツマミ食いしてるので事情は知らない。

この前のコードをちょっと変える。

#!/usr/bin/env deno run --allow-read --allow-write
import { renames } from './renames_lib.ts';
renames();

変更点は、denoにサブコマンドが追加されたことです。denoではなく、deno runとする。ヘルプで--allow-readや--allow-writeのことが記述されてなかったので無くなったのかと思い削ったら意図した動きにはならなかった。ヘルプから今は記述が落ちてても、権限指定は変わらずに必要。