前端vue3项目的GitHub工作流配置
1. 创建工作流文件
项目根目录创建.github/workflows/deploy.yml
name: GitHub Pages |
工作流中,配置了:
on: |
两种触发方式所执行的是同一个工作流,但是它们的触发时机不同,取决于你配置的 on
部分的内容。
这意味着:
- push 触发:当你将代码推送到
main
分支时,工作流会运行。 - pull_request 触发:当有 PR 提交到
main
分支时,工作流会运行。
这两种事件都触发同一个工作流的执行。但是,它们的触发时机和目的不同:
- push 事件:通常用于 代码推送后 的自动化过程,例如构建、部署、发布等。当你将代码推送到
main
分支时,自动触发工作流中的相关步骤(比如构建静态页面并部署到 GitHub Pages)。 - pull_request 事件:用于 PR 创建、更新时 的自动化检查过程,通常是用于 测试和审查。例如,你可以在 PR 被创建或更新时运行测试,确保代码在合并之前没有问题。
2.base 路径问题
默认情况下,Vite 会使用 /
作为资源的基础路径。这样会有以下几个结果,特别是在你部署到 GitHub Pages 或类似的静态资源托管平台时:
1. 开发环境中的行为:
在本地开发时(运行 vite
开发服务器),默认的 base
是 /
,这意味着:
- 静态资源(如 CSS、JS、图片等)的路径将从 根路径
/
开始。 - 这在开发环境中通常不会有问题,因为开发服务器会根据
/
路径来正确解析静态资源。
2. 生产环境中的行为:
当你在生产环境中(如部署到 GitHub Pages)没有设置 base
时,静态资源的路径也默认是 /
。然而,GitHub Pages 将项目部署在一个 子路径 下(如 https://yourusername.github.io/your-repo/
),这就导致了以下问题:
- 静态资源的路径仍然是基于根路径
/
,例如https://yourusername.github.io/app/css/style.css
。 - 错误的资源路径:在 GitHub Pages 上,资源的实际路径应该是
https://yourusername.github.io/your-repo/css/style.css
,即它需要从/your-repo/
开始,但因为没有设置base
,它尝试从根路径/
加载资源,这会导致 404 错误。
3. 如何影响 GitHub Pages 部署:
如果你不设置 base
,并直接将生成的文件部署到 GitHub Pages 的 gh-pages
分支,GitHub Pages 会尝试从根路径 /
加载静态资源,而不是从 /your-repo/
路径加载。这导致了静态资源无法正确加载,页面样式、脚本等都可能出现问题,页面可能会显示为空白或者报错。
4. 总结:
- 开发环境:没有设置
base
,开发时没有问题,因为它会从/
路径加载资源。 - 生产环境(部署到 GitHub Pages 等):没有设置
base
,静态资源的路径会错误地指向根路径/
,而不是子路径(如/your-repo/
),这会导致资源加载失败,页面样式、JS 可能无法正确显示。
注意下方第14行:
// vite.config.ts |
5. 补充 fetch 加载本地资源、与部署后加载静态资源的路径问题
如果你的 fetch
数据文件存储在前端项目中(而不是后端项目),并且你希望在本地开发环境和构建部署后都能通过 fetch
访问这些数据文件,以下是具体的解决方案和最佳实践:
这是ai-给的方案点击查看详情
最佳方案:将数据文件放在 public 目录
将数据文件放在前端项目的 public
目录中,这样无论是在开发环境还是构建部署后,都可以通过相同的路径访问这些文件。
具体步骤
- 将数据文件放在 public 目录
将你的数据文件(如 data.json
)移动到 public
目录中。构建工具(如 Create React App、Vue CLI 等)会将 public
目录中的文件直接复制到构建输出目录中,而不会对它们进行处理。
文件结构:
your-project/
├── public/
│ └── data.json
├── src/
│ └── App.js
└── package.json优点:
- 数据文件在开发环境和生产环境中都可以通过相同的路径访问。
- 无需额外配置 Webpack 或构建工具。
- 在代码中使用绝对路径访问数据
在代码中,使用绝对路径(以 /
开头)访问 public
目录中的数据文件。
示例代码:
fetch('/data.json')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error fetching data:', error));解释:
- 在开发环境中,
/data.json
会指向http://localhost:3000/data.json
。 - 在构建部署后,
/data.json
会指向静态文件服务器的根目录下的data.json
。
- 在开发环境中,
- 本地开发环境
在本地开发环境中,数据文件可以通过开发服务器的根路径访问。
- 在代码中,
fetch('/data.json')
会自动指向http://localhost:3000/data.json
。
- 构建和部署
在构建和部署后,数据文件会被复制到构建输出目录中,并通过相同的路径访问。
构建项目:
构建完成后,数据文件会被复制到构建输出目录(如
public
)中。部署:
将构建输出目录部署到静态文件服务器(如 Nginx、Apache 或 GitHub Pages)。访问数据:
在部署后的页面中,fetch('/data.json')
会自动指向静态文件服务器的根目录下的data.json
。
- 处理路径问题(如果需要子路径)
如果你的项目部署在子路径下(如 https://your-domain.com/your-app/
),需要调整路径以确保 fetch
请求正确指向数据文件。
使用环境变量动态设置路径:
在.env.production
文件中配置子路径:VITE_PUBLIC_URL=/shuangzhao-vue3-ts
在代码中使用 process.env.PUBLIC_URL:
fetch(`${process.env.PUBLIC_URL}/data.json`)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error fetching data:', error));解释:
- 在开发环境中,
process.env.PUBLIC_URL
为空,路径为/data.json
。 - 在构建部署后,路径为
/your-app/data.json
。
- 在开发环境中,
- 检查构建输出
确保数据文件被正确复制到构建输出目录中。构建完成后,检查输出目录(如 public
)中是否存在数据文件。
- 示例:
- 如果使用 Create React App,构建输出目录是
build
。 - 如果使用 Vue CLI,构建输出目录是
dist
。
- 如果使用 Create React App,构建输出目录是
- 检查步骤:
- 运行构建命令(如
npm run build
)。 - 打开构建输出目录,检查是否存在数据文件。
- 如果数据文件不存在,检查构建配置是否正确。
- 运行构建命令(如
总结
通过将数据文件放在 public
目录,并使用绝对路径访问,可以确保无论是在本地开发环境还是构建部署后,都能通过 fetch
获取数据。具体步骤如下:
- 将数据文件放在
public
目录。 - 在代码中使用绝对路径(如
/data.json
)访问数据。 - 在本地开发环境中,通过开发服务器访问数据。
- 在构建部署后,通过静态文件服务器访问数据。
这种方法简单、直接,且无需额外配置,适合大多数场景。如果你的项目部署在子路径下,可以通过环境变量动态设置路径。
这是根据实战总结的
可以在utils中封装一个专用fetch组件:
const fetchWithBaseUrl = url => { |
以上代码中最重要的一个注意点,在根目录分别创建了 .env.production 和 .env/development:
.env.production
中:VITE_PUBLIC_URL=/vue3-ts-shuangzhao.env.development
中:VITE_PUBLIC_URL=’ ‘ ,这里必须为一个空字符串,否则,’/‘ 将抵消 localhost地址
根据这个现象推测,fetch 函数是自动拼接拼接传入的路径字符串,VITE_PUBLIC_URL=’/‘,意味着在传入的参数前增加了一个 ‘/‘,会导致字符串拼接时,如果传入参数以/开头,如’/data’,会导致拼接后的路径被多加了一个’/‘,成为’//data’。
这里带领自己复习一下:
用法区别
- 单个 /(相对当前网站根目录)
/path/to/resource
表示 相对于当前网站的根目录 解析路径。例如,在
http://example.com/app/
页面:
fetch('/data/banner.json')
解析后请求的是:
http://example.com/data/banner.json
(注意
/
代表根目录,而不是当前路径app/
)
- 双斜杠 //(协议相对 URL)
//example.com/path/to/resource
表示 协议相对 URL,它会使用当前页面的协议(http
或https
)。例如,在
https://example.com/app/
页面:
fetch('//cdn.example.com/data/banner.json')
解析后请求的是:
https://cdn.example.com/data/banner.json
(它继承了当前页面的
https
协议)如果当前页面是
http://example.com/app/
,那么
//cdn.example.com/data/banner.json
解析为:
http://cdn.example.com/data/banner.json
- 完整 URL
https://example.com/path/to/resource
代表完整的绝对路径,不会受到当前页面 URL 影响。
什么时候用 //
?
- 适用于 CDN 资源或跨域请求,但你希望它自动匹配当前协议。
- 例如,网页可能会在
http://
或https://
下运行,而//
可确保资源请求使用相同协议,避免“混合内容”警告。
什么时候避免 //
?
如果
VITE_PUBLIC_URL = //api.example.com
,则拼接路径时会导致
fetch('//api.example.com/data')
,这实际上会变成:
arduino
复制编辑
https://api.example.com/data (在 https 站点上)但如果
VITE_PUBLIC_URL = /
,则拼接的/data
是相对路径,不涉及跨域问题。
结论:
/path
👉 当前网站根目录的相对路径//example.com/path
👉 继承当前协议的完整 URLhttp://example.com/path
👉 完整 URL,不依赖当前页面协议
3.导航守卫中的更改
路由守卫中也需要考虑该前缀。否则,to.path
和 next()
中的路径可能会与实际访问的路径不匹配,从而导致路由跳转失败或跳转到错误的页面。
import { createRouter, createWebHistory } from 'vue-router' |
4. 学习了一个新技能
因为使用了插件,基于文件系统自动生成路由,因此当初创建了一些列空白的.vue文件,而在项目生产阶段,进行打包部署时,严格的打包检查会提示空白文件,因此需要一个 js 脚本来为空白的 .vue 文件进行预填充。
项目根目录创建一个 js 文件,如:fill-empty-vue-files.js
import fs from 'fs' |
然后,终端执行 node fill-empty-vue-files.js,现在可以暂时打包项目了 /
5. vite-plugin-eslint 插件的类型声明问题
前面整理过 vite-plugin-eslint 插件的基本情况,这里不再重复啦。
很奇怪,本地构建时并没有有关于该插件的类型错误提示,但是工作流部署,却一直报错,试了n多方法,最终vscode快速修改给秒速度解决了 /
直接在引入文件前加上这一句:
import { fileURLToPath, URL } from 'node:url' |
// @ts-expect-error: eslint plugin does not have type definitions
- 这是一个 TypeScript 的注释,用于告诉 TypeScript 编译器:接下来的代码会有一个类型错误,但这是预期的,因此不需要报错。
- 具体来说,
vite-plugin-eslint
这个插件可能没有提供 TypeScript 的类型定义文件(即.d.ts
文件),因此 TypeScript 无法推断它的类型,会报类型错误。通过@ts-expect-error
,开发者明确表示这个错误是已知的,并且可以忽略。
import eslint from 'vite-plugin-eslint'
- 这是一个 ES Module 的导入语句,用于从
vite-plugin-eslint
包中导入默认导出(default export
)。 vite-plugin-eslint
是一个 Vite 插件,用于在 Vite 项目中集成 ESLint。ESLint 是一个 JavaScript/TypeScript 的代码检查工具,用于发现代码中的潜在问题并保持代码风格一致。- 通过这个导入语句,开发者可以在 Vite 配置中使用这个插件。
6. 关于 base 设置后的一个细节
工作流部署静态页面后,进入页面,在页面中点击跳转至其他页面,可以正常跳转,但是在浏览器直接输入该页面路由地址 ,却报404。
问题分析:
- Vue Router 使用 history 模式:
- 在使用
createWebHistory
模式时,Vue Router 会使用 HTML5 history API,这意味着路由是基于浏览器的地址栏路径进行管理的,而不是使用传统的哈希(#
)模式。 - 当您通过点击跳转到不同的页面时,路由器会通过 JavaScript 捕捉到这些路由并渲染相应的页面内容。
- 在使用
- 页面直接访问时出现 404 错误:
- 当您在浏览器的地址栏直接输入某个页面的 URL(比如
/login
或/task
)时,浏览器会向服务器发出请求,直接访问该路径。 - 由于服务器并不知道如何处理这个路径,它会返回一个
404
错误。特别是在 GitHub Pages 或类似的静态文件托管服务中,服务器没有对应的路由处理逻辑来为这些路径提供内容。
- 当您在浏览器的地址栏直接输入某个页面的 URL(比如
- 静态页面部署的限制:
- 现代前端框架(如 Vue.js)依赖 JavaScript 来动态渲染页面,但静态托管服务(如 GitHub Pages)通常不会处理 SPA 的路由。因此,直接输入路由时,服务器无法返回相应的 HTML 文件,而是返回 404 错误。
解决方案:
为了解决这个问题,您可以采取以下两种方法:
- 确保服务器的所有路由都指向 index.html(SPA 解决方案)
由于您的项目是单页应用(SPA),所有路径最终都应该返回 index.html
,然后由前端的 Vue Router 处理实际的页面渲染。为此,您需要配置一个 404 重定向 或 路径重写,将所有未找到的路径都指向 index.html
。
- GitHub Pages 的工作原理是它只会返回静态资源,但它并不会自动处理 Vue Router 的路径重定向。为了解决这个问题,可以通过以下方式实现:
在
public
目录下创建一个.nojekyll
文件(如果不存在)。在
public
目录下创建一个404.html
文件,并让它重定向到index.html
。以下是404.html
的内容示例:<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="0; url=/" />
</head>
<body>
<p>Page not found. Redirecting to <a href="/">home</a>...</p>
</body>
</html>这会将所有 404 错误自动重定向到首页,Vue Router 会接管路由处理,确保页面渲染正确。
2. 使用 Hash 模式(不推荐,但简单)
另一种方法是切换到 hash模式(默认情况下,Vue Router 使用的是 history
模式),这样就不会依赖服务器的路径,而是依赖 URL 的哈希部分(例如 /#/login
)。这样可以避免直接访问页面时返回 404 错误。
修改 router/index.ts
中的代码:
import { createRouter, createWebHashHistory } from 'vue-router'; |
使用哈希模式后,URL 会变成类似 https://youruilin.github.io/vue3-ts-shuangzhao/#/login
,这样就不会依赖服务器的路径处理,避免了 404 错误。
推荐的解决方法:
由于您是使用 Vue 3 和 Vite,推荐 使用第一种方案,即让服务器始终返回 index.html
,然后由 Vue Router 来处理路径。
- 在生产环境中,使用
createWebHistory(basePath)
配置 Vue Router 并确保服务器处理路径时始终返回index.html
,让 Vue Router 在客户端接管路由。 - 对于 GitHub Pages,您可以通过创建
404.html
文件来实现路径重定向。
总结:
- 使用 history 模式时,直接输入路径会导致 404 错误,因为服务器没有相应的路由处理。这时需要设置服务器将所有请求指向
index.html
。 - 使用 GitHub Pages 部署时,确保设置了 404 页面来重定向到
index.html
,然后由 Vue Router 来处理实际的路由渲染。