vue-next（Vue.js 3.0 wip）+ TypeScript + webpackでの開発環境を構築する

2020年のQ1にVue.js 3.0のリリースが予告されています。

公開に先駆けてVue 3.0の新機能を試したいと思い、TypeScript + Webpackでの開発環境を整えてみたのでまとめます。

**（2020/06/04 追記）**
vue-cli-nextが出ているようです。
https://github.com/vuejs/vue-cli-plugin-vue-next

**（2020/02/04 追記）**
この記事で作った環境を使いVue3.0の新機能`Suspense`, `Teleport`を試しました。こちらも参考までに。

* [Vue.js 3.0 の新機能を試す。 〜 Suspense 編〜](https://qiita.com/ryo2132/items/7225d60768a15dabfb9f)
* [Vue.js 3.0 の新機能を試す。 〜 Teleport 編〜](https://qiita.com/ryo2132/items/a620755b04294ffabde6)



# 内容

vue-nextのREADME.mdで紹介されている以下リポジトリを参考に、Webpack版のVue.js 3.0の開発環境をTypeScriptに対応させました。

https://github.com/vuejs/vue-next-webpack-preview

今回の動作コードはこちらにあります。
https://github.com/kawamataryo/vue-next-ts-webpack-preview

# 開発環境構築

以下作業は、
https://github.com/vuejs/vue-next-webpack-preview
をclone、またはforkしたリポジトリで行って下さい。

```
git clone https://github.com/vuejs/vue-next-webpack-preview.git
```

## 1. 依存モジュールの追加

TypeScriptのコンパイルに必要な`typescript`と`ts-loader`を追加します

```
yarn add -D typescript ts-loader
```

## 2. tsconfig.jsonの追加

TypeScriptの設定ファイル ts-config.jsonを追加します。
[vueの公式のもの]()を参考にしました。

```tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "strict": true,
    "module": "es2015",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true
  }
}
```

## 3. shims-vue.d.tsの追加
.vueファイルのimportでも型解決が出来るように、`shims-vue.d.ts`を追加します。
~~Vue 2系までの書き方で書いていたらコンパイルエラーで詰まったのですが、こちらのissueに助けられました。~~
~~https://github.com/vuejs/vue-next-webpack-preview/issues/5~~
（2020/06/05 型エラーが出ていたので修正しました）

`component`の型は`ReturnType<typeof defineComponent>`になるようです。

```src/shims-vue.d.ts
declare module "*.vue" {
  import { defineComponent } from "vue";
  const component: ReturnType<typeof defineComponent>;
  export default component;
}
```

## 4 webpack.config.jsonの修正

`main.js`から`main.ts`へエントリーポイントを変更し、さらに`ts-loader`を通すようにrulesを修正します。
`webpack.config.json`を以下のように修正してください。

```diff:webpack.config.json
module.exports = (env = {}) => ({
  mode: env.prod ? 'production' : 'development',
  devtool: env.prod ? 'source-map' : 'cheap-module-eval-source-map',
- entry: path.resolve(__dirname, './src/main.js'),
+ entry: path.resolve(__dirname, './src/main.ts'),
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/'
  },
  resolve: {
    alias: {
      // this isn't technically needed, since the default `vue` entry for bundlers
      // is a simple `export * from '@vue/runtime-dom`. However having this
      // extra re-export somehow causes webpack to always invalidate the module
      // on the first HMR update and causes the page to reload.
      'vue': '@vue/runtime-dom'
    }
  },
  module: {
    rules: [
+     {
+       test: /\.ts$/,
+       exclude: /node_modules/,
+       loader: 'ts-loader',
+       options: {
+         appendTsSuffixTo: [/\.vue$/]
+       }
+     },
      {
        test: /\.vue$/,
        use: 'vue-loader'
      },
      {
        test: /\.png$/,
        use: {
          loader: 'url-loader',
          options: { limit: 8192 }
        }
      },
...
```

## 5. main.js, App.vueをTypeScript化

ここまでで下準備が整ったので、`main.js`と、`App.vue`を実際にTypeScript化します。

`main.js`は拡張子を`ts`に変更するだけです。

```
mv src/main.js src/main.ts
```

`App.vue`は`<script>`に`lang="ts"`を追記して`defineComponent()`をexportするように修正します。

※ モジュールとして公開されている[vue/composition-api](https://github.com/vuejs/composition-api)では`createComponent()`だったのですが名前が変更されたようです。 https://github.com/vuejs/vue-next/pull/549

```src/App.vue
<template>
  <img src="./logo.png">
  <h1>Hello Vue 3!</h1>
  <button @click="inc">Clicked {{ count }} times.</button>
</template>

<script lang="ts">
import { ref, defineComponent } from 'vue'

export default defineComponent({
  setup() {
    const count = ref(0)
    const inc = () => {
      count.value++
    }

    return {
      count,
      inc
    }
  }
})
</script>

<style scoped>
img {
  width: 200px;
}
h1 {
  font-family: Arial, Helvetica, sans-serif;
}
</style>

```

以上で、TypeScript化の完了してるはず。
実際にコンパイルしてみましょう。

```
yarn dev
```

無事コンパイルが通れば成功です。

<img width="460" alt="スクリーンショット 2020-02-02 17.39.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114396/c678ee5f-9238-7fa8-99d7-9f1fb2e5fad8.png">


# 終わりに

以上「vue-next（Vue.js 3.0-alpha） + TypeScript + Webpackの開発環境を構築する」でした。
この環境を使って、Vue 3.0の新機能を色々試していきたいです!