mazipan.xyz

Migrasi Nuxt ke TypeScript

📆 May 15, 2019 • ☕️ 10 min read • ❤️ 0 likes • 📓 0 read
📆 May 15, 2019 • ☕️ 10 min read
❤️ 0 likes • 📓 0 read

Seperti kita tau bersama bahwa bawaan dari project Nuxt akan membuat kode dengan basis JavaScript Vanilla. Sedangkan dengan makin maraknya penggunaan TypeScript di kalangan para pengembang JavaScript membuat saya pribadi ikut kepincut untuk mengimplementasikan penggunaan TypeScript pada projek kode sumber terbuka saya.

Quran Offline

Berikut hal-hal yang saya kerjakan dalam proses migrasi tersebut:

Menambahkan tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "moduleResolution": "node",
    "lib": ["esnext", "esnext.asynciterable", "dom"],
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "resolveJsonModule": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noImplicitAny": false,
    "strictNullChecks": false,
    "noEmit": true,
    "baseUrl": ".",
    "paths": {
      "~/*": ["./*"],
      "@/*": ["./*"]
    },
    "types": ["@types/jest", "@types/node", "@nuxt/vue-app"]
  },
  "exclude": [
    "nuxt.config.ts",
    "node_modules/**",
    "dist/**",
    ".nuxt/**",
    "tests/**"
  ]
}

Untuk menambahkan berkas ini, saya juga perlu menambahkan beberapa dependencies berikut:

{
  "@nuxt/typescript": "2.7.1",
  "@types/jest": "24.0.13",
  "@types/node": "11.13.10",
  "typescript": "3.4.5"
}

Perbarui eslintrc.js

module.exports = {
  plugins: ['@typescript-eslint'],
  parserOptions: {
    parser: '@typescript-eslint/parser'
  },
  extends: [
    '@nuxtjs',
    'plugin:nuxt/recommended',
  ],
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-unused-vars': 'off',
    'vue/component-name-in-template-casing': [
      'error',
      'PascalCase',
      {
        ignores: ['nuxt', 'nuxt-link', 'nuxt-child', 'no-ssr']
      }
    ],
    'vue/html-closing-bracket-newline': [
      'error',
      {
        singleline: 'never',
        multiline: 'never'
      }
    ]
  }
}

Dan menambahkan beberapa dependencies berikut:

{
  "@nuxtjs/eslint-config": "0.0.1",
  "@typescript-eslint/eslint-plugin": "1.9.0"
}

Ubah nuxt.config.js menjadi nuxt.config.ts

Ubah ekstensi file dan buat sedikit perubahan menjadi seperti berikut:

import NuxtConfiguration from '@nuxt/config'
import {
  Configuration as WebpackConfiguration
} from 'webpack'

const config: NuxtConfiguration = {
  mode: 'universal',
  head: {},
  build: {
    extend(config: WebpackConfiguration, ctx) {
    }
  }
}

export default config

Refactor Vuex Store

Karena hampir semua komponen dalam projek saya telah menggunakan Vuex Store maka dari itu saya meletakan hal ini sebagai yang pertama untuk saya refactor sebelum melakukan refactor pada komponen. Untuk menggunakan Vuex dengan TypeScript terdapat sedikit perubahan dibandingkan ketika menggunakan JavaScript biasa, berikut perubahan yang saya kerjakan:

Classic Store

Pada projek ini saya masih menggunakan Classic Store yang mana sebenarnya sudah deprecated dan akan di remove pada Nuxt v3 kedepannya, berikut classic store yang saya buat dalam berkas store/index.ts:

import Vuex from 'vuex'

import { state } from './state'
import { mutations } from './mutations'
import { actions } from './actions'

const createStore = () => {
  return new Vuex.Store({
    state: state(),
    mutations,
    actions
  })
}

export default createStore

State

Pada berkas state.ts saya membuat interface yang menjadi type definitions dari state yang akan dibuat dan membuat state dengan berbagai initial state yang sudah dibuat seperti contoh berikut:

export interface StateType {
  isShowSidebar: boolean,
}

// initial state
export const state = (): StateType => ({
  isShowSidebar: false
})

Mutations

Vuex sendiri sudah menyediakan dukungan untuk TypeScript dengan memberikan tipe data pada balikan untuk Mutations dengan cukup meng-import MutationTree dari Vuex, berikut contoh kodenya:

