<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Vue3 全家桶 + TS+ Vite2 + element-plus 搭建簡潔時尚的博客網(wǎng)站實(shí)戰(zhàn)及踩坑記

          共 21510字,需瀏覽 44分鐘

           ·

          2021-05-08 08:57

          五一期間,花了 3 天時間,邊學(xué) Vue3 和 Vite2,邊重構(gòu)自己的項(xiàng)目,終于都用 Vue3 + TypeScript + Vite2 + Vuex4 + Vue-Router4 + element-plus 重構(gòu)完啦!

          終于完成一項(xiàng)心心念念的 2021 年度目標(biāo)了 ??

          項(xiàng)目地址:

          https://github.com/biaochenxuying/blog-vue-typescript

          效果

          效果圖:

          • pc 端
          • 移動端

          完整效果請看:

          https://biaochenxuying.cn

          功能

          已經(jīng)完成功能

          • [x] 登錄
          • [x] 注冊
          • [x] 文章列表
          • [x] 文章歸檔
          • [x] 標(biāo)簽
          • [x] 關(guān)于
          • [x] 點(diǎn)贊與評論
          • [x] 留言
          • [x] 歷程
          • [x] 文章詳情(支持代碼語法高亮)
          • [x] 文章詳情目錄
          • [x] 移動端適配
          • [x] github 授權(quán)登錄

          前端主要技術(shù)

          所有技術(shù)都是當(dāng)前最新的。

          • vue:^3.0.5
          • typescript : ^4.1.3
          • element-plus: ^1.0.2-beta.41
          • vue-router : ^4.0.6
          • vite: ^2.2.3
          • vuex: ^4.0.0
          • axios: ^0.21.1
          • highlight.js: ^10.7.2
          • marked:^2.0.3

          1. 初化化項(xiàng)目

          用 vite-app 創(chuàng)建項(xiàng)目

          yarn create vite-app <project-name>

          # 或者
          npm init vite-app <project-name>

          然后按照提示操作即可!

          進(jìn)入項(xiàng)目,安裝依賴

          cd <project-name>

          yarn # 或 npm i

          運(yùn)行項(xiàng)目

          yarn dev 

          打開瀏覽器 http://localhost:3000 查看

          2. 引入 TypeScript

          在創(chuàng)建項(xiàng)目的時候可以 TypeScript 的,如果你選擇了 TypeScript ,可以忽略第 2 個步驟。

          加入 ts 依賴

          yarn add --dev typescript

          在 項(xiàng)目根目錄下創(chuàng)建 TypeScript 的配置文件 tsconfig.json

          {
            "compilerOptions": {
              // 允許從沒有設(shè)置默認(rèn)導(dǎo)出的模塊中默認(rèn)導(dǎo)入。這并不影響代碼的輸出,僅為了類型檢查。
              "allowSyntheticDefaultImports"true,
              
              // 解析非相對模塊名的基準(zhǔn)目錄
              "baseUrl"".",

              "esModuleInterop"true,

              // 從 tslib 導(dǎo)入輔助工具函數(shù)(比如 __extends, __rest等)
              "importHelpers"true,

              // 指定生成哪個模塊系統(tǒng)代碼
              "module""esnext",

              // 決定如何處理模塊。
              "moduleResolution""node",

              // 啟用所有嚴(yán)格類型檢查選項(xiàng)。
              // 啟用 --strict相當(dāng)于啟用 --noImplicitAny, --noImplicitThis, --alwaysStrict, 
              // --strictNullChecks和 --strictFunctionTypes和--strictPropertyInitialization。
              "strict"true,

              // 生成相應(yīng)的 .map文件。
              "sourceMap"true,

              // 忽略所有的聲明文件( *.d.ts)的類型檢查。
              "skipLibCheck"true,

              // 指定ECMAScript目標(biāo)版本 
              "target""esnext",
              
              // 要包含的類型聲明文件名列表
              "types": [

              ],

              "isolatedModules"true,

              // 模塊名到基于 baseUrl的路徑映射的列表。
              "paths": {
                "@/*": [
                  "src/*"
                ]
              },
              // 編譯過程中需要引入的庫文件的列表。
              "lib": [
                "ESNext",
                "DOM",
                "DOM.Iterable",
                "ScriptHost"
              ]
            },
            "include": [
              "src/**/*.ts",
              "src/**/*.tsx",
              "src/**/*.vue",
              "tests/**/*.ts",
              "tests/**/*.tsx"
            ],
            "exclude": [
              "node_modules"
            ]
          }

          在 src 目錄下新加 shim.d.ts 文件

          /* eslint-disable */
          import type { DefineComponent } from 'vue'

          declare module '*.vue' {
            const component: DefineComponent<{}, {}, any>
            export default component
          }

          把 main.js 修改成 main.ts

          在根目錄,打開 Index.html

          <script type="module" src="/src/main.js"></script>
          修改為:
          <script type="module" src="/
          src/main.ts"></script>

          3. 引入 eslint

          安裝 eslint prettier 依賴

          @typescript-eslint/parser @typescr ipt-eslint/eslint-plugin 為 eslint 對 typescript 支持。

          yarn add --dev eslint prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue @typescript-eslint/parser @typescr ipt-eslint/eslint-plugin

          在根目錄下建立 eslint 配置文件:.eslintrc.js

          module.exports = {
            parser'vue-eslint-parser',
            parserOptions: {
              parser'@typescript-eslint/parser',
              ecmaVersion2020,
              sourceType'module',
              ecmaFeatures: {
                jsxtrue
              }
            },
            extends: [
              'plugin:vue/vue3-recommended',
              'plugin:@typescript-eslint/recommended',
              'prettier/@typescript-eslint',
              'plugin:prettier/recommended'
            ],
            rules: {
              '@typescript-eslint/ban-ts-ignore''off',
              '@typescript-eslint/explicit-function-return-type''off',
              '@typescript-eslint/no-explicit-any''off',
              '@typescript-eslint/no-var-requires''off',
              '@typescript-eslint/no-empty-function''off',
              'vue/custom-event-name-casing''off',
              'no-use-before-define''off',
              // 'no-use-before-define': [
              //   'error',
              //   {
              //     functions: false,
              //     classes: true,
              //   },
              // ],
              '@typescript-eslint/no-use-before-define''off',
              // '@typescript-eslint/no-use-before-define': [
              //   'error',
              //   {
              //     functions: false,
              //     classes: true,
              //   },
              // ],
              '@typescript-eslint/ban-ts-comment''off',
              '@typescript-eslint/ban-types''off',
              '@typescript-eslint/no-non-null-assertion''off',
              '@typescript-eslint/explicit-module-boundary-types''off',
              '@typescript-eslint/no-unused-vars': [
                'error',
                {
                  argsIgnorePattern'^h$',
                  varsIgnorePattern'^h$'
                }
              ],
              'no-unused-vars': [
                'error',
                {
                  argsIgnorePattern'^h$',
                  varsIgnorePattern'^h$'
                }
              ],
              'space-before-function-paren''off',
              quotes: ['error''single'],
              'comma-dangle': ['error''never']
            }
          };

          建立 prettier.config.js

          module.exports = {
            printWidth100,
            tabWidth2,
            useTabsfalse,
            semifalse// 未尾逗號
            vueIndentScriptAndStyletrue,
            singleQuotetrue// 單引號
            quoteProps'as-needed',
            bracketSpacingtrue,
            trailingComma'none'// 未尾分號
            jsxBracketSameLinefalse,
            jsxSingleQuotefalse,
            arrowParens'always',
            insertPragmafalse,
            requirePragmafalse,
            proseWrap'never',
            htmlWhitespaceSensitivity'strict',
            endOfLine'lf'
          }

          4. vue-router、vuex

          npm install vue-router@4 vuex

          4.1 vuex

          在根目錄下創(chuàng)建 store/index.ts

          import { InjectionKey } from 'vue'
          import { createStore, Store } from 'vuex'

          export interface State {
            count: number
          }

          export const key: InjectionKey<Store<State>> = Symbol()

          export const store = createStore<State>({
            state() {
              return {
                count: 0
              }
            },
            mutations: {
              increment(state) {
                state.count++
              }
            }
          })

          main.ts 修改

          import { createApp } from 'vue'
          import { store, key } from './store'
          import App from './App'
          import './index.css'

          const app = createApp(App)

          app.use(store, key)

          app.mount('#app')

          components/HelloWord.vue 修改

          <template>
            <h1>{{ msg }}</h1>
            <button @click="inCrement"> count is: </button>
            <p>{{ count }}</p>
          </template>

          <script>
            import { defineComponent, computed } from 'vue'
            import { useStore } from 'vuex'
            import { key } from '../store'

            export default defineComponent({
              name: 'HelloWorld',
              props: {
                msg: {
                  type: String,
                  default: ''
                }
              },
              setup() {
                const store = useStore(key)

                const count = computed(() => store.state.count)

                return {
                  count,
                  inCrement: () => store.commit('increment')
                }
              }
            })
          </script>

          4.2 vue-router

          在 src 目錄下建立 router/index.ts,內(nèi)容如下:

          import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
          import HelloWorld from "../components/HelloWorld.vue";

          const routes: Array<RouteRecordRaw> = [
              {
                  path"/",
                  name"HelloWorld",
                  component: HelloWorld,
              },
              {
                  path"/about",
                  name"About",
                  // route level code-splitting
                  // this generates a separate chunk (about.[hash].js) for this route
                  // which is lazy-loaded when the route is visited.
                  component() =>
                      import(/* webpackChunkName: "About" */ "../components/About.vue")
              }
          ];

          const router = createRouter({
              history: createWebHistory(process.env.BASE_URL),
              routes,
          });

          export default router;

          再新建一個 components/About.vue 文件,內(nèi)容如下:

          <template>
            <img
              alt="Vue logo"
              src="../assets/logo.png"
            />

            <h1>{{ msg }}</h1>
          </template>

          <script lang="ts">
          import { defineComponent } from 'vue'

          export default defineComponent({
            name: 'About',
            data() {
              return {
                msg: 'Hello Vue 3.0 + Vite!'
              }
            },
            setup() {}
          })
          </
          script>

          再修改 main.ts

          import { createApp } from 'vue'
          import { store, key } from './store'
          import router from "./router";
          import App from './App'
          import './index.css'

          const app = createApp(App)

          app.use(store, key)
          app.use(router)
          app.mount('#app')

          再訪問 http://localhost:3000/

          和 http://localhost:3000/about 即可

          5. 加入 Element Plus

          5.1 安裝 element-plus

          全局安裝

          npm install element-plus --save

          5.2 引入 Element Plus

          你可以引入整個 Element Plus,或是根據(jù)需要僅引入部分組件。我們先介紹如何引入完整的 Element。

          完整引入

          在 main.js 中寫入以下內(nèi)容:

          import { createApp } from 'vue'
          import ElementPlus from 'element-plus';
          import router from "./router";
          import 'element-plus/lib/theme-chalk/index.css';
          import App from './App.vue';
          import './index.css'

          const app = createApp(App)
          app.use(ElementPlus)
          app.use(router)
          app.mount('#app')

          以上代碼便完成了 Element Plus 的引入。需要注意的是,樣式文件需要單獨(dú)引入。


          按需引入

          借助 babel-plugin-component,我們可以只引入需要的組件,以達(dá)到減小項(xiàng)目體積的目的。

          首先,安裝 babel-plugin-component:

          npm install babel-plugin-component -D

          然后,將 .babelrc 修改為:

          {
            "plugins": [
              [
                "component",
                {
                  "libraryName""element-plus",
                  "styleLibraryName""theme-chalk"
                }
              ]
            ]
          }

          接下來,如果你只希望引入部分組件,比如 Button 和 Select,那么需要在 main.js 中寫入以下內(nèi)容:

          import { createApp } from 'vue'
          import { store, key } from './store';
          import router from "./router";
          import { ElButton, ElSelect } from 'element-plus';
          import App from './App.vue';
          import './index.css'

          const app = createApp(App)
          app.component(ElButton.name, ElButton);
          app.component(ElSelect.name, ElSelect);

          /* or
           * app.use(ElButton)
           * app.use(ElSelect)
           */


          app.use(store, key)
          app.use(router)
          app.mount('#app')
          app.mount('#app')

          更詳細(xì)的安裝方法請看 快速上手。

          5.3 全局配置

          在引入 Element Plus 時,可以傳入一個全局配置對象。

          該對象目前支持 size 與 zIndex 字段。size 用于改變組件的默認(rèn)尺寸,zIndex 設(shè)置彈框的初始 z-index(默認(rèn)值:2000)。按照引入 Element Plus 的方式,具體操作如下:

          完整引入 Element:

          import { createApp } from 'vue'
          import ElementPlus from 'element-plus';
          import App from './App.vue';

          const app = createApp(App)
          app.use(ElementPlus, { size'small'zIndex3000 });

          按需引入 Element:

          import { createApp } from 'vue'
          import { ElButton } from 'element-plus';
          import App from './App.vue';

          const app = createApp(App)
          app.config.globalProperties.$ELEMENT = option
          app.use(ElButton);

          按照以上設(shè)置,項(xiàng)目中所有擁有 size 屬性的組件的默認(rèn)尺寸均為 'small',彈框的初始 z-index 為 3000。

          5.4 配置 vite.config.ts

          其中 proxy 和 alias 是和 vue-cli 區(qū)別比較大的地方。

          import { defineConfig } from 'vite'
          import vue from '@vitejs/plugin-vue'
          import styleImport from 'vite-plugin-style-import'
          import path from 'path'

          // https://vitejs.dev/config/
          export default defineConfig({
            plugins: [
              vue(),
              styleImport({
                libs: [
                  {
                    libraryName'element-plus',
                    esModuletrue,
                    ensureStyleFiletrue,
                    resolveStyle(name) => {
                      return `element-plus/lib/theme-chalk/${name}.css`;
                    },
                    resolveComponent(name) => {
                      return `element-plus/lib/${name}`;
                    },
                  }
                ]
              })
            ],

            /**
             * 在生產(chǎn)中服務(wù)時的基本公共路徑。
             * @default '/'
             */

            base'./',
            /**
            * 與“根”相關(guān)的目錄,構(gòu)建輸出將放在其中。如果目錄存在,它將在構(gòu)建之前被刪除。
            * @default 'dist'
            */

            // outDir: 'dist',
            server: {
              // hostname: '0.0.0.0',
              host"localhost",
              port3001,
              // // 是否自動在瀏覽器打開
              // open: true,
              // // 是否開啟 https
              // https: false,
              // // 服務(wù)端渲染
              // ssr: false,
              proxy: {
                '/api': {
                  target'http://localhost:3333/',
                  changeOrigintrue,
                  wstrue,
                  rewrite(pathStr) => pathStr.replace('/api''')
                },
              },
            },
            resolve: {
              // 導(dǎo)入文件夾別名
              alias: {
                '@': path.resolve(__dirname, './src'),
                views: path.resolve(__dirname, './src/views'),
                components: path.resolve(__dirname, './src/components'),
                utils: path.resolve(__dirname, './src/utils'),
                less: path.resolve(__dirname, "./src/less"),
                assets: path.resolve(__dirname, "./src/assets"),
                com: path.resolve(__dirname, "./src/components"),
                store: path.resolve(__dirname, "./src/store"),
                mixins: path.resolve(__dirname, "./src/mixins")
              },
            }
          })

          踩到坑

          npm run dev 打包時不報錯,但是在 npm run build 時卻報錯了,build 的時候會把 node_modules 里面的文件也編譯,所以挺多 element-plus 的類型文件報錯了。

          tsconfig.json 里面的 includeexclude 修改一下就不會了,配置如下

          {
            "compilerOptions": {
              "target""esnext",
              "module""esnext",
              "moduleResolution""node",
              "strict"true,
              "jsx""preserve",
              "sourceMap"true,
              // 忽略 this 的類型檢查, Raise error on this expressions with an implied any type.
              "noImplicitThis"false,
              "resolveJsonModule"true,
              "esModuleInterop"true,
              "lib": ["esnext""dom"],
              "types": ["vite/client"]
            },
            "include": ["/src/**/*.ts""/src/**/*.d.ts""/src/**/*.tsx""/src/**/*.vue"],
            // ts 排除的文件
            "exclude": ["node_modules"]
          }

          Vue3 + vite2 打包出來的文件和原來 vue2 版的差別也挺大的,由原來 2.5M 直接變成了 1.8M ,amazing!

          最后

          項(xiàng)目代碼大多都是 2 年前的,還有很多可以優(yōu)化的地方,這次重構(gòu)的過程沒對原來的樣式和代碼做什么改動,沒那么多時間,加上我懶 ??

          這次就升級了主要框架與相應(yīng)的 ui 庫,過了一遍 Vue3 中的 API,發(fā)現(xiàn)很多 Vue3 中新的 API 都用不上,主要是要熟練一下 Vue3 和 Vite2 項(xiàng)目搭建,這假期也算有所收獲。

          具體項(xiàng)目源碼請看:

          https://github.com/biaochenxuying/blog-vue-typescript

          至此,一個基于 Vue3 全家桶 + Vite2 + TypeScript + Element Plus 的開發(fā)環(huán)境已經(jīng)搭建完畢,現(xiàn)在就可以編寫代碼了,各個組件的使用方法請參閱它們各自的文檔。

          不得不說 Vue3 + Element Plus + Vite + TypeScript 是真的香!

          推薦一個 Vue3 相關(guān)的資料匯總:Vue3 的學(xué)習(xí)教程匯總、源碼解釋項(xiàng)目、支持的 UI 組件庫、優(yōu)質(zhì)實(shí)戰(zhàn)項(xiàng)目,相信你會挖到礦哦!

          推薦一個 Vue3 相關(guān)的資料匯總:Vue3 的學(xué)習(xí)教程匯總、源碼解釋項(xiàng)目、支持的 UI 組件庫、優(yōu)質(zhì)實(shí)戰(zhàn)項(xiàng)目,相信你會挖到礦哦!

          推薦閱讀

          瀏覽 44
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  北条麻妃无码一区三区 | 亚洲成人18禁 | 色秘 乱码一区二区三区在线男奴-百 | 麻豆豆成人版在线观看 | 黄色做爱视频免费观看 |