search
LoginSignup
4

More than 3 years have passed since last update.

posted at

updated at

Organization

Nuxt.js + TypeScript 環境に tslint を導入

はじめに

単一ファイルコンポーネント(.vue)に tslint を導入しようと試みたところ
<script lang="ts"></script> の部分以外にも lint が適応されてしまう問題に当たってしまった。
この記事ではその解決方法を交え tslint の導入方法を記載します。typescript の導入までは他の記事を参考にしたので、そもそも typescript の導入方法が異なる方は多少わかりづらいかも知れません。

前提

  • 既に単一ファイルコンポーネントに typescript で書ける環境が整っていること。
  • typescript の導入までは下記記事を参考にしましたので、ディレクトリー構造は下記記事と同様のまま説明していきます。

  ※ 参考記事(typescriptの導入)
  create-nuxt-appで構築したNuxt2のプロジェクトにTypeScriptを入れてvuexを使えるところまで持っていく

使用するパッケージ

一応バージョンも記載しておきます

  • tslint (v5.11.0)
  • tslint-loader (v3.5.4)
  • loader-utils (1.1.0)
  • vue-parser (1.1.6)

手順

STEP1: 必要なパッケージのインストール

npmの場合
$ npm install --save-dev tslint tslint-loader loader-utils vue-parser
yarnの場合
$ yarn add --dev tslint tslint-loader loader-utils vue-parser

STEP2: tslint-loaderの修正(vue-parserを使用する)

まず tslint を導入するに当たって tslint-loader を webpack の設定へ噛ませる必要があるのですが、
tslint-loader をそのまま使用すると <script lang="ts"></script> 以外の箇所も lint が適応されてしまうので
tslint-loader 自体を少し修正します。

tslint-loader 自体は node_modules/ の中にあるので、
一旦コピーしたファイル(_tslint-loader.js)を modules/ ディレクトリーへ置きます。

tslint-loaderをコピー
$ cp node_modules/tslint-loader/index.js modules/_tslint-loader.js

node_modules/tslint-loader/formatters/ の customFormatter.js も modules/ にコピーしておく
(無いと後々エラーになるため)

formatterをコピー
$ cp node_modules/tslint-loader/formatters/customFormatter.js modules/formatters/customFormatter.js

コピーした _tslint-loader.js の下記コード部分に少し修正を加えます

modules/_tslint-loader.js(修正前)
module.exports = function(input, map) {
  this.cacheable && this.cacheable();
  var callback = this.async();

  if (!semver.satisfies(Lint.Linter.VERSION, '>=4.0.0')) {
    throw new Error('Tslint should be of version 4+');
  }

  var options = resolveOptions(this);
  lint(this, input, options);
  callback(null, input, map);
};
modules/_tslint-loader.js(修正後)
var vueParser = require('vue-parser');
//...
module.exports = function(input, map) {
  this.cacheable && this.cacheable();
  var callback = this.async();

  if (!semver.satisfies(Lint.Linter.VERSION, '>=4.0.0')) {
    throw new Error('Tslint should be of version 4+');
  }

  var options = resolveOptions(this);
  // https://github.com/wbuchwalter/tslint-loader/issues/105
  if (/<script.*lang="ts".*>([\s|\S]*)<\/script>/.test(input)) {
    const _input = vueParser.parse(input, 'script', { lang: ['ts', 'tsx'] });
    lint(this, _input, options);
  } else {
    lint(this, input, options);
  }
  callback(null, input, map);
};

STEP3: tslint-loader を webpack へ噛ませる

修正した _tslint-loader.js を webpack へ噛ませるために modules/typescript.js を修正します。