import { MutationTree } from 'vuex'
import { StateType } from './state'
import { Types } from './types'

export const mutations: MutationTree<StateType> = {
  [Types.SET_SHOW_SIDEBAR](state: StateType, data: boolean) {
    state.isShowSidebar = data
  }
}

Actions

Untuk actions sendiri hampir mirip dengan mutations yang mana sudah disediakan tipe data dari Vuex, seperti contoh kode berikut:

import { ActionTree } from 'vuex'
import { StateType } from './state'
import { Types } from './types'

export const actions: ActionTree<StateType, StateType> = {
  setShowSidebar({ commit }, payload) {
    commit(Types.SET_SHOW_SIDEBAR, payload)
  }
}

Refactor Komponen

Setelah berhasi melakukan refactor pada Vuex Store, selanjutnya kita akan melakukan refactor pada kode komponen kita agar mendukung TypeScript.

Untuk mendukung TypeScript, kita perlu menambahkan beberapa dependencies baru seperti berikut:

{
  "vue-class-component": "7.1.0",
  "vue-property-decorator": "8.1.1",
  "vuex-class": "0.3.2"
}

Yang paling utama, tentu kita harus mengubah kode dalam single file komponen Vue yang sebelumnya hanya <script></script> menjadi <script lang="ts"></script> agar kita bisa mendukung kode TypeScript pada bagian script. Dan berikut contoh layout default.vue yang sudah saya refactor menggunakan TypeScript:

import { Component, Vue } from 'vue-property-decorator'
import { State, Mutation, Action } from 'vuex-class'

import ArrowUpIcon from 'vue-ionicons/dist/js/ios-arrow-dropup-circle'
import BaseHeader from '../components/BaseHeader.vue'
import BaseSidebar from '../components/BaseSidebar.vue'
import BaseToast from '../components/BaseToast.vue'

@Component({
  components: {
    BaseHeader,
    BaseSidebar,
    BaseToast,
    ArrowUpIcon
  }
})

export default class DefaultLayout extends Vue {
  showArrowToTop = false;

  @State settingActiveTheme;
  @State isShowSidebar;

  @Mutation setShowSidebar;

  @Action initDataFromBrowserStorage;
  @Action setWebshareSupport;

  hideSidebar(): void {
    this.setShowSidebar(false)
  }

  handleScroll(): void {
    this.showArrowToTop = window.pageYOffset > 2000
  }

  mounted() {
    window.addEventListener('scroll', this.handleScroll)
  }

  beforedestroy() {
    window.removeEventListener('scroll', this.handleScroll)
  }
}

Seperti bisa kalian lihat dari contoh kode diatas, saya menggunakan vue-property-decorator ↗️ untuk mendefinisikan komponen tersebut serta menggunakan vuex-class ↗️ untuk melakukan binding terhadap Vuex Store yang telah dibuat sebelumnya agar bisa digunakan di dalam komponen. Silakan kunjungi tautan masing-masing untuk mempelajari lebih lanjut mengenai apa saja yang bisa dan tidak bisa kita lakukan dengan vue-property-decorator maupun vuex-class.

Refactor Jest Config

Unit test hampir tidak diperlukan perubahan sama sekali selain dari path dan nama file yang kemungkinan besar kita ubah nama dan letaknya. Kita hanya perlu mencocokan konfigurasi Jest agar mendukung TypeScript seperti pada contoh kode berikut:

module.exports = {
  moduleNameMapper: {
    '^~/(.*)$': '<rootDir>/$1',
    '^@/(.*)$': '<rootDir>/$1',
    '^vue$': 'vue/dist/vue.common.js'
  },
  moduleFileExtensions: ['js', 'ts', 'vue', 'json'],
  transform: {
    '^.+.tsx?$': '<rootDir>/node_modules/ts-jest',
    '^.+.js$': '<rootDir>/node_modules/babel-jest',
    '^.+.vue$': '<rootDir>/node_modules/vue-jest'
  },
  globals: {
    'ts-jest': {
      diagnostics: false
    }
  }
}

Repository sumber

🐙 https://github.com/mazipan/quran-offline ↗️

Demikian artikel kali ini, semoga bermanfaat...



📧 Get the newsletter