介绍
当前 typescript 在前端的使用已经越来越热,伴随前端工程越来越庞大,javascript 的弱语言的特点逐渐显露出了一些缺点。 但是现在的浏览器并不支持 TS 的语法,所以还是需要将 TS 最终编译成 JS 才能正常在浏览器中打开。
Vue 项目迁移 ts
安装依赖
Vue官方提供了一个库Vue-class-component,用于让我们使用Ts的类声明方式来编写vue组件代码。但是查看若干文章,都在使用 Vue-property-decorator 来使用,其中 vue-element-admin的 TS 版本也使用了这个在Vue-class-component的基础上提供了装饰器来编写,那么在迁移的过程我们便也不犹豫的使用了。 我的项目是基于vue-cli@4.X创建的,还需要在项目中引入支持 TS 的编译的依赖:
yarn add @vue/cli-plugin-typescript typescript --dev
配置 tsconfig.json 和 vue.config.js
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"node",
"jest",
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
这里边进行启动查看一下效果,发现启动报错:已经在src 目录下寻找 main.ts 文件了,而我想做的是一步步的迁移,main.ts 文件是最后才替换的。
* ./src/main.ts in multi (webpack)-dev-server/client?http://192.168.43.86:8080/sockjs-node (webpack)/hot/dev-server.js ./src/main.ts, multi (webpack)/hot/dev-server.js (webpack)-dev-server/client?http://192.168.43.86:8080/sockjs-node ./src/main.ts
Type checking in progress...
No type errors found
Version: typescript 3.8.3
Time: 4321ms
进而先移除掉 @vue/cli-plugin-typescript 组件,而添加只是编译 ts 的loader:
yarn add ts-loader --dev
增加配置文件 vue.config.js
'use strict'
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
const name = 'hello-world' // page title
// If your port is set to 80,
// use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
// You can change the port by the following method:
// port = 9527 npm run dev OR npm run dev --port = 9527
const port = 3000 // dev port
module.exports = {
publicPath: '/',
outputDir: 'dist',
assetsDir: 'static',
lintOnSave: process.env.NODE_ENV === 'development',
productionSourceMap: false,
devServer: {
port: port,
open: true,
overlay: {
warnings: false,
errors: true
}
},
configureWebpack: {
// provide the app's title in webpack's name field, so that
// it can be accessed in index.html to inject the correct title.
name: name,
resolve: {
alias: {
'@': resolve('src')
},
extensions: [".ts", ".tsx", ".js", ".json"]
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
}
}
]
}
}
}
添加之后可以正常启动。
文件之间的相互引用
vue 文件中引用 ts 文件
新建 ts 文件:
export const hello = '你好,这是在增加 ts-loader 之后增加的第一个 ts 文件'
class Person {
private name: string;
constructor (name:string) {
this.name = name
}
sayHi () {
return 'hi, ' + this.name
}
}
export const sayHello = (name: string) => {
let person = new Person(name)
return person.sayHi()
}
将该文件在 hello.vue 中引用:
<template>
<div>
{{helloConst}}----{{greeting}}
</div>
</template>
<script>
import { hello, sayHello } from './const'
export default {
name: 'hello',
data () {
return {
helloConst: hello
}
},
computed: {
greeting () {
return sayHello('张三')
}
}
}
</script>
重新启动后报错:
error in D:\workspace\vue\demo\hello-world\hello-world\tsconfig.json
[tsl] ERROR
TS2688: Cannot find type definition file for 'webpack-env'.
安装 webpack-env
yarn add @types/webpack-env
安装之后可以正常启动并渲染内容。
ts 文件中引用 ts 文件
Cat.ts
class Cat {
static miao() {
return 'miaomiao--可爱喵'
}
}
export default Cat
const.ts
import Cat from './Cat'
export const hello = '你好,这是在增加 ts-loader 之后增加的第一个 ts 文件'
class Person {
name: string;
constructor (name:string) {
this.name = name
}
sayHi () {
return 'hi, ' + this.name
}
}
export const sayHello = (name: string) => {
let person = new Person(name)
return person.sayHi()
}
export const miao = () => {
return Cat.miao()
}
hello.vue
<template>
<div>
{{helloConst}}----{{greeting}}
</div>
</template>
<script>
import { hello, sayHello, miao} from './const'
export default {
name: 'hello',
data () {
return {
helloConst: hello
}
},
computed: {
greeting () {
return sayHello('张三') + '====' + miao()
}
}
}
</script>
根据以上两步之后,在 vue 中引用 ts 文件和 ts 文件中引用 ts 文件已经是可以的了。然后就剩下要在 ts 文件中引用 vue 文件了。
ts 文件引用 vue 文件
本来想直接使用 router 下的 index.js 改为 ts 文件来实验这个内容。可是修改之后直接报错:
Module build failed (from ./node_modules/eslint-loader/index.js):
Error: ENOENT: no such file or directory, open 'D:\workspace\vue\demo\hello-world\hello-world\src\router\index.js'
@ ./src/main.js 8:0-30 15:10-16
@ multi (webpack)-dev-server/client?http://192.168.43.86:3000/sockjs-node (webpack)/hot/dev-server.js ./src/main.js
根据报错信息的显示,看来在main.js 文件中是无法引用 ts 文件的。
是js 文件中均无法引用 ts 文件吗???
在 hello 文件夹下新建:index.ts:
export { default as hello } from './hello.vue'
报错:
This relative module was not found:
* ./const in ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/hello/hello.vue?vue&type=script&lang=js&
Visual Studio 提示:
can not find module './hello.vue'
看来在 ts 文件中还无法引用 vue 组件,ts文件中是无法识别vue文件的,所以需要在项目根目录新建 shims-vue.d.ts 文件,添加以下代码,来让ts识别vue文件。
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
添加之后Visual Studio 的错误提示消失,在 ts 文件已经认识 vue 文件了。 但是编译的报错依然存在。 呃呃,经过查找是路径发生了变化,真是恶心了,现在 hello.vue 文件引用的 const.ts 的路径不对。修改后可以正常启动。
但是现在hello.vue 中需要渲染出来的内容却没有展示出来,可恶。 将新增的index.ts 修改为:
// export { default as hello } from './hello.vue'
// 引用的文件的写法是 import { hello } from "./hello/index", 不能在 router 的 component 下直接使用
import hello from './hello.vue'
export default hello
之后可以正常展示。这里真的是犯了一个很弱的错误,在 router 的 index.js 文件中,
export const constantRoutes = [
{
path: '/',
component: Layout,
redirect: '/hello',
children: [
{
path: '/hello',
component: () => import ('@/views/hello') // hello 里只能是倒出的一个组件
}
]
}
]
至此,文件之间的相互引用已经全部 ok 了。
改写 Vue 文件
将原来的vue文件改写成使用 vue-property-decorator 编写的方式。
安装依赖
yarn add vue-property-decorator
新建文件 about.vue
<template>
<div>
{{msg}}
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
export default class about extends Vue {
@Prop({default: 'about......'}) private msg!: string;
}
</script>
页面可以正常显示信息,但是一只在报编译错误:
Module Warning (from ./node_modules/eslint-loader/index.js):
D:\workspace\vue\demo\hello-world\hello-world\src\views\about.vue
11:0 error Parsing error: Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.
2 | import { Component, Prop, Vue } from 'vue-property-decorator';
3 | @Component
> 4 | export default class about extends Vue {
| ^
5 | @Prop({default: 'about......'}) private msg!: string;
6 | }
增加 .eslintrc.js 文件后,报错消失。 这个文件中需要确定在 package.json 的 dev 中存在依赖:"@typescript-eslint/parser","@typescript-eslint/eslint-plugin"
module.exports = {
parser: '@typescript-eslint/parser', //定义ESLint的解析器
extends: ['plugin:@typescript-eslint/recommended'],//定义文件继承的子规范
plugins: ['@typescript-eslint'],//定义了该eslint文件所依赖的插件
env:{ //指定代码的运行环境
browser: true,
node: true,
}
}