vite vue3 初體驗

真香

vite的特點簡單理解

  1. 使用原生esm編譯
  2. 使用rollup打包
  3. 支援熱更新(即時編譯)
  4. 更輕更快

分析常常會用到的需求

  1. 安裝搭配vue3與vue-router
  2. 環境變數功能
  3. 設定api proxy
  4. 設定檔案引入別名
  5. 設定拆分打包檔案
  6. 設定打包後靜態資料夾位置與名稱
  7. 設定打包後輸出資料夾位置與名稱
  8. 設定打包後服務器引入檔案路徑
  9. 設定打包後使用cdn引入
  10. 所有檔案共享指定scss檔案

安裝與啟動

安裝vite

npm init vite@latest  //vite的
npm init vue@next //vue官網推薦

安裝vue3

# npm 6.x 
npm init vite@latest my-vue-app --template vue

# npm 7+, extra double-dash is needed:
npm init vite@latest my-vue-app -- --template vue

安裝vue-router

npm install vue-router@next -S

搭建vue-router

# main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
# router > index.js
import { createRouter, createWebHashHistory } from "vue-router";
const routes = [
    {
        path: "/", component: () => import("../views/HelloWorld.vue"),
    }
]
export default createRouter({
    history: createWebHashHistory(),
    routes
});

npm run dev 啟動

npm run build 打包

npm run serve 預覽打包後的結果

環境變數功能

檔案裡面的變數都要開頭為VITE才可以在組建內使用

#檔案名稱
.env                # loaded in all cases
.env.local          # loaded in all cases, ignored by git
.env.[mode]         # only loaded in specified mode
.env.[mode].local   # only loaded in specified mode, ignored by git

API PROXY

# vite.config.js
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
export default defineConfig({
  server: {
    port: 3030, //npm run dev port
    proxy: { //跨域代理
      // 字符串简写写法
      '/foo': 'http://localhost:4567',
      // 选项写法
      '/api': {
        target: 'https://jsonplaceholder.typicode.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      },
      // 正则表达式写法
      '^/fallback/.*': {
        target: 'http://jsonplaceholder.typicode.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/fallback/, '')
      },
      // 使用 proxy 实例
      // '/api': {
      //   target: 'http://jsonplaceholder.typicode.com',
      //   changeOrigin: true,
      //   configure: (proxy, options) => {
      //     // proxy 是 'http-proxy' 的实例
      //   }
      // }
    }
  }
})

設定檔案引入別名

# vite.config.js
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
export default defineConfig({
  resolve: {
    alias: {
      '@/': `${path.resolve(__dirname, 'src')}/` //別名
    }
  },
})

打包設定

  1. 設定打包後靜態資料夾位置與名稱
  2. 設定打包後輸出資料夾位置與名稱
  3. 設定打包後服務器引入檔案路徑
  4. 設定打包後使用cdn引入
# vite.config.js
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import externalGlobals from "rollup-plugin-external-globals"; //打包後要使用cdn的變數時需要安裝此外掛,開發時一樣可以用import引入使用.

export default defineConfig({
  build: {
    rollupOptions: {
      //當成外部模組
      external: ['vue', 'axios', 'vue-router'], //不打包 用cdn引入要記得在index.html頁面掛上cdn不然打包後會出錯
      output: {
        manualChunks(id) { //分割打包
          if (id.includes('node_modules') && id.includes('@vue')) {
            return 'vender'
          }
          if (id.includes('node_modules')) {
            if (id.includes('vue/dist/vue.runtime.esm-bundler.js')) return
            return id.toString().split('node_modules/')[1].split('/')[0].toString()
          }
        }
      },
      plugins: [ 
        externalGlobals({ //打包後使用cdn的配置
          vue: "Vue",
          axios: 'axios',
          ['vue-router']: 'VueRouter'
        })
      ],
      chunkSizeWarningLimit: 500, // chunk 大小警告的限制
      outDir: 'dist', // 構建輸出路徑
      assetsDir: 'assets', //靜態資原始檔夾,和outDir同級
      assetsInlineLimit: 4096, // kb, 小於此值將內聯base64格式
      cssCodeSplit: true, // 執行css檔案按chunk拆分,chunk載入時插入,如果false則所有的樣式匯出為一個css檔案
    },
})

所有檔案共享指定scss檔案

# vite.config.js
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
export default defineConfig({
  css: {
    preprocessorOptions: { //所有檔案共享某個scss感覺我會用來做變量等等放置的檔案
      scss: {
        additionalData: `@import "@/assets/style/base.scss";`
      }
    }
  }
})

資料夾模組化引入

import.meta.globEager('./modules/*.ts') 一次性引入某個資料夾的檔案

https://cn.vitejs.dev/guide/features.html#glob-import

import { createRouter, createWebHistory } from 'vue-router'
const routes:any = []
const modules = import.meta.globEager('./modules/*.ts')
for (const path in modules) {
  routes.push(...modules[path].default)
}
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})
export default router

全部的設定

import path from 'path'
import externalGlobals from "rollup-plugin-external-globals"; //cdn
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  root: path.resolve(__dirname), //index.html所在資料夾
  publicDir: 'public', //靜態資源
  base: './', //服務器檔案引入路徑
  build: {
    rollupOptions: {
      //當成外部模組
      external: ['vue', 'axios', 'vue-router'], //不打包 用cdn引入
      output: {
        manualChunks(id) { //分割打包
          if (id.includes('node_modules') && id.includes('@vue')) {
            return 'vender'
          }
          if (id.includes('node_modules')) {
            if (id.includes('vue/dist/vue.runtime.esm-bundler.js')) return
            return id.toString().split('node_modules/')[1].split('/')[0].toString()
          }
        }
      },
      plugins: [
        externalGlobals({
          vue: "Vue",
          axios: 'axios',
          ['vue-router']: 'VueRouter'
        })
      ],
      // chunk 大小警告的限制
      chunkSizeWarningLimit: 500,
    },
    outDir: 'dist', // 構建輸出路徑
    assetsDir: 'assets', //靜態資原始檔夾,和outDir同級
    assetsInlineLimit: 4096, // kb, 小於此值將內聯base64格式
    cssCodeSplit: true, // 執行css檔案按chunk拆分,chunk載入時插入,如果false則所有的樣式匯出為一個css檔案
  },
  plugins: [vue()],
  resolve: {
    alias: {
      '@/': `${path.resolve(__dirname, 'src')}/` //別名
    }
  },
  server: {
    port: 3030, //npm run dev port
    proxy: { //跨域代理
      // 字符串简写写法
      '/foo': 'http://localhost:4567',
      // 选项写法
      '/api': {
        target: 'https://jsonplaceholder.typicode.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      },
      // 正则表达式写法
      '^/fallback/.*': {
        target: 'http://jsonplaceholder.typicode.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/fallback/, '')
      },
      // 使用 proxy 实例
      // '/api': {
      //   target: 'http://jsonplaceholder.typicode.com',
      //   changeOrigin: true,
      //   configure: (proxy, options) => {
      //     // proxy 是 'http-proxy' 的实例
      //   }
      // }
    }
  },
  css: {
    preprocessorOptions: { //可以所有檔案共享某個scss 感覺我會用來做變量等等的宣告
      scss: {
        additionalData: `@import "@/assets/style/base.scss";`
      }
    }
  }
})

參考資料

官網

https://vitejs.dev/guide/env-and-mode.html#production-replacement

postcss

https://cythilya.github.io/2018/08/10/postcss/

cdn注入

https://github.com/vitejs/vite/discussions/2836 

gzip

https://www.npmjs.com/package/vite-plugin-compression