Webpack+ Vue2.5 引入 Typescript 全面指南

写在前面

写这篇文章时的我,Vue使用经验三个多月,Typescript完全空白,
花了大概三个晚上把手头项目迁移至Typescript,因此这篇文章更像个入门指引。

总原则

两大原则:

最小依赖引入

由于我个人从Javascript到Typescript的升级,更倾向于平滑顺移,因此,我对新依赖的引入整体保持克制原则,只引入了必要项,以尽量贴近原生vue写法:

  • typescript
  • ts-loader

以下依赖均未引入:

  • vue-class-component:官方维护,学习成本小,但与vuex融合性较差,计划等官方完善对vuex支持后再考虑引入
  • vue-property-decorator:非官方维护,一定学习成本
  • vuex-class:非官方维护,在 vue-class-component 基础上补充一定vuex支持(支持有限)
  • vuex-ts-decorators/vuex-typescript等:非官方维护,学习成本极高

PS: 后总结,vue官方维护的 vue-class-component 还是很有必要引入的,文末有详细说明。PS: tslint-loader由于对vue的支持尚不完美,作为可选项文末有详细说明。

既然用了 Typescript,不到万不得已不用 any!

any 任意类型的存在,在我看来就是个潘多拉魔盒,一旦开启,很容易养成偷懒的习惯,碰到难题就上 any。因此,我的建议是,尽量不要去碰它,除非你无路可走。

Vue-cli 生成项目启用 Typescript

注:这里只介绍Webpack模板下使用。

vue init webpack <项目名称> 生成的项目需做如下改动以兼容 Typescript:

依赖安装

npm i --save-dev typescript ts-loader 安装必要依赖。推荐使用 npm 8及以上版本。

Webpack 配置

./build/webpack.base.conf.js,作如下改动:

  • entry入口文件main.js改为main.ts

entry: {

  app: './src/main.ts'

}

  • resolve.extensions添加.ts

resolve: {

  extensions: ['.js', '.ts', '.vue', '.json']

}

  • module.rules添加.ts解析规则:

module: {

  rules: [

    {

      test: /\.tsx?$/,

      loader: 'ts-loader',

      exclude: /node_modules/,

      options: {

        appendTsSuffixTo: [/\.vue$/]

      }

    }

  ]

}

tsconfig.json

项目根路径下添加文件tsconfig.json,官方推荐配置如下:

// tsconfig.json

{

  "compilerOptions": {

    // 与 Vue 的浏览器支持保持一致

    "target": "es5",

    // 这可以对 `this` 上的数据属性进行更严格的推断

    "strict": true,

    // 如果使用 webpack 2+ 或 rollup,可以利用 tree-shake:

    "module": "es2015",

    "moduleResolution": "node"

  }

}

vue-shim.d.ts

src目录下添加文件vue-shim.d.ts

declare module "*.vue" {

  import Vue from "vue";

  export default Vue;

}

意思是告诉TypeScript *.vue后缀的文件可以交给vue模块来处理。

.js 文件重命名为 .ts 文件

src/main.js开始,包括src/router/index.js等逐一从.js重命名为.ts

注意:重命名后对vue文件的import,需添加.vue后缀

因为Typescript默认只识别*.ts文件,不识别*.vue文件

之前:

import App from './App'

import HelloWorld from '@/components/HelloWorld'

需改为:

import App from './App.vue'

import HelloWorld from '@/components/HelloWorld.vue'

.vue 文件改造

要点:

  • npm run dev

    至此运行项目,即可正常运行,vue对typescript的初步引入,基本完成。

    TSLint

    2017-12-6更新:
    当前(2017年12月),对.vue文件,VSCode编辑器的编辑时提示,有了一个非官方方案(官方进度见以下issue,仍均未解决),TSLint Vue。

    简单讲,一给力小哥 Fork 了 VSCode 官方的 TSLint插件,添加了对 Vue 文件的支持。小哥更新蛮频繁的,基本上第一时间跟随官方插件的最新版,亲测可用。

    使用方式:VSCode Plugin,关闭 TSLint,下载并启用 TSLint Vue即可:


    当前(2017年11月),对.vue文件,可以在关闭no-consecutive-blank-lines检查前提下,开启构建时TSLint支持;至于VSCode编辑器的编辑时提示,完全没有。

    详见TSLint的 issue 及vetur的 issue

    不幸的是,也不能拿ESLint将就用,不然一堆如下的Error等着你:
    Webpack+ Vue2.5 引入 Typescript 全面指南_第1张图片

    所以,只剩俩选择,要么关了,要么按照下面的配置将就着用:

    • 添加依赖

    npm i --save-dev tslint tslint-loader tslint-config-standard

    • module.rules移除eslint-loader,添加tslint-loader预处理

    // ./build/webpack.base.conf.js

    module: {

      rules: [

        // {

        //   test: /\.(js|vue)$/,

        //   enforce: 'pre',

        //   exclude: /node_modules/,

        //   use: {

        //     loader: 'eslint-loader',

        //     options: {

        //       formatter: require('eslint-friendly-formatter')

        //     }

        //   }

        // },

        {

          test: /\.ts$/,

          exclude: /node_modules/,

          enforce: 'pre',

          loader: 'tslint-loader'

        },

        {

          test: /\.vue$/,

          loader: 'vue-loader',

          options: vueLoaderConfig

        },

      ]

    }

    • vue-loader中开启tslint-loader选项:

    // ./build/vue-loader.conf.js

     

    const merge = require('webpack-merge')

     

    module.exports = {

      loaders: merge(utils.cssLoaders({

          sourceMap: isProduction

            ? config.build.productionSourceMap

            : config.dev.cssSourceMap,

          extract: isProduction

        }), {

          ts: ['ts-loader', 'tslint-loader']

        }

      ),

      ... // 其他内容

    }

    • 项目根路径下添加文件tslint.json

    // tslint.json

    {

      "extends": "tslint-config-standard",

      "globals": {

        "require": true

      },

      "rules": {

        "no-consecutive-blank-lines": false

      }

    }

    no-consecutive-blank-lines 关闭的解释 见这里

    简单翻译,vue-loadertslint-loader结合使用,就像是把.vue文件里的