Vue3 多页面实现
Vite 官方多页面应用模式对项目文件结构存在一定要求。
我想实现的是多页面
文件归类,子页面单独打包,最重要的就是减少手动配置操作,具体文件目录如下
├── env
| ├── .env
| └── .env.[name]
├── package.json
├── package.json
├── vite.config.js
└── src
├── router
├── views
├── views
└── pages
├── index.html
├── App.html
├── main.ts
└── page1
├── router
├── views
├── index.html
├── App.html
└── main.ts
以上结构将
主页面跟其他子页面统一至src/pages文件下进行归类,主页面开发主要在src根目录下开发,子页面主要在src/pages/[name]下开发。公共的组件、方法就放置于
src文件夹下(如assets、utils等),子页面的就放置对应子页面src/pages/[name]文件夹下,这样的归类可以减少多人开发的文件变更记录,让文件归属更加清晰
实现代码如下
- vite.config 文件配置
// vite.config.ts
import { UserConfig, defineConfig } from "vite";
import { resolve } from "path";
import vue from "@vitejs/plugin-vue";
import { getInput } from "./build/rollup-options";
// https://vitejs.dev/config/
export default defineConfig((): UserConfig => {
// 项目根目录(index.html 文件所在的位置)变更
const rootPage = resolve(__dirname, "./src/pages/");
// 打包后文件指定输出路径(相对于 项目根目录)变更
const outDirDist = resolve(__dirname, "./dist");
const input = getInput();
return {
root: rootPage,
// 变更 .env 文件的目录
envDir: resolve(__dirname, "./env"),
plugins: [vue()],
build: {
outDir: outDirDist, // 输出路径
assetsDir: "static", // 静态文件目录
// 默认情况下 若 outDir 在 root 目录下, 则 Vite 会在构建时清空该目录。
emptyOutDir: true,
rollupOptions: {
input,
output: {
// 更改静态文件 目录+文件名
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]",
},
},
},
// 打包移除log、debug
esbuild: {
drop:
process.env.NODE_ENV === "development" ? [] : ["console", "debugger"],
},
server: {
host: "0.0.0.0",
port: 8080,
// 项目启动后,自动打开
open: true,
proxy: {
"/api": {
target: "http://127.0.0.1",
changeOrigin: true,
rewrite: (path: any) => path.replace(/^\/api/, ""),
},
},
},
};
});
rollup-options.ts文件配置如下
import fs from "fs";
import { resolve, join, extname } from "path";
// 获取项目根目录
const ROOT_PATH = resolve(__dirname, "..");
// 获取项目页面文件夹
const PAGE_PATH = join(ROOT_PATH, "/src/pages");
type FileInfo = {
fullPath: string,
fileInfo: fs.Stats,
file: string,
};
const readDirectory = (
filePath: string,
excludeFiles: string[] = []
): FileInfo[] => {
const files: FileInfo[] = [];
try {
const items = fs.readdirSync(filePath);
for (const item of items) {
if (!excludeFiles.includes(item)) {
const fullPath = resolve(filePath, item);
const fileInfo = fs.statSync(fullPath);
files.push({ fullPath, fileInfo, file: item });
}
}
} catch (error) {
console.error(`读取目录出错: ${filePath}`, error);
}
return files;
};
interface inputInfo {
[key: string]: string;
}
const getInput = (): inputInfo => {
const input: inputInfo = {
index: resolve(PAGE_PATH, "index.html"),
};
const files = readDirectory(PAGE_PATH);
for (const { fullPath, fileInfo, file } of files) {
if (fileInfo.isDirectory()) {
const innerFiles = readDirectory(fullPath);
const htmlFile = innerFiles.find(({ file }) => extname(file) === ".html");
if (htmlFile) {
input[file] = htmlFile.fullPath;
}
}
}
// 子页面打包时,获取子页面的页面 name,该 name 需要与实际子页面文件夹 name 一致,如无子页面单独打包需求可以去除该代码,保留也无影响
const pageIndex = process.argv.findIndex((item) => item === "--page");
if (pageIndex !== -1) {
const pageName = process.argv[pageIndex + 1] || undefined;
if (pageName && input[pageName]) {
return {
[pageName]: input[pageName],
};
}
}
return input;
};
export { getInput };
子页面的一些配置
子页面单独启动
- 配置下
package.json文件即可
// package.json
{
"scripts": {
"dev": "vite",
"dev:page1": "vite serve src/pages/page1/ --config ./vite.config.ts"
}
}
子页面单独打包
- 打包命令配置
// package.json
{
"scripts": {
"build:page1": "vue-tsc && vite build -- --page page1"
}
}
多页面全局 css 变量引入
- 这里以引入 scss 变量文件为例,例如我要引入
src/styles/variables.scss这个scss变量文件
export default defineConfig({
resolve: {
// 配置下文件系统路径的别名,如果使用了ts 还需要进行 tsconfig.json 文件的配置
alias: {
"@": `${resolve(__dirname, "src")}`,
},
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/variables.scss" as *;`,
},
},
},
});
tsconfig.json文件的别名配置
// tsconfig.json
{
"compilerOptions": {
"paths": {
"@/*": ["src/*"]
}
}
}
子页面共享全局 stores 配置
- 默认已进行
stores配置,而后在子项目的mian.ts配置如下参数
import { createApp } from "vue";
import App from "./App.vue";
import pinia from "@/stores";
const app = createApp(App);
app.use(pinia);
Powered by Waline v2.15.8