# BSDN-PORTAL搭建

## 1、环境准备

环境：nodejs

配置方式：[环境配置地址](https://www.cnblogs.com/coder-lzh/p/9232192.html)

安装vite，创建bsdn-portal项目。[官网](https://vitejs.cn/guide/#scaffolding-your-first-vite-project)

开发工具

```
WebStorm 2021.3.2
创建文件快捷键 ctrl+alt+inert
pretier快捷键： Ctrl+alt+shift+p  alt+f
```

安装yarn

```sh
# Node.js >=16.10
corepack enable
# Node.js <16.10
npm i -g corepack
```

在D盘创建yarn文件夹，设置yarn的全局文件夹和缓存地址

```
yarn config set global-folder "D:\yarn\global"
yarn config set cache-folder "D:\yarn\cache"
```

在E盘创建文件夹

```
E:\vue_code
```

打开命令框，创建vite项目

```
yarn create vite
```

项目名为：vue3-starter，选择vue-ts版本

安装pnpm，[官网](https://www.pnpm.cn/installation)pnpm - 速度快、节省磁盘空间的软件包管理器，windows(power shell)上进行安装

```
npm install -g pnpm
```

进入项目目录，进行安装，启动

```
cd vue3-starter
pnpm i
yarn dev
```

安装路由

```
pnpm add vue-router@4
```

安装pretter + eslint

```
pnpm i prettier eslint eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue vue-eslint-parser @typescript-eslint/eslint-plugin @typescript-eslint/parser -D
```

配置.eslintrc.json

```json
{
  "root": true,
  "env": {
    "es2021": true,
    "node": true,
    "browser": true
  },
  "globals": {
    "node": true
  },
  "extends": [
    //    "plugin:vue/essential",
    /** @see https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#recommended-configs */
    //    "plugin:@typescript-eslint/recommended",
    //    "eslint:recommended",
    "plugin:vue/vue3-recommended",
    /**@see https://github.com/prettier/eslint-plugin-prettier#recommended-configuration */
    "plugin:prettier/recommended"
  ],
  "parser": "vue-eslint-parser",
  "parserOptions": {
    "parser": "@typescript-eslint/parser",
    "ecmaVersion": 12,
    "sourceType": "module"
  },
  "plugins": ["@typescript-eslint"],
  "ignorePatterns": ["types/env.d.ts", "node_modules/**", "**/dist/**"],
  "rules": {
    "@typescript-eslint/no-unused-vars": "error",
    "@typescript-eslint/no-var-requires": "off",
    "@typescript-eslint/consistent-type-imports": "error",
    "@typescript-eslint/explicit-module-boundary-types": "off",
    "vue/singleline-html-element-content-newline": "off",
    "vue/multiline-html-element-content-newline": "off",
    "vue/no-v-html": "off",

    //    "space-before-blocks": "warn",
    //    "space-before-function-paren": "error",
    //    "space-in-parens": "warn",
    //    "no-whitespace-before-property": "off",
    /**
     * Having a semicolon helps the optimizer interpret your code correctly.
     * This avoids rare errors in optimized code.
     * @see https://twitter.com/alex_kozack/status/1364210394328408066
     */
    "semi": ["error", "always"]
    /**
     * This will make the history of changes in the hit a little cleaner
     */
    //    "comma-dangle": ["warn", "always-multiline"],
    /**
     * Just for beauty
     */
    //    "quotes": ["warn", "single"]
  }
}
```

配置.editorconfig

```
root = true

[*]
charset = utf-8
# end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
ij_html_quote_style = double
max_line_length = 120
tab_width = 2
trim_trailing_whitespace = true
```

配置.prettierrc.json

```json
{
  "printWidth": 100,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "vueIndentScriptAndStyle": true,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "bracketSpacing": true,
  "trailingComma": "es5",
  "jsxBracketSameLine": true,
  "jsxSingleQuote": false,
  "arrowParens": "always",
  "insertPragma": false,
  "requirePragma": false,
  "proseWrap": "never",
  "htmlWhitespaceSensitivity": "ignore",
  "endOfLine": "auto",
  "rangeStart": 0
}
```

在src目录下创建pages目录，目录下创建`Front.vue`和 `Admin.vue` 文件

Admin.vue

```
<script lang="ts" setup="setup">
  import { ref } from 'vue';
</script>

<template>Admin</template>

<style lang="sass" scoped></style>
```

Front.vue

```
<script lang="ts" setup="setup">
  import { ref } from 'vue';
</script>

<template>Front</template>

<style lang="sass" scoped></style>
```

在src目录下创建route目录

目录下创建index.ts文件，用来做总的路由管理页面

index.ts内容如下

```tsx
import type { RouteRecordRaw } from 'vue-router';
import { createRouter, createWebHistory } from 'vue-router';
const routes: RouteRecordRaw[] = [];
//使用vite3 https://vitejs.cn/guide/features.html#glob-import
const modules = import.meta.globEager('./module/*.ts');
for (const path in modules) {
  routes.push(...modules[path].default);
}
const router = createRouter({
  history: createWebHistory(),
  routes: routes,
});

export default router;
```

在src目录下创建module文件夹，module文件里创建front.ts文件和admin.ts文件，用来做各自的路由文件

front.ts文件内容如下

```tsx
import type { RouteRecordRaw } from 'vue-router';

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    component: () => import('../../pages/Front.vue'),
  },
];
export default routes;
```

admin.ts文件内容如下

```tsx
import type { RouteRecordRaw } from 'vue-router';

const routes: RouteRecordRaw[] = [
  {
    path: '/admin',
    component: () => import('../../pages/Admin.vue'),
  },
];
export default routes;
```

修改src下main.js，添加路由信息，总的信息如下

```tsx
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
createApp(App).use(router).mount('#app');
```

修改src下的App.vue，文件内容如下

```tsx
<template>
  <router-view />
</template>
```

重启项目，分别访问地址以下地址验证改动情况

```
http://localhost:3000
http://localhost:3000/admin
```

## 2、使用piinio

```
pnpm add pinia
```

在main.ts引入pinia

```
import { createPinia } from 'pinia';
const pinia = createPinia();
app.use(pinia);
```

在`src`下创建`store`文件夹，在`store`文件夹下面创建`index.ts`的文件夹，在store创建module的文件夹，在module下面创建 `useCountStore.ts`文件,`useCountStore.ts`内容如下

```tsx
import { defineStore } from 'pinia';

const useCountStore = defineStore({
  id: 'count',
  state: () => ({ num: 1 }),
  actions: {
    increment() {
      this.num += 1;
    },
  },
});

export default useCountStore;
```

在`Front.vue`文件中进行引用文件，文件内容如下

```vue
<script lang="ts" setup="setup">
  import useCountStore from '../store/module/useCountStore';
  const countStore = useCountStore();
</script>

<template>
  <div>count: {{ countStore.num }}</div>
  <div><button @click="countStore.increment()">+1</button></div>
</template>

<style lang="sass" scoped></style>
```

### 2.1 刷新页面不更新状态

在`useCountStore.ts`下添加如下代码

```ts
//store
const instance = useCountStore();
//save
instance.$subscribe((_, state) => {
  localStorage.setItem('count-store', JSON.stringify({ ...state }));
});
//get
const old = localStorage.getItem('count-store');
if (old) {
  instance.$state = JSON.parse(old);
}
```

## 3、别名的配置

cmd查看node的版本

```
node -v
```

根据node的版本安装依赖

```
pnpm add @types/node@17.0.21 -D
```

修改vite.config.js，添加path以及其路径，全部的内容如下。`// --`中间的为新增的内容

```ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
// --
import * as path from 'path';
const resolve = (p) => {
  return path.resolve(__dirname, p);
};
// --

// https://vitejs.dev/config/
export default defineConfig({
    // --
  resolve: {
    alias: {
      '@': resolve('./src'),
    },
  },
  // --
  plugins: [vue()],
});

```

修改route中module中引用的page用@进行代替

如`admin.ts`

```ts
import type { RouteRecordRaw } from 'vue-router';

const routes: RouteRecordRaw[] = [
  {
    path: '/admin',
    component: () => import('@/pages/Admin.vue'),
  },
];
export default routes;
```

设置IDEA自动提示

例如在src下创建一个app文件夹，在app文件夹下创建`utils.ts`文件，内容如下

```
const add = (n: number) => {
  return n + 1;
};

export { add };
```

在Front.vue中的script中写add()会提示，按下会显示，不是用@进行引用的

```
import { add } from '../app/utils';
//书写的内容
add();
```

解决办法

在tsconfig.json中的compilerOptions里添加

```
    "baseUrl": ".",
    "paths": {
        "@/*": ["./src/*"]
    }
```

## 4、tailwindcss使用

安装scss，全局安装

```
 npm install -g node-sass --registry=https://registry.npm.taobao.org
```

配置webstorm scss lint，我的路径如下，可以用everything进行搜索

```
D:\Develop\nodejs\node_global\node-sass.cmd
```

安装：

```
pnpm install -D tailwindcss@latest postcss@latest autoprefixer@latest
```

接下来，生成您的 `tailwind.config.js` 和 `postcss.config.js` 文件：

```
npx tailwindcss init -p
```

在您的 `tailwind.config.js` 文件中，配置 `purge` 选项指定所有的 pages 和 components 文件，使得 Tailwind 可以在生产构建中对未使用的样式进行摇树优化。

```
   content: ['./public/**/*.html', './src/**/*.{js,ts,vue}'],
```

在assets-》style下创建文件app.scss内容为：

```
@tailwind base;
@tailwind components;
@tailwind utilities;
```

在main.ts里进行引用：

```
import '@/assets/styles/app.scss';
```

在Front.vue里进行使用，使用如图

```
<button class="bg-green-500 text-white rounded px-5 py-2" @click="countStore.increment()">
      +1
    </button>
```

## 5、安装element-plus

安装`element-plus`

```
pnpm install element-plus
```

自动导入

```
pnpm install -D unplugin-vue-components unplugin-auto-import
```

配置vite.config.ts

```tsx
// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default {
  plugins: [
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
}
```

在Front.vue中使用即可

```
<el-button>TT</el-button>
```

## 6、iconify图标库

地址 [https://icon-sets.iconify.design](https://icon-sets.iconify.design)

地址 [https://icones.js.org/collection/all](https://icones.js.org/collection/all)

iconify

```
pnpm add @iconify/iconify
pnpm add vite-plugin-purge-icons @iconify/json -D
```

```
//vite.config.ts
import PurgeIcons from 'vite-plugin-purge-icons';
export default defineConfig({
  plugins: [
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
    PurgeIcons({
      content: ['**/*.html', '**/*.js', '**/*.vue'],
    }),
    vue(),
  ],
});
```

```
//main.ts
import '@purge-icons/generated';
```

在Front.vue中使用

```
<div><span class="iconify" data-icon="system-uicons:fork-git"></span></div>
```

这样使用不算方便，可以定义一个component进行使用

使用方法，创建common文件夹，创建common文件夹后，创建AppIcon.vue，内容如下

```
<script lang="ts" setup="setup">
  const props = defineProps<{
    icon: string;
  }>();
</script>
<template>
  <span class="iconify" :data-icon="props.icon"></span>
</template>
<style lang="scss" scoped></style>
```

然后在Front.vue里，引入这个component

```
<app-icon icon="teenyicons:airpods-outline"></app-icon>
```

## 7、env的配置

在跟目录下创建.env的文件

```
VITE_API_URL=http://localhost:8080
```

在根目录下创建.env.production文件

```
VITE_API_URL=http://localhost:8081
```

就可以使用上述文件

typescript类型提示

在src目录下的env.d.ts文件里加入

```
//底部加入，在declare module下
interface ImportMetaEnv {
  readonly VITE_API_URL: string
  // 更多环境变量...
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}
```

在Front.vue的script中进行引用

```
console.log(import.meta.env.VITE_API_URL);
```

在打包的时候`yarn build`,production会把默认的给覆盖上

可以使用命令`http-server -o`来启动打包好的项目

安装它的命令为

```
npm install http-server -g
```

安装sass的命令

```
pnpm add sass
```

## 8、后台模板的搭建

