# Vue3与TSX尝鲜版
## 涉及到的主要依赖
1. `vite@2.0.4`
2. `vue@3.0.7`
3. `vuex@4.0.0`
4. `vue-router@4.0.4`
5. `typescript@4.2.2`

## 准备工作
1. 确保安装`yarn`
```bash
npm install yarn -g
```
2. 确保安装`vite`脚手架
```bash
npm install -g create-vite-app
# or
yarn add -g create-vite-app
```

## 开始
### 项目初始化
```bash
yarn create vite-app <project-name>
```

### 集成TS
```bash
yarn add --dev typescript
```
项目根目录创建配置文件：`tsconfig.json`：
```js
{
  "include": ["./**/*.ts"],
  "compilerOptions": {
    "jsx": "react",
    "target": "es2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
    "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
    // "lib": ["es2017.object"] /* Specify library files to be included in the compilation. */,
    // "declaration": true /* Generates corresponding '.d.ts' file. */,
    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
    "sourceMap": true /* Generates corresponding '.map' file. */,
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
    "outDir": "./dist" /* Redirect output structure to the directory. */,

    "strict": true /* Enable all strict type-checking options. */,
    "noUnusedLocals": true /* Report errors on unused locals. */,
    "noImplicitReturns": true /* Report error when not all code paths in function return a value. */,

    "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
    "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
  }
}
```

### 集成eslint
```bash
yarn add --dev eslint eslint-plugin-vue
```
项目根目录创建配置文件`.eslintrc.js`：
```js
module.exports = {
  parser: 'vue-eslint-parser',
  parserOptions: {
    parser: '@typescript-eslint/parser', // Specifies the ESLint parser
    ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
    sourceType: 'module', // Allows for the use of imports
    ecmaFeatures: {
      // tsx: true, // Allows for the parsing of JSX
      jsx: true,
    },
  },
  // settings: {
  //   tsx: {
  //     version: "detect" // Tells eslint-plugin-react to automatically detect the version of React to use
  //   }
  // },
  extends: [
    'plugin:vue/vue3-recommended',
    'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
    'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
    'plugin:prettier/recommended', // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
  ],
  rules: {
    // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
    // e.g. "@typescript-eslint/explicit-function-return-type": "off",
  },
};
```

### 集成pritter
```bash
yarn add --dev prettier eslint-config-prettier eslint-plugin-prettier
```
项目根目录创建配置文件：`.prettierrc.js`：
```js
module.exports = {
  semi: true,
  trailingComma: "all",
  singleQuote: true,
  printWidth: 100,
  tabWidth: 2,
  endOfLine:"auto"
};
```

到这一步，一个Vue3+TSX的项目就搭建起来了，以上配置文件的具体内容就不做解释了。

### 修改入口文件
因为默认项目模板是以`src/main.js`为入口的，我们需要把它修改为`src/main.ts`。  
在`根目录的index.html`中修改入口文件的引用即可：
```html
... ...
<body>
  ... ...
  <script type="module" src="/src/main.ts"></script>
</body>
</html>

```

### 优化TS类型推断
在src目录下，创建`shim.d.ts、source.d.ts`  

`shim.d.ts`: (这个其实不太需要，因为项目中全是通过tsx开发的)
```ts
declare module '*.vue' {
  import Vue from 'vue';
  export default Vue;
}
```
`source.d.ts`: (优化编译器提示，声明静态资源文件)
```ts
declare const React: string;
declare module '*.json';
declare module '*.png';
declare module '*.jpg';
```

### 集成vue-router
```bash
yarn add --dev vue-router@4.0.4
```
这里可以去`npm官网`查找最新版本  
在src目录下，`新建router文件夹`，并在文件夹内`创建index.ts`
`index.ts`:
```js
import { RouteRecordRaw, createRouter, createWebHistory } from 'vue-router';

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'Home',
    component: () => import('../views/Home'),
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About'),
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

```  
这里创建router的方式与之前不同，在vue3中，结合TS的类型推断，开发效率会高很多。  

### 集成vuex

```bash
yarn add --dev vuex@4.0.0
```
在src目录下，新建store文件夹，并在文件夹内创建`index.ts`  

`index.ts`:  
```js
import { state } from './state';
import { createStore } from 'vuex';

export default createStore({
  state,
  mutations: {},
  actions: {},
  modules: {},
});
```
`state.js`:
```js
export interface State {
  title: string;
}

export const state: State = {
  title: 'Vue(v3) 与 tsx 的结合~',
};
```
### main.ts
最终main.ts中引入store、router：
```js
import { createApp } from 'vue';
import App from './App';
import router from './router';
import store from './store';

createApp(App).use(router).use(store).mount('#app');
```  
### TSX
最终我们的组件代码，都会是这样的：`App.tsx`:  
```js
import { defineComponent } from 'vue';
import {RouterLink, RouterView} from 'vue-router';
import './style/main.scss'

export default defineComponent({
  name: 'App',
  setup() {
    return () => (
      <>
        <div id="nav">
          <RouterLink to="/">Home</RouterLink> |
          <RouterLink to="/about">About</RouterLink>
        </div>
        <RouterView/>
      </>
    );
  }
});
```  
自我感觉TSX比模板好多了，并且html、组件标签的属性都带有类型推断。

## 结尾
vue3正式版的发布，势必导致vue2的周边框架的集体更新，例如UI框架、基于Vue2的指令库等，作为这么久的白嫖党，也要为vue3社区的建设出一份力了。
  
   
Vue3与TS的结合是大趋势，如果不适应TS，那还是建议使用Vue2吧。23333~
  

后续博主也将研究vite框架和vue3全家桶的新特性与API，争取输出有质量的文档。  
***
参考文章： [https://github.com/hyperMoss/vue-tsx](https://github.com/hyperMoss/vue-tsx)
