feat: 添加 ESLint 和 Prettier 配置,集成自动格式化工作流

This commit is contained in:
2025-12-19 19:37:29 +08:00
parent 6b05f7c74e
commit 618723a689
6 changed files with 261 additions and 121 deletions

80
.github/workflows/lint-format.yml vendored Normal file
View File

@@ -0,0 +1,80 @@
name: Lint and Format
on:
push:
branches: ["**"]
pull_request:
branches: ["**"]
jobs:
lint:
name: ESLint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "pnpm"
- name: Enable corepack and install pnpm
run: |
corepack enable
corepack prepare pnpm@latest --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run ESLint
run: pnpm lint
- name: Run Prettier check
run: pnpm format:check
format:
name: Auto-format (eslint --fix)
runs-on: ubuntu-latest
needs: lint
if: github.event_name == 'push'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: true
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "pnpm"
- name: Enable corepack and install pnpm
run: |
corepack enable
corepack prepare pnpm@latest --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Prettier --write
run: pnpm format
- name: Run ESLint --fix
run: pnpm lint:fix
- name: Commit & push fixes
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if ! git diff --quiet; then
git add -A
git commit -m "chore: auto format by GitHub Actions" || echo "No changes to commit"
git push
else
echo "No formatting changes"
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

18
.prettierignore Normal file
View File

@@ -0,0 +1,18 @@
node_modules/
.output/
.nuxt/
dist/
build/
public/build/
.vscode/
.pnp.*
coverage/
*.log
*.lock
pnpm-lock.yaml
.env
.env.*
.DS_Store
# ignore generated images
public/images/generated/

12
.prettierrc Normal file
View File

@@ -0,0 +1,12 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf",
"htmlWhitespaceSensitivity": "css"
}

View File

@@ -1,6 +1,19 @@
// @ts-check // @ts-check
import withNuxt from './.nuxt/eslint.config.mjs' import withNuxt from "./.nuxt/eslint.config.mjs";
// import simpleImportSort from "eslint-plugin-simple-import-sort";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
export default withNuxt( export default withNuxt([eslintPluginPrettierRecommended], {
// Your custom configs here files: ["src/**/*.ts", "src/**/*.vue"],
) ignores: [".nuxt/", "node_modules/"],
language: "vue",
// plugins: {
// prettier: prettierPlugin,
// },
// rules: {
// "prettier/prettier": "error",
// "simple-import-sort/imports": "error",
// "simple-import-sort/exports": "error",
// },
});

View File

