はじめに
単一ファイルコンポーネント(.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 install --save-dev tslint tslint-loader loader-utils vue-parser
$ 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/ ディレクトリーへ置きます。
$ cp node_modules/tslint-loader/index.js modules/_tslint-loader.js
node_modules/tslint-loader/formatters/ の customFormatter.js も modules/ にコピーしておく
(無いと後々エラーになるため)
$ cp node_modules/tslint-loader/formatters/customFormatter.js modules/formatters/customFormatter.js
コピーした _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);
};
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 を修正します。
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")
}
})
}
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 ファイルを作成する
$ touch 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の開発環境を立ち上げてみましょう。
# yarn
$ yarn run dev
# npm
$ npm run dev
オプション
tslint は正常に動作するようになったものの、
少し見にくいのでログを見やすくするために formatter を追加します
STEP1
custom-tslint-formatters をインストールします(npm での install は割愛)
$ yarn add --dev custom-tslint-formatters
STEP2
options に formatter と formattersDirectory を追加
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 内容が見やすくなりました🎉
最後に
何か記事に間違いなどありましたらご指摘よろしくお願いします。
参考にしたURLをまとめておきます