LoginSignup
14
15

More than 5 years have passed since last update.

Nuxt.jsでTypeScriptとJSXとJest

Posted at

世界中の"むずかしい"を簡単にする株式会社diffeasy日本一魅力的なプログラマー集団を目指すCTO西です。

この記事はGeeks Who Drink in Fukuoka -Front End Edition 2-でのLTの内容を記事にしたものです。
image.png

当日発表スライドはこちら。
Nuxt.jsで
TypeScriptとJSXとJest

ソースはGitHubにあげています。

Nuxt.jsとTypeScript

image.png

Nuxt.jsTypeScriptについては、こちらでは説明を省略します。

フロントエンドはTypeScriptで書きたい!という人が最近増えてきたように思います。
Nuxt.jsはTypeScriptをサポートしていなかったのですが、Ver.2.4.0からTypeScriptがサポートされるようになりました。

Nuxt.jsとJSX

JSX(「JavaScript eXtension」の略)はReactで利用されるJavaScriptの記法です。
JSX=Reactというイメージですが、Vue.js(Nuxt.js)でも利用することができます。

ちなみに、JSXでGoogle検索しようとすると、候補キーワードとして「気持ち悪い」が出てきます笑
JSX気持ち悪い
私自身も初めてJSXに出会った時の正直な感想は「キモっ!!」でした。
当時は「ロジックとデザインの分離をいかに進めるか?」ということを考えてシステム設計されることが多かったと思います。
弊社もエンジニアのスキル、体制を考慮して、ロジックとデザインは基本的に分離する設計を進めていました。

しかし、フロントエンド開発において構造・見た目・振る舞いをセットにして考える「コンポーネント志向」が増えてきました。その流れの中で、最近では私も「JSXありなんじゃないか?」と思うようになってきました。

Nuxt.jsとTypeScriptとJSXでアプリケーション開発

create-nuxt-appでNuxt.jsアプリケーション構築

Nuxt.jsのアプリケーションはcreate-nuxt-appを利用すると、コマンド1つで簡単に作成できます。まずはこれでNuxt.jsアプリケーションの雛形を作ります。
ただし、2019年3月時点で、TypeScriptには対応していないので、後からTypeScript対応していきます。

以下のコマンドを実行します。<my-project>にはプロジェクト名を入れてください。

$ yarn create nuxt-app <my-project>

実行すると、server framework、UI framework、test frameworkなど利用するフレームワークを聞かれますので、それぞれ選択してください。

今回はJestでテストするので、test frameworkはJestを選択します。
その他はお好みで。

nuxt-tsでTypeScript対応

nuxtを削除して、nuxt-tsを利用することで、TypeScript対応していきますので、一旦、yarn.lockとnode_modulesを削除します。

$ rm ./yarn.lock
$ rm -rf ./node_modules

nuxt-tsとvue-property-decoratorをインストールします。

$ yarn add nuxt-ts
$ yarn add vue-property-decorator

package.jsonのScriptをnuxtからnuxt-tsに書き換えます。

/package.json
  "scripts": {
    "dev": "nuxt-ts",
    "build": "nuxt-ts build",
    "start": "nuxt-ts start",
    "generate": "nuxt-ts generate",
    "test": "jest"
  },

tsconfig.jsonにTypeScriptを利用するための設定を追加します。
(この後の手順で再度tsconfig.json編集します。)

tsconfig.json
{
  "extends": "@nuxt/typescript",
  "compilerOptions": {
    "baseUrl": ".",
    "experimentalDecorators": true,
    "noImplicitAny": false,
    "allowJs": true,
    "types": [
      "@types/node",
      "@nuxt/vue-app"
    ]
  }
}

Nuxt.jsでJSXを利用する

tsconfig.jsonにJSXを利用するための設定を追加します。

tsconfig.json
{
  "extends": "@nuxt/typescript",
  "compilerOptions": {
    "baseUrl": ".",
    "experimentalDecorators": true,
    "noImplicitAny": false,
    "allowJs": true,
    "module": "commonjs",
    "jsxFactory": "h",
    "types": [
      "@types/node",
      "@nuxt/vue-app"
    ]
  }
}