modules/typescript.js(修正前)
module.exports = function() {
  // Add .ts extension for store, middleware and more
  this.nuxt.options.extensions.push("ts")
  // Extend build
  this.extendBuild(config => {
    const tsLoader = {
      loader: "ts-loader",
      options: {
        appendTsSuffixTo: [/\.vue$/]
      }
    }
    // Add TypeScript loader
    config.module.rules.push(
      Object.assign(
        {
          test: /((client|server)\.js)|(\.tsx?)$/
        },
        tsLoader,
      )
    )
    // Add TypeScript loader for vue files
    for (let rule of config.module.rules) {
      if (rule.loader === "vue-loader") {
        rule.options.loaders = {
          ts: "tsLoader"
        }
      }
    }
    // Add .ts extension in webpack resolve
    if (config.resolve.extensions.indexOf(".ts") === -1) {
      config.resolve.extensions.push(".ts")
    }
  })
}
modules/typescript.js(修正後)
const path = require('path');

module.exports = function() {
  // Add .ts extension for store, middleware and more
  this.nuxt.options.extensions.push("ts")
  // Extend build
  this.extendBuild(config => {
    const tsLoader = {
      loader: "ts-loader",
      options: {
        appendTsSuffixTo: [/\.vue$/]
      }
    }
    const tslintLoader = {
      loader: path.resolve(__dirname, '_tslint-loader.js'),
      // tslint の linterOptions.exclude で除外ファイルを指定できますが、
      // コマンドラインから tslint を実行した場合のみ有効なので、下記で除外ファイルを指定する必要があリます
      exclude: /node_modules|\.nuxt/,
      enforce: 'pre',
      options: {
        configFile: 'tslint.json',
      }
    }
    // Add TypeScript loader
    config.module.rules.push(
      Object.assign(
        {
          test: /((client|server)\.js)|(\.tsx?)$/
        },
        tsLoader,
      )
    )
    // Add TypeScript loaders
    config.module.rules.push(
      Object.assign(
        {
          test: /((client|server)\.js)|(\.tsx?)$/
        },
        tslintLoader,
      )
    )
    // Add TypeScript loader for vue files
    for (let rule of config.module.rules) {
      if (rule.loader === "vue-loader") {
        rule.options.loaders = {
          ts: "tsLoader!tslintLoader"
        }
      }
    }
    // Add .ts extension in webpack resolve
    if (config.resolve.extensions.indexOf(".ts") === -1) {
      config.resolve.extensions.push(".ts")
    }
  })
}

STEP4: tslint.json ファイルを作成する

tslint.jsonファイルの作成
$ touch tslint.json
tslint.json(例)
{
  "defaultSeverity": "error",
  "extends": "tslint:recommended",
  "rules": {
    "no-namespace": false,
    "no-string-literal": false,
    "max-line-length": {
      "options": {"limit": 120},
      "severity": "warn"
    },
    "interface-name": [true,  "never-prefix"],
    "ordered-imports": false,
    "object-literal-sort-keys": false
  }
}

STEP5: 完了

これで一通り完了なので、Nuxtの開発環境を立ち上げてみましょう。

nuxtの開発環境立ち上げ
# yarn
$ yarn run dev
# npm
$ npm run dev

下記のように tslint が動作していれば完了です🎉
image.png

オプション

tslint は正常に動作するようになったものの、
少し見にくいのでログを見やすくするために formatter を追加します

STEP1

custom-tslint-formatters をインストールします(npm での install は割愛)

$ yarn add --dev custom-tslint-formatters

STEP2

options に formatter と formattersDirectory を追加

modules/typescript.js
    const tslintLoader = {
      loader: path.resolve(__dirname, '_tslint-loader.js'),
      // tslint の linterOptions.exclude で除外ファイルを指定できますが、
      // コマンドラインから tslint を実行した場合のみ有効なので、下記で除外ファイルを指定する必要があリます
      exclude: /node_modules|\.nuxt/,
      enforce: 'pre',
      options: {
        configFile: 'tslint.json',
        // ↓ formatter と formattersDirectory オプションを追加
        formatter: 'grouped',
        formattersDirectory: 'node_modules/custom-tslint-formatters/formatters',
      }
    }

STEP3

Nuxtの開発環境を立ち上げて確認する。
lint の error 内容が見やすくなりました🎉
image.png

最後に

何か記事に間違いなどありましたらご指摘よろしくお願いします。
参考にしたURLをまとめておきます

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
What you can do with signing up
4