開発が止まっていたflow-to-typescriptを動かした話

We Are JavaScripters!【執筆初心者歓迎】 Advent Calendar 2018 2日目の記事です。

jsの記事はさして読んで嬉しい記事をかけないのですが、初心者歓迎とのことなので書かせていただきます!

今回はReact/Flow製アプリをbcherny/flow-to-typescriptを使ってReact/TypeScriptに変換できるのか試して見ました。
FlowからTSへ移行する際のモチペーションや進める上でのTIPS等はPIXTAさんのFlow から TypeScript に移行しましたが詳しいので、こちらを参照される事をオススメしますw
今回は上記記事にも出てくるbcherny/flow-to-typescriptを実際に使って見たらどんなもんかと思い、試してみたログになります。

TL;DR

  • 動けばok程度であれば自動ツールを使うことで変換できることが確認できた。
  • TypeScriptのエラー等正しく取り除くためにはペインも多いので、業務で実行するにはROI悪めな印象を受けた。
  • アウトプットはこちらsizer/mobx-flow-example

やったことは

  • flow-to-typescriptを動くようにする
  • TSコンパイラとWebpackの設定を書く
  • TypeScriptが.tsxじゃないとJSX変換できないので変換する

です。

変換するアプリケーション

githubで「react flow」などのキーワードで検索をして程よい規模のリポジトリを見つけたので下記を変換することに決定。

karlem/mobx-flow-example

ToDoアプリケーションですね。Forkして作業リポジトリを作る

作業リポジトリ(TypeScript)

https://github.com/sizer/mobx-flow-example

flow-to-typescriptを動くようにする

とりあえずREADME.mdに書いてあるままに

flow2ts.js

const f2ts = require('flow-to-typescript')
const fs = require('fs')

let path = 'src/index.js'
let file = fs.readFileSync(path, 'utf-8')

f2ts.compile(file, path).then(ts =>
  fs.writeFileSync('src/index.ts', ts)
)

実行。

> const f2ts = require('flow-to-typescript')
{ Error: Cannot find module 'flow-to-typescript'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:587:15)
    at Function.Module._load (internal/modules/cjs/loader.js:513:25)
    at Module.require (internal/modules/cjs/loader.js:643:17)
    at require (internal/modules/cjs/helpers.js:22:18) code: 'MODULE_NOT_FOUND' }

動かない、まじか笑

Continued development / support #1

どうやら開発が止まっているようですねw
(この辺でPIXTAさんの記事を知りましたw)

こちらもForkして動くところまで持って行きました。

diffはこちら

  • @bable/babylonを使っていたので、現在利用されている@babel/parserに移行
  • TypeScriptが古かったので最新化

しました。

改めて

flow2ts.js

const flow2typescript = require('./flow-to-typescript/dist/src')
const fs = require('fs')
const glob = require('glob')
const path = require('path')

const convertJS2TS = path => path.replace('\.js', '\.ts').replace('src', 'ts')

const compile2TS = (file) => (
  flow2typescript.compile(
    fs.readFileSync(file, 'utf-8'),
    file,
  ).then(ts => {
    fs.promises.mkdir(path.dirname(convertJS2TS(file)), { recursive: true })
    return ts
  }).then(ts => {
    fs.writeFileSync(convertJS2TS(file), ts)
  })
)

let pattern = 'src/**/*.js*'

glob(pattern, (_, files) => { files.forEach(file => compile2TS(file)) } )

Forkした方のブランチを相対パス指定することで解決。

無事、.js -> .ts変換できました。

TSコンパイラとWebpackの設定を書く

commitはこちら

  • mobx-flow-example
    • src
      • ここにFlow製の元ファイル
    • ts
      • こちらに変換した.tsファイルを吐き出す。
    • dist
      • Webpackの成果物はこちら

こんな感じでビルドして行きます。

TypeScriptが.tsxじゃないとJSX変換できないので変換する

これ、ハマりました。

公式にも書いてあるのですが、

In order to use JSX you must do two things.

  1. Name your files with a .tsx extension
  2. Enable the jsx option

https://www.typescriptlang.org/docs/handbook/jsx.html

TypeScriptはJSXを変換する際は、拡張子が.tsxじゃないといけないのですね、、、

tsconfig.json"jsx": "react"って書いたらイケるのかと思いきや、壊れた.jsファイルとしばらく格闘することになりました :sob:

こちらはやむなく手動で.js->.jsxに変換。

commit

ここまでやってアプリ自体は動くところまできました。

yarn run builddist/index.html にアプリが吐き出される事を確認。

やってみて

検証がてらやってみましたが、業務でやる内容ではないなーという気はしましたw
手間がかかる割に、成果物の質が低いのでw

PIXTAさんの記事にも書いてありますが、.jsと.ts共存できる環境作って、徐々にFlow製のアプリをTypeScriptに変換するのが吉かな、という印象でした。

以上です。パケットの無駄遣い失礼w