コンポーネントを作成します。
/components配下に、*.tsxの拡張子でファイルを作成します。
ここでは、HelloWorld.tsxとします。

/components/HelloWorld.tsx
import { Vue, Component, Prop } from 'vue-property-decorator'

@Component
export default class HelloWorld extends Vue {
  @Prop({ default: 'TypeScript!' }) readonly name!: string
  message: string = 'Hello, '
  render(h: Vue.CreateElement): Vue.VNode {
    return (
      <div>
        <p>{this.message} {this.name}</p>
      </div>
    )
  }
}

通常のVueでは、*.vueファイル内にtemplateとscriptタグでテンプレートとロジックを書きますが、JSXを利用する場合は、render関数の中でJSXをレンダリングします。

pagesからHelloWorld.tsxを読み込みます。

/pages/index.vue
<template>
・・・
      <HelloWorld name="Takeshi"/>
・・・
</template>
<script>
import HelloWorld from '~/components/HelloWorld.tsx'
export default {
  components: {
    ・・・,
    HelloWorld
  }
}
</script>

devサーバーを起動して、ブラウザで http://localhost:3000 を開きます。

$ yarn run dev

NuxtJSX.png

起動して、コンポーネントが表示されました。

Jestでテスト

続けてコンポーネントのテストを書きます。

TypeScriptのテストを書くために、ts-jestをインストールします。

$ yarn add -D ts-jest

テストコードはとりあえず簡単に以下の通り。

/test/HelloWorld.spec.js
import { mount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.tsx'

describe('HelloWorld', () => {
  test('is a Vue instance', () => {
    const wrapper = mount(HelloWorld)
    expect(wrapper.isVueInstance()).toBeTruthy()
  })
})

JestでJSXのテストを実行すると、以下のエラーが発生します。

    Jest encountered an unexpected token
・・・
    Details:

    SyntaxError: /Users/takeshi/projects/nuxt24/nuxt_ts/components/HelloWorld.tsx: Unexpected token (16:16)

      14 |     }
      15 |     render(h) {
    > 16 |         return (<div>
         |                 ^
      17 |         <p>{this.message} {this.name}</p>
      18 |       </div>);
      19 |     }

JestでJSXのテストを実行するためには、tsconfig.jsonに"jsx": "react"の設定が必要なのですが、これを追加すると、JSXで書いたコンポーネントが画面に表示されなくなってしまいました。

そこで、テスト用のtsconfig.jsonを新たに作成して回避します。

/tsconfig.test.json
{
  "extends": "@nuxt/typescript",
  "compilerOptions": {
    "baseUrl": ".",
    "experimentalDecorators": true,
    "noImplicitAny": false,
    "allowJs": true,
    "jsx": "react",
    "module": "commonjs",
    "jsxFactory": "h",
    "types": [
      "@types/node",
      "@nuxt/vue-app"
    ]
  }
}

jest.config.jsからこちらのテスト用のtsconfigを読み込みます。
globals -> ts-jest -> tsConfigFileの設定箇所です。

/jest.config.js
module.exports = {
  globals: {
    'ts-jest': {
      useBabelrc: true,
      tsConfigFile: 'tsconfig.test.json'
    }
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/$1',
    '^~/(.*)$': '<rootDir>/$1',
    '^vue$': 'vue/dist/vue.common.js'
  },
  moduleFileExtensions: ['js', 'vue', 'json', 'tsx'],
  transform: {
    '^.+\\.js$': 'babel-jest',
    '.*\\.(vue)$': 'vue-jest',
    "^.+\\.tsx?$": "ts-jest"
  },
  "collectCoverage": true,
  "collectCoverageFrom": [
      "<rootDir>/components/**/*.vue",
      "<rootDir>/pages/**/*.vue"
  ]
}

テストを実行します。

$ yarn test

テスト成功しました!
image.png

感想

Nuxt.js Ver.2.4.0からTypeScirptサポートされるようになったとはいえ、色々なライブラリと連携させようとするとなかなかスムーズにはいきませんでした。

あと個人的な感想ですが、JSXだとrenderのなかにあまりダラダラとHTMLを書きたくないので、自然とコンポーネントの単位が小さくなりそうな気がします。

14
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
15