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
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(
// Your custom configs here
)
export default withNuxt([eslintPluginPrettierRecommended], {
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";
export default defineNuxtConfig({
compatibilityDate: "2025-12-12",
srcDir: "app/",
modules: ["@nuxt/image", "@nuxt/eslint"],
compatibilityDate: "2025-12-12",
srcDir: "app/",
modules: ["@nuxt/image", "@nuxt/eslint"],
// 禁用 Vue Router 的非关键警告
vue: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith("ion-"),
// eslint: {
// config: {
// extends: ["plugin:nuxt/recommended", "prettier"],
// 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",
},
},
// 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",
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",
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",
},
},
nitro: {
prerender: {
crawlLinks: true,
// routes: ["/sitemap.xml", "/rss.xml"],
{
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",
},
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",
},
},
nitro: {
prerender: {
crawlLinks: true,
// routes: ["/sitemap.xml", "/rss.xml"],
},
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",
"private": true,
"type": "module",
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build",
"generate": "nuxt generate",
"preview": "nuxt preview",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"dependencies": {
"@giscus/vue": "^3.1.1",
"@jaseeey/vue-umami-plugin": "^1.4.0",
"@nuxt/eslint": "1.12.1",
"@nuxt/image": "2.0.0",
"eslint": "^9.39.2",
"nodemailer": "^7.0.11",
"nuxt": "^4.2.2",
"vite-tsconfig-paths": "^6.0.1"
},
"devDependencies": {
"@tailwindcss/vite": "^4.1.18",
"@types/node": "^24.10.1",
"@types/nodemailer": "^7.0.4",
"autoprefixer": "^10.4.22",
"tailwindcss": "^4.1.18",
"typescript": "^5.9.3"
}
"name": "cloud-home",
"private": true,
"type": "module",
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build",
"generate": "nuxt generate",
"preview": "nuxt preview",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
"dependencies": {
"@giscus/vue": "^3.1.1",
"@jaseeey/vue-umami-plugin": "^1.4.0",
"@nuxt/image": "2.0.0",
"nodemailer": "^7.0.11",
"nuxt": "^4.2.2",
"vite-tsconfig-paths": "^6.0.1"
},
"devDependencies": {
"@nuxt/eslint": "1.12.1",
"@tailwindcss/vite": "^4.1.18",
"@types/node": "^24.10.1",
"@types/nodemailer": "^7.0.4",
"@typescript-eslint/parser": "^8.50.0",
"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"
}
}