2018/03/06

JavaScriptとTypeScriptを共存させ、段階的に移行する方法

某サービスのフロントエンド開発に携わるようになってからずっと考えていることがある。


TypeScriptに移行して、型に守られたい!



ただ稼働しているサービスをいっきにTypeScriptに移行するのは危険で膨大な工数がかかるため、段階的に移行できないかと考えた。
ということでJavaScriptとTypeScriptを共存させる方法をまとめる。

環境は以下のとおり。
  • webpack@4.0.1
  • webpack-cli@2.0.9
    • webpack v3系の場合は不要
  • typescript@2.7.2
  • ts-loader@4.0.0
※ あとでbabel-loaderについて追記予定です!
→ 2018/03/23 追記しました


移行前の状態


極小サンプルを使って紹介する。
// src/main.js
import { add } from './module'

const result = add(1, 2)
console.log(result)
// src/module.js
export const add = (x, y) => x + y


一部のコードをTypeScriptにして共存させる


src/main.jsのコードはそのままにsrc/module.jsだけTypeScriptに移行する。
// src/module.ts
export const add = (x: number, y: number): number => x + y

拡張子をjs→tsにして、型を書いただけ。


次に、JS+TSをビルドできるようにwebpackの設定を行う。
# webpackをインストール(※webpack4.0からCLIで実行するためにはwebpack-cliが必要になる)
$ npm i -D webpack webpack-cli

# TypeScriptをビルドする用
$ npm i -D typescript ts-loader

次にwebpackの設定をする。
// webpack.config.js
const path = require("path");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist")
  },
  resolve: {
    extensions: [".js", ".ts"]
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: "ts-loader",
        include: __dirname
      }
    ]
  }
};
package.jsonにビルド用のスクリプトを定義する。
// package.json
{
  // 略
  "scripts": {
    "build": "webpack --config webpack.config.js"
  },
  // 略
}


お好みのtsconfig.jsonを用意して、あとはnpm run buildを実行すればいい感じにビルドしてくれる。



追記: babel-loaderをつかって各ブラウザ対応をする


追記: 2018/03/23

ts-loaderでビルドするだけでも良いのだが、たとえばIE11はPromiseやGeneratorに対応していない。そのため、ts-loaderでts→jsに変換したあとにbabelを使って各ブラウザ対応するのが一般的だ。

まずbabel関連のライブラリをインストールする。バージョンは以下のとおり。

  • babel-loader@7.1.4
    • webpack用のplugin
  • babel-core@6.26.0
    • babelでトランスパイルするため
  • babel-preset-env@1.6.1
    • ターゲットをもとに必要なプラグインを自動で決定してくれるライブラリ
  • babel-plugin-transform-runtime@6.23.0
    • ないと「regeneratorRuntime is not defined」というエラーになる
    • babel-polyfillもあるが、体感ではtransform-runtimeを使っている人が多い


# babel関連をインストール
$ npm i -D babel-loader babel-core babel-preset-env babel-plugin-transform-runtime

.babelrcにトランスパイルするときの設定を定義する。
下記の例では、ブラウザは最新の2バージョンのみ対応している。browseri.lstで確認できる。
.babelrc
{
  "presets": [
    ["env", {
      "targets": {
        "browsers": [
          "last 2 versions"
        ]
      },
      "modules": false
    }]
  ],
  "plugins": [
    "transform-runtime"
  ]
}

modules: falseがないと、babelが勝手にCommonJSに変換してしまうのでimport hoge from fugaがおかしくなるので注意。(これでかなりハマった)

最後にwebpack.config.jsを編集して完成!
loaderの指定方法はいくつかあるので、書き方はお好みで。
原則として文字列や配列で指定したloaderの後ろから実行されるので、そこだけ注意が必要。
module.exports = {
  // 略
  module: {
    rules: [
      // 略
      {
        test: /\.ts$/,
        loader: 'babel-loader!ts-loader',
        include: __dirname,
        exclude: /node_modules/
      },
      // 略
    ]
  }
}



以上

written by @bc_rikko

0 件のコメント :

コメントを投稿