@@ -3,97 +3,108 @@ import siteConfig from "./app/config/siteConfig";
import tailwindcss from "@tailwindcss/vite"; import tailwindcss from "@tailwindcss/vite";
export default defineNuxtConfig({ export default defineNuxtConfig({
compatibilityDate: "2025-12-12", compatibilityDate: "2025-12-12",
srcDir: "app/", srcDir: "app/",
modules: ["@nuxt/image", "@nuxt/eslint"], modules: ["@nuxt/image", "@nuxt/eslint"],
// 禁用 Vue Router 的非关键警告 // eslint: {
vue: { // config: {
compilerOptions: { // extends: ["plugin:nuxt/recommended", "prettier"],
isCustomElement: (tag) => tag.startsWith("ion-"), // plugins: ["prettier"],
// rules: {
// "prettier/prettier": "error",
// },
// stylistic: true
// },
// },
// 禁用 Vue Router 的非关键警告
vue: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith("ion-"),
},
},
// Tailwind CSS 集成
css: ["~/styles.global.css"],
vite: {
plugins: [tailwindcss()],
},
routeRules: {
"/": { prerender: true },
"/about": { isr: 3600 },
"/sites": { prerender: true },
"/projects": { prerender: true },
"/friends": { prerender: true },
},
app: {
head: {
title: siteConfig.siteMeta.title,
link: [
{ rel: "icon", href: siteConfig.siteMeta.icon },
// Font Awesome CDN 预加载和优化
{
rel: "preload",
as: "style",
href: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css?font-display=swap",
crossorigin: "anonymous",
}, },
}, {
rel: "preload",
// Tailwind CSS 集成 as: "font",
css: ["~/styles.global.css"], href: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/webfonts/fa-solid-900.woff2?font-display=swap",
type: "font/woff2",
vite: { crossorigin: "anonymous",
plugins: [tailwindcss()],
},
routeRules: {
"/": { prerender: true },
"/about": { isr: 3600 },
"/sites": { prerender: true },
"/projects": { prerender: true },
"/friends": { prerender: true },
},
app: {
head: {
title: siteConfig.siteMeta.title,
link: [
{ rel: "icon", href: siteConfig.siteMeta.icon },
// Font Awesome CDN 预加载和优化
{
rel: "preload",
as: "style",
href: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css?font-display=swap",
crossorigin: "anonymous",
},
{
rel: "preload",
as: "font",
href: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/webfonts/fa-solid-900.woff2?font-display=swap",
type: "font/woff2",
crossorigin: "anonymous",
},
{
rel: "preload",
as: "font",
href: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/webfonts/fa-brands-400.woff2?font-display=swap",
type: "font/woff2",
crossorigin: "anonymous",
},
],
}, },
}, {
rel: "preload",
nitro: { as: "font",
prerender: { href: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/webfonts/fa-brands-400.woff2?font-display=swap",
crawlLinks: true, type: "font/woff2",
// routes: ["/sitemap.xml", "/rss.xml"], crossorigin: "anonymous",
}, },
minify: true, ],
}, },
},
runtimeConfig: { nitro: {
smtpHost: process.env.SMTP_HOST ?? "", prerender: {
smtpPort: Number(process.env.SMTP_PORT ?? 465), crawlLinks: true,
smtpUser: process.env.SMTP_USER ?? "", // routes: ["/sitemap.xml", "/rss.xml"],
smtpPass: process.env.SMTP_PASS ?? "",
senderEmail: process.env.SENDER_EMAIL ?? "",
adminEmail: process.env.ADMIN_EMAIL ?? "",
smtpSecure: process.env.SMTP_SECURE ? process.env.SMTP_SECURE === "true" : undefined,
wakatimeApiKey: process.env.WAKATIME_API_KEY ?? "",
wakatimeApiUrl: process.env.WAKATIME_API_URL ?? "https://wakatime.com/api/v1",
public: {
githubToken: process.env.NUXT_PUBLIC_GITHUB_TOKEN ?? "",
umamiApiKey: process.env.NUXT_PUBLIC_UMAMI_API_KEY ?? "",
// Twikoo 评论服务地址(在 Netlify 或部署环境中设置 NUXT_PUBLIC_TWIKOO_URL
twikooUrl: process.env.NUXT_PUBLIC_TWIKOO_URL ?? "",
// Giscus 配置(在部署环境中设置 NUXT_PUBLIC_GISCUS_* 系列变量)
giscus: {
repo: process.env.NUXT_PUBLIC_GISCUS_REPO ?? "",
repoId: process.env.NUXT_PUBLIC_GISCUS_REPO_ID ?? "",
category: process.env.NUXT_PUBLIC_GISCUS_CATEGORY ?? "",
categoryId: process.env.NUXT_PUBLIC_GISCUS_CATEGORY_ID ?? "",
mapping: process.env.NUXT_PUBLIC_GISCUS_MAPPING ?? "pathname",
reactionsEnabled: process.env.NUXT_PUBLIC_GISCUS_REACTIONS_ENABLED ?? "1",
emitMetadata: process.env.NUXT_PUBLIC_GISCUS_EMIT_METADATA ?? "0",
inputPosition: process.env.NUXT_PUBLIC_GISCUS_INPUT_POSITION ?? "bottom",
theme: process.env.NUXT_PUBLIC_GISCUS_THEME ?? "light",
},
},
}, },
minify: true,
},
runtimeConfig: {
smtpHost: process.env.SMTP_HOST ?? "",
smtpPort: Number(process.env.SMTP_PORT ?? 465),
smtpUser: process.env.SMTP_USER ?? "",
smtpPass: process.env.SMTP_PASS ?? "",
senderEmail: process.env.SENDER_EMAIL ?? "",
adminEmail: process.env.ADMIN_EMAIL ?? "",
smtpSecure: process.env.SMTP_SECURE ? process.env.SMTP_SECURE === "true" : undefined,
wakatimeApiKey: process.env.WAKATIME_API_KEY ?? "",
wakatimeApiUrl: process.env.WAKATIME_API_URL ?? "https://wakatime.com/api/v1",
public: {
githubToken: process.env.NUXT_PUBLIC_GITHUB_TOKEN ?? "",
umamiApiKey: process.env.NUXT_PUBLIC_UMAMI_API_KEY ?? "",
// Twikoo 评论服务地址(在 Netlify 或部署环境中设置 NUXT_PUBLIC_TWIKOO_URL
twikooUrl: process.env.NUXT_PUBLIC_TWIKOO_URL ?? "",
// Giscus 配置(在部署环境中设置 NUXT_PUBLIC_GISCUS_* 系列变量)
giscus: {
repo: process.env.NUXT_PUBLIC_GISCUS_REPO ?? "",
repoId: process.env.NUXT_PUBLIC_GISCUS_REPO_ID ?? "",
category: process.env.NUXT_PUBLIC_GISCUS_CATEGORY ?? "",
categoryId: process.env.NUXT_PUBLIC_GISCUS_CATEGORY_ID ?? "",
mapping: process.env.NUXT_PUBLIC_GISCUS_MAPPING ?? "pathname",
reactionsEnabled: process.env.NUXT_PUBLIC_GISCUS_REACTIONS_ENABLED ?? "1",
emitMetadata: process.env.NUXT_PUBLIC_GISCUS_EMIT_METADATA ?? "0",
inputPosition: process.env.NUXT_PUBLIC_GISCUS_INPUT_POSITION ?? "bottom",
theme: process.env.NUXT_PUBLIC_GISCUS_THEME ?? "light",
},
},
},
}); });

