創建 Vite Vue Vite 安裝與環境變數設定
相容性說明
Vite 需要 Node.js 版本 18+。 20+。 但是,某些模板需要更高的 Node.js 版本才能運作,如果您的套件管理器發出警告,請升級。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 npm create vite-extra@latest 專案名稱 create-vite@5.5.2 Ok to proceed? (y) ? Select a framework: › - Use arrow-keys. Return to submit. Vanilla ❯ Vue React Preact Lit Svelte Solid Qwik Others
參考官網
1 2 3 4 cd vite-project npm install npm run dev
專案架構
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ├── .vscode ├── public │ └── vite.svg ├── src │ ├── App.vue │ ├── assets │ │ └── vue.svg │ ├── components │ │ └── HelloWorld.vue │ ├── main.js │ └── style.css ├── .gitignore ├── index.html ├── package.json ├── package-lock.json ├── README.md ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.node.json └── vite.config.js
安裝完成gitHub上的說明 gitHub上的說明(vite ^5.4.1”)
創建 Express 伺服器 安裝 express 與nodemon concurrently
1 2 npm install express npm install --save-dev nodemon concurrently
gitHub上的說明:安裝 express 與nodemon concurrently 專案新增server/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 import express from "express"; const port = process.env.PORT || 3000; const app = express(); app.get("/api/v1/hello", (_req, res) => { res.json({ message: "Hello, world!" }); }); app.listen(port, () => { console.log("Server listening on port", port); });
修改package.json設定檔,新增一個主檔案並將 dev 命令替換為以下內容
1 2 3 4 5 6 7 8 9 10 11 "version": "1.0.1", "type": "module", + "main": "server/index.js", "scripts": { - "dev": "vite", + "dev:frontend": "vite", + "dev:backend": "nodemon server/index.js", + "dev": "concurrently 'npm:dev:frontend' 'npm:dev:backend'", + "build": "vite build", "preview": "vite preview" },
這樣Vite伺服器和Nodemon就會並行運作。 運行來啟動伺服器
如果我們訪問http://localhost:3000/api/v1/hello 現在有一個前端和一個後端正在運行,但它們還沒有互相溝通
1 2 3 { "message": "Hello, world!" }
gitHub上的說明:測試api/v1/hello運行
連接客戶端和伺服器 安裝ejs
新增server/homepageRouter.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import express from "express"; import fs from "fs/promises"; import path from "path"; const router = express.Router(); // const environment = process.env.NODE_ENV; //開發中,獲取所有的數據(來自打包產生dist/manifest.json router.get("/*", async (_req, res) => { const data = { environment, manifest: await parseManifest(), }; console.log('data', data) res.render("index.html.ejs", data); }); const parseManifest = async () => { if (environment !== "production") return {}; const manifestPath = path.join(path.resolve(), "dist", "manifest.json"); console.log('manifestPath', manifestPath) const manifestFile = await fs.readFile(manifestPath); console.log(' manifestFile', manifestFile) return JSON.parse(manifestFile); }; export default router;
homepageRouter.js 新增server/assetsRouter.js,靜態圖片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import express from "express"; const router = express.Router(); //支持的檔案類型 const supportedAssets = ["svg", "png", "jpg", "png", "jpeg", "mp4", "ogv"]; const assetExtensionRegex = () => { //JS 把陣列 Array 所有元素併成字串,且可任意穿插符號的 join() const formattedExtensionList = supportedAssets.join("|"); //JS Regex 正則表達式 return new RegExp(`/.+\.(${formattedExtensionList})$`); }; router.get(assetExtensionRegex(), (req, res) => { res.redirect(303, `http://localhost:5173/src${req.path}`); }); export default router;
homepageRouter.js
修改server/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import express from "express"; import path from "path"; import homepageRouter from "./homepageRouter.js"; import assetsRouter from "./assetsRouter.js"; const port = process.env.PORT || 3000; //載入為靜態目錄 const publicPath = path.join(path.resolve(), "public"); const distPath = path.join(path.resolve(), "dist"); const app = express(); app.get("/api/v1/hello", (_req, res) => { res.json({ message: "Hello, Lara!" }); }); //如果是生產階段就連結到dist/,否則連接到public與/src if (process.env.NODE_ENV === "production") { app.use("/", express.static(distPath)); } else { app.use("/", express.static(publicPath)); app.use("/src", assetsRouter); } //將路由器連接到 Express 應用程式 app.use(homepageRouter); app.listen(port, () => { console.log("Server listening on port", port); });
路由器
修改src/components/HelloWorld.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <script setup lang="ts"> import { ref } from 'vue' const count = ref(0) const serverHello = ref({}) fetch('/api/v1/hello') .then((res) => res.json()) .then(({ message }) => { serverHello.value = message }) </script> <template> <h2>{{ serverHello }}</h2> </template>
HelloWorld.vue
刪除index.html ,在根目錄新增一個 views/index.html.ejs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vite + Vue</title> <% if (environment === 'production') { %> <link rel="stylesheet" href="<%= manifest['src/main.css'].file %>" /> <% } %> </head> <body> <div id="app"></div> <% if (environment === 'production') { %> <script type="module" src="<%= manifest['src/main.ts'].file %>"></script> <% } else { %> <script type="module" src="http://localhost:5173/@vite/client"></script> <script type="module" src="http://localhost:5173/src/main.ts"></script> <% } %> </body> </html>
index.html.ejse
生產中運行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], // 新增打包 build: { manifest: true, rollupOptions: { input: "./src/main.ts", }, }, });
vite.config.ts 新增打包設定
執行打包,
產生dist後,在.vite將manifest.json移動到dist根目錄,並修改manifest.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 { "src/assets/vue.svg": { "file": "vite.svg", "src": "src/assets/vue.svg"//物件名與src名相同 }, "src/main.css": { "file": "assets/main-CYBnthfA.css",//打包後的檔案 "src": "src/main.css"//物件名與src名相同 }, "src/main.ts": { "file": "assets/main-CpTINVMW.js",//打包後的檔案 "name": "main", "src": "src/main.ts",//物件名與src名相同 "isEntry": true, "css": [ "assets/main-CYBnthfA.css"//打包後的檔案 ] } }
demo