yesodとwebpackを協調させてTypeScriptをビルドする方法
yesodとwebpackを協調させてTypeScriptをビルドする方法
現在yesodとTypeScriptを併用していて, yesodがhaskellアプリケーションをビルドする前にwebpackでTypeScriptをJavaScriptにビルドするということを行っています.
yesodのshakespeareのText.TypeScript
にはエラー表示が極めてわかりにくいとかグローバルにtsc
をインストールしないといけないとかそもそも何故か動かなくなる時があったので独自にwebpackを動かしています.
package.yaml
build-type: Custom
package.yamlでもcabalでもいいですが,
build-type: Custom
を指定しましょう.
これでstack build
にhookをかますことが出来ます.
Setup.hs
import Distribution.PackageDescription
import Distribution.Simple
import Distribution.Simple.Setup
import System.Process
main :: IO ()
main = defaultMainWithHooks simpleUserHooks
{ preBuild = pb
}
pb :: Args -> BuildFlags -> IO HookedBuildInfo
pb _ _ = callProcess "yarn" ["run", "build"] >> return emptyHookedBuildInfo
このようにすればビルド前にyarn run build
を動かすことが出来ます.
後はpackage.jsonで好きなようにすれば良いでしょう.
Application.hs
-- | main function for use by yesod devel
develMain :: IO ()
develMain = do
(_, _, _, watchProcess) <- createProcess $ (proc "yarn" ["run", "watch"]) { create_group = True }
develMainHelper getApplicationDev `finally` interruptProcessGroupOf watchProcess
yesod devel
時にファイル変更をwebpack側などでキャッチしてyesod devel
の再起動をせずにTypeScriptなどをビルドしたい場合は,
develMain
に仕掛けを行う必要があります.
今回はyarn run watch
を動かしています.
このようにプロセスをきちんと取り扱わないとyesod devel
が終了してもnodeのプロセスが終了しないので注意.
travis.yml
sudo: false
cache:
yarn: true
directories:
- $HOME/.local
- $HOME/.stack
language: node_js
node_js: "8"
addons:
apt:
packages:
- libgmp-dev
before_install:
- mkdir -p ~/.local/bin
- export PATH=$PATH:$HOME/.local/bin
- hash stack || travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
- stack setup
install:
- stack --jobs 2 --no-terminal test --only-dependencies
- stack install hlint
- yarn
script:
- hlint src
- stack --jobs 2 --no-terminal test
travisは普通にinstall時にyarn
を実行すればいいでしょう.
細かい変更をmerge&rebaseして移している
goofysを使わないでS3のAPIを使うように変更するためのブランチで色々作業を行ってしまっていました. それがクラッシュ問題(別に前と比べてクラッシュ量が増えるというわけではないけど)で取り込まれるのが遅れそうなので, 他のブランチに変更をrebaseしてaws関係ないところだけpickして移しています.
こんなことなら初めから別ブランチで変更を加えれば良かった… しかし, 現在作業しているブランチに即座に変更を加えたい時についその場で変更してしまいます. 別ブランチでcommitしてpushしておいて, travisの結果を待たずにその変更をローカルでmergeしておけば問題ないのかな.
細部の変更を別ブランチにしてpushしたらtravis ciのテストに結構時間がかかる. 新しいブランチだとcache効かないんだっけ, そのへんの把握が曖昧.
jsをexternal指定してcdnjsを使う
reactとwebpackの構築は当初
React & Webpack · TypeScript
を参考に行っていたのですが,
import
で全部結合されるからexternals
要らなくね?
ということで取り外していました.
当時はJavaScriptのモジュール機能とwebpackの行う作業が全くわからなかったというのも原因にあります.
一時期はimport
で結合しているのに外部でcdnjsを読み込んでいるというアホみたいなことを行っていました.
どうもそれが間違いということがわかってきました, 大規模なjsファイルはcdnjsのようなpublic cdnを使った方が高速でキャッシュも効いて良さそうですね. 現在はreactもjs-cookieも1つのページでしか使っていませんが, この先複数のページで使うこともあるかもしれません. あと吐き出されるscriptが少なくなるのでデバッグする時に便利.
なのでなるべくcdnjsを使うようにexternals
を使っていきましょう.
ES Modulesを使いたいなと思いますが流石に無理ですね, IEしかサポートしてないという状況になったら考えますが, まだfirefoxすらフラグ付きのサポートなので.
このサイト自体はimport
どころかrequire
とbrowserifyを使ってるんですけどね…
bootstrap関係のscriptもcdnjsのものに書き換えようとしたけどbetaになってtetherからpopperというライブラリに乗り換えていますね, とりあえず放置で…
SRI付きのaddScriptRemoteAttrs
のボイラープレートを書いていくのが面倒くさくなってきたので以下の関数を追加しました.
問題がなくてコミュニケーションコストが払えればyesod本体に追加の提案をしていきたい.
-- | `addScriptRemote`をSRI付きで行う
addScriptRemoteSri :: MonadWidget m => Text -> Text -> m ()
addScriptRemoteSri remote integrity =
addScriptRemoteAttrs remote [("integrity", integrity), ("crossorigin", "anonymous")]
新しい@types/reactがエラーを吐くのでとりあえず問題ないバージョンに固定
cdn付きに切り替えるついでにパッケージのアップデートもしておいたらTS2403: Subsequent variable declarations must have the same type. Variable 'textarea' must be of type 'DetailedHTMLProps<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>', but here has type 'DetailedHTMLProps<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>'
というエラーになった.
ググッてコンパイラオプションのせいかと思ってデフォルトに戻してみたが改善せず.
大体なんだこのエラーは, 双方の型が完全に一致しているのにエラーが出る? 意味不明.
問題のtextareaの場所に行って行削除してみたらコンパイルが通ってしまった.
そもそもHTMLTextArea
とHTMLTextarea
どっちが正しいんだと思ってmdnを見に行ったらHTMLTextArea
が正しいらしい.
HTMLTextAreaElement - Web APIs | MDN
じゃあなんでreactはTextareaHTMLAttributes
なんだろうか.
しかし全てこちら側で統一されているから問題ないはず,
と思って@type/reactを修正してみたら今度は@type/react-domでエラーが発生した.
適当に本体にpull request出さなくて良かった, 環境の問題っぽい.
どうも中途半端にアップデートしたからreactとreact-dom間でバージョンの不整合が発生しているのかなと思い
yarn upgrade-interactive --latest
してみたら今度はreact-dom側で大量のエラーが発生しました.
@types/react-dom側はreact-15までしかサポートしてないので, @types/reactをバージョン15にしておくしかありませんね.
と思い@types/reactを15.5に限定してみましたがエラーは治らず. ならいっそのこと@types/react-dom側の15.5.4に固定してしまえば良いと思って選択してみましたが@types/reactは15.5を提供してないんですね…
@types/react-domは15.5しか提供しておらず, @types/reactは15.5を提供していない, 詰んだかな.
詰んだので上手く行っていた時のバージョン@types/react-15.0.38と@types/react-dom-15.5.4にバージョンを固定したら上手くいきました. react-domがバージョン16に統一されるようになったらバージョンも統一されて治るだろう.
自分の環境のせいなのかライブラリがおかしいのかわからないし, どうせreact-domがバージョン16になれば治りそうなバグなので, issueを建てる気にはなりませんね.