View File

@@ -1,31 +1,37 @@
{ {
"name": "cloud-home", "name": "cloud-home",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "nuxt dev", "dev": "nuxt dev",
"build": "nuxt build", "build": "nuxt build",
"generate": "nuxt generate", "generate": "nuxt generate",
"preview": "nuxt preview", "preview": "nuxt preview",
"lint": "eslint .", "lint": "eslint .",
"lint:fix": "eslint . --fix" "lint:fix": "eslint . --fix",
}, "format": "prettier --write .",
"dependencies": { "format:check": "prettier --check ."
"@giscus/vue": "^3.1.1", },
"@jaseeey/vue-umami-plugin": "^1.4.0", "dependencies": {
"@nuxt/eslint": "1.12.1", "@giscus/vue": "^3.1.1",
"@nuxt/image": "2.0.0", "@jaseeey/vue-umami-plugin": "^1.4.0",
"eslint": "^9.39.2", "@nuxt/image": "2.0.0",
"nodemailer": "^7.0.11", "nodemailer": "^7.0.11",
"nuxt": "^4.2.2", "nuxt": "^4.2.2",
"vite-tsconfig-paths": "^6.0.1" "vite-tsconfig-paths": "^6.0.1"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/vite": "^4.1.18", "@nuxt/eslint": "1.12.1",
"@types/node": "^24.10.1", "@tailwindcss/vite": "^4.1.18",
"@types/nodemailer": "^7.0.4", "@types/node": "^24.10.1",
"autoprefixer": "^10.4.22", "@types/nodemailer": "^7.0.4",
"tailwindcss": "^4.1.18", "@typescript-eslint/parser": "^8.50.0",
"typescript": "^5.9.3" "autoprefixer": "^10.4.22",
} "eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"prettier": "^3.7.4",
"tailwindcss": "^4.1.18",
"typescript": "^5.9.3"
}
} }