vue项目引入ts步骤(小结)


Posted in Javascript onOctober 31, 2019

最近考虑到老项目代码的可维护性以及稳定性,决定引入ts做规范检测。因为介绍的东西比较基础,如果介绍的不对,麻烦指正。

1. 简介

TypeScript 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持。网上关于ts的学习资料很多,这里不做详细介绍。可参考的学习网站:

ts.xcatliu.com/

typescript.bootcss.com/

2. 安装依赖包

cnpm i typescript ts-loader --save-dev

3. 添加tsconfig.json文件

在项目根目录下添加 tsconfig.json 文件。tsconfig.json 文件用来指定ts的编译选项。配置可参考:

https://typescript.bootcss.com/tsconfig-json.html

项目工程 tsconfig.json 文件配置如下:(仅做参考)

{
  "compilerOptions": {
    "baseUrl": ".",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "noEmitOnError": true,
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "allowJs": true,
    "noEmit": false,
    "noImplicitThis": true,
    "esModuleInterop": true,
    "sourceMap": true,
    "moduleResolution": "node"
  },
  "include": [
    "src/**/*", "types"
  ],
  "exclude": [
    "node_modules",
    "build"
  ]
}

4. webpack打包配置修改

webpack.config.js 打包文件修改,新增对.ts文件的打包配置。

4.1 入口文件后缀名由.js修改为.ts

module.exports = {
  entry: {
    app: ['@babel/polyfill', './src/main.ts']
  }
}

4.2 extensions 文件扩展名增加 .ts, .tsx 文件的支持

tsx针对react项目文件的支持,因为我们的工程基于vue开发,支持.ts文件就可以了。

module.exports = {
  resolve: {
    extensions: ['.js', '.vue', '.json', '.css', '.ts']
  }
}

4.3 loader增加对ts文件的支持

使用ts-loader来转换ts文件。

module.exports = {
  module: {
    rules: [
      {
        test: /\.ts?$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
        options: {
         appendTsSuffixTo: [/\.vue$/],
        }
      }
    ]
  }
}

5. eslint 添加对ts文件的检测

5.1 安装依赖包

cnpm i @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-typescript eslint-plugin-typescript --save-dev

@typescript-eslint/parser ts文件解析器

@typescript-eslint/eslint-plugin 版本号需要与@typescript-eslint/parser的版本一致,解析器相关的配置选项

eslint-config-typescript 针对ts项目配置的eslint检测规范

5.2 .eslintrc配置文件修改

.eslintrc配置文件修改,支持对ts的文件的校验。经过多次调整,我们工程的 .eslintrc 配置文件如下:

{
  "parserOptions": {
    "parser": "@typescript-eslint/parser",
    "project": "./tsconfig.json",
    "extraFileExtensions": [".vue"],
    "ecmaVersion": 2017,
    "sourceType": "module",
    "ecmaFeatures": {
      "modules": true
    }
  },
  "env": {
   "jest": true,
   "browser": true
  },
  "settings": {
   "import/resolver": {
    "node": {
     "extensions": [".js", ".jsx", ".ts", ".tsx", ".eslintrc"]
    },
    "webpack": {
     "config": {
      "resolve": {
       "alias": {
        "src": "src"
       }
      }
     }
    }
   }
  },
  "plugins": [
    "vue",
    "babel",
    "@typescript-eslint"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:vue/base",
    "typescript",
    "standard"
  ],
  "rules": {
    "func-names": 0,
    "one-var": [1, "never"],
    "prefer-const": 1,
    "no-unused-expressions": 1,
    "new-cap": 2,
    "prefer-arrow-callback": 2,
    "arrow-body-style": 0,
    "max-len": [
      1,
      {
      "code": 200,
      "ignoreStrings": true,
      "ignoreUrls": true,
      "ignoreRegExpLiterals": true
      }
    ],
    "consistent-return": "off",
    "default-case": 2,
    "prefer-rest-params": 2,
    "no-script-url": 0,
    "no-console": [
      2,
      {
      "allow": ["info", "error", "warn", "log"]
      }
    ],
    "no-duplicate-imports": 2,
    "newline-per-chained-call": 2,
    "no-underscore-dangle": 2,
    "eol-last": 2,
    "no-useless-rename": 2,
    "class-methods-use-this": 0,
    "prefer-destructuring": 0,
    "no-unused-vars": 0,
    "@typescript-eslint/no-unused-vars": 1,
    "no-plusplus": 0,
    "import/prefer-default-export": 0,
    "import/no-dynamic-require": 2,
    "@typescript-eslint/no-var-requires": 2,
    "no-use-before-define": [
      "error",
      {
      "functions": false
      }
    ],
    "@typescript-eslint/no-use-before-define": 0,
    "@typescript-eslint/explicit-function-return-type": 0,
    "@typescript-eslint/interface-name-prefix": 0,
    "no-invalid-this": 0,
    "babel/no-invalid-this": 2,
    "no-await-in-loop": "off",
    "array-callback-return": "off",
    "no-restricted-syntax": "off",
    "@typescript-eslint/no-explicit-any": 0,
    "import/no-extraneous-dependencies": 0,
    "import/no-unresolved": 0,
    "@typescript-eslint/explicit-member-accessibility": 0,
    "@typescript-eslint/no-object-literal-type-assertion": 0,
    "no-param-reassign": [
      2,
      {
      "props": false
      }
    ],
    "generator-star-spacing": "off",
    "indent": [2, 4, {
      "SwitchCase": 1
    }],
    "eqeqeq": 0,
    "no-else-return": 2,
    "arrow-parens": 0,
    "space-before-function-paren": ["error", "never"],
    "comma-dangle": [2, "never"],
    "semi": [2, "always"]
  }
 }

注意"extends": ["plugin:vue/base"], 只能选择vue/base,不能用vue/recommend。不然会有规则冲突。

6. 项目文件转换

项目配置好后,开始对老代码进行改造,来支持ts的语法检测。

6.1 增加ts声明文件目录

项目中总会依赖一些资源包,或是自己开发的一些组件,这些文件需要补充声明文件,声明文件就是将多个声明语句放在一起,这些声明文件可统一放到一个目录里。这个目录需要包含在 tsconfig.json 文件的include里。

ms工程在根目录下新建 types 目录,目前包含 vue.d.ts, request.d.ts, dialog.d.ts, base.d.ts 等文件。

6.2 全局vue.d.ts声明文件

需要在ts环境下识别vue文件,需要添加 vue.d.ts 全局声明文件,例子如下:

import VueRouter, { Route } from 'vue-router';
import RequestAxios from './request';

declare module '*.vue' {
  import Vue from 'vue';
  export default Vue;
}
declare module 'vue/types/vue' {
  interface Vue {
    $router: VueRouter;
    $route: Route;
    $request: RequestAxios;
    ....
  }
}

6.2 vue文件的改造

vue文件的改造,只改造js部分,代码大致修改如下:

import { Vue, Component, Prop, Watch } from 'vue-property-decorator';

@Component({
  components: {
    ....
  }
})
export default class MyComponent extends Vue {
  // prop
  @Prop({ default: () => {} }) readonly pageInfo !: any

  // data
  private showAnimation : boolean = true;

  // watch
  @Watch('showModuleIndex')
  onShowModuleIndexChanged(newValue: any) {
    this.$emit('input', newValue);
  }

  // computed
  get list() {
    const { page, cityList } = this;
    return page.cityList.split(',').map(
      cityId => cityList.find(c => String(c.id) === cityId)
    );
  }

  // mounted
  private mounted() :void {
    this.initEditor();
  }

  // methods
  private initEditor() :void {
    ....
  }
}
</script>

6.3 js文件的改造

将文件后缀名更改为.ts,然后加上类型就可以了。

7. 踩坑总结

大部分都是eslint校验时的报错,按照提示修复就可以了。

"vue/html-indent": [2, 4] eslint这条规则去掉

"plugin:vue/base"与"plugin:vue/recommend"的区别

...

8. 总结

项目改造过程中,大部分时间都是在查配置兼容问题,配置这块解决了,改造起来速度还是挺快的。虽然前期会有一些改造成本,但是长远来看,还是有意义的。毕竟很多代码类型上的问题在开发阶段就可以暴露,不用等到运行时才发现了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 动态将数字金额转化为中文大写金额
May 14 Javascript
jQuery(1.3.2) 7行代码搞定跟随屏幕滚动的层
May 21 Javascript
Javascript之旅 对象的原型链之由来
Aug 25 Javascript
juqery 学习之五 文档处理 包裹、替换、删除、复制
Feb 11 Javascript
js实现俄罗斯方块小游戏分享
Jan 31 Javascript
JavaScript实现购物车基本功能
Jul 21 Javascript
详解在Vue中有条件地使用CSS类
Sep 30 Javascript
支付宝小程序自定义弹窗dialog插件的实现代码
Nov 30 Javascript
Flutter 超实用简单菜单弹出框 PopupMenuButton功能
Aug 06 Javascript
layui动态渲染生成select的option值方法
Sep 23 Javascript
javascript刷新父页面方法汇总详解
Oct 10 Javascript
序列化模块json代码实例详解
Mar 03 Javascript
微信小程序canvas分享海报功能
Oct 31 #Javascript
解决vue初始化项目时,一直卡在Project description上的问题
Oct 31 #Javascript
vue项目初始化到登录login页面的示例
Oct 31 #Javascript
vue3 源码解读之 time slicing的使用方法
Oct 31 #Javascript
vue data恢复初始化数据的实现方法
Oct 31 #Javascript
vue和iview实现Scroll 数据无限滚动功能
Oct 31 #Javascript
vue 使用鼠标滚动加载数据的例子
Oct 31 #Javascript
You might like
MySql 按时间段查询数据方法(实例说明)
2008/11/02 PHP
Codeigniter校验ip地址的方法
2015/03/21 PHP
php实现数组中出现次数超过一半的数字的统计方法
2018/10/14 PHP
身份证号码前六位所代表的省,市,区, 以及地区编码下载
2007/04/12 Javascript
类之Prototype.js学习
2007/06/13 Javascript
Javascript 判断是否存在函数的方法
2013/01/03 Javascript
JQuery的AJAX实现文件下载的小例子
2013/05/15 Javascript
jQuery根据用户电脑是mac还是pc加载对应样式的方法
2015/06/26 Javascript
全面解析Bootstrap中Carousel轮播的使用方法
2016/06/13 Javascript
vue2.0+webpack环境的构造过程
2016/11/08 Javascript
javascript 正则表达式分组、断言详解
2017/04/20 Javascript
javascript checkbox/radio onchange不能兼容ie8处理办法
2017/06/13 Javascript
AngularJS页面带参跳转及参数解析操作示例
2017/06/28 Javascript
深入理解React高阶组件
2017/09/28 Javascript
原生js实现trigger方法示例代码
2019/05/22 Javascript
基于vue和websocket的多人在线聊天室
2020/02/01 Javascript
jQuery 常用特效实例小结【显示与隐藏、淡入淡出、滑动、动画等】
2020/05/19 jQuery
python用reduce和map把字符串转为数字的方法
2016/12/19 Python
详解python使用Nginx和uWSGI来运行Python应用
2018/01/09 Python
对django xadmin自定义菜单的实例详解
2019/01/03 Python
Django的用户模块与权限系统的示例代码
2019/07/24 Python
Python操作SQLite数据库过程解析
2019/09/02 Python
浅谈Python爬虫原理与数据抓取
2020/07/21 Python
自定义Django_rest_framework_jwt登陆错误返回的解决
2020/10/18 Python
德国Discount-Apotheke中文官网:DC德式康线上药房
2020/02/18 全球购物
main 函数执行以前,还会执行什么代码
2013/04/17 面试题
大学生学习2014全国两会心得体会
2014/03/13 职场文书
广告词串烧
2014/03/19 职场文书
三好学生先进事迹材料
2014/08/28 职场文书
体育个人工作总结
2015/02/09 职场文书
大学升旗仪式主持词
2015/07/04 职场文书
python plt.plot bar 如何设置绘图尺寸大小
2021/06/01 Python
MySQL库表名大小写的选择
2021/06/05 MySQL
Python制作动态字符画的源码
2021/08/04 Python
MySQL事务操作的四大特性以及并发事务问题
2022/04/12 MySQL
Redis sentinel哨兵集群的实现步骤
2022/07/15 Redis