前端项目架构 项目格式化规范篇

目录

一、概述

[二、VS Code设置格式化规范](#二、VS Code设置格式化规范)

1、插件推荐安装

2、Setting.json统一

三、项目中使用Prettier(推荐)

1、安装Prettier依赖

2、创建.prettierrc.cjs文件

3、创建.prettierignore文件

4、有ESLint文件可以进行配置

5、在package.json中加入命令

四、格式化

1、格式化说明

2、格式化优先级

3、格式化案例


一、概述

工欲善其事,必先利其器。在团队开发过程中,代码提交格式不统一的情况时有发生,这会导致在查看代码更新时效率降低、不便追溯。本文将针对这一问题,介绍如何构建一套有效的项目代码格式化架构。

本篇文章将从以下两个方面梳理解决方案:一是在 VS Code 中实现本地代码格式化统一,二是通过 Prettier 配置确保项目中的代码格式优先统一。

二、VS Code设置格式化规范

1、插件推荐安装

Tailwind CSS IntelliSense

Tailwind Sorter

Less IntelliSense

SCSS IntelliSense

CSS Modules

ES7+ React/Redux/React-Native snippets

React PropTypes Intellisense

React Native Tools

ESLint

Prettier - Code formatter

Path Intellisense

Error Lens

GitLess

Material Icon Theme

Solarized Light (no bold) -> Solarized Light

Project Manager

Todo Tree

Expo Tools

2、Setting.json统一

这里关键在于统一格式化属性,使用Prettier插件格式化

javascript 复制代码
{
  "workbench.settings.applyToAllProfiles": [],
  "workbench.iconTheme": "material-icon-theme",
  "diffEditor.ignoreTrimWhitespace": true,
  "react-native-tools.showUserTips": false,

  // 字体调大更护眼
  "editor.fontSize": 14,
  "editor.lineHeight": 1.6,

  // 降低对比度 - 柔和的米色主题
  "workbench.colorCustomizations": {
    "editor.background": "#f9f3e4",
    // ========== 活动栏(最左侧) ==========
    "activityBar.background": "#F7F2E7",
    "activityBar.foreground": "#666666",
    "activityBar.inactiveForeground": "#999999",
    "activityBar.border": "#E8E4DD",
    "activityBarBadge.background": "#D4C8B5",
    "activityBarBadge.foreground": "#333333",
    // ========== 侧边栏 ==========
    "sideBar.background": "#F8F6F2",
    "sideBar.foreground": "#444444",
    "sideBar.border": "#E8E4DD",
    "sideBarSectionHeader.background": "#F0EDE8",
    "sideBarTitle.foreground": "#555555",
    // ========== 标题栏 ==========
    "titleBar.activeBackground": "#F6F4F0",
    "titleBar.activeForeground": "#444444",
    "titleBar.inactiveBackground": "#F9F7F3",
    "titleBar.inactiveForeground": "#888888",
    "titleBar.border": "#E8E4DD",
    // ========== 状态栏 ==========
    "statusBar.background": "#F5F1EB",
    "statusBar.foreground": "#555555",
    "statusBar.border": "#E8E4DD",
    "statusBar.noFolderBackground": "#F5F1EB",
    "statusBar.debuggingBackground": "#E8DCC8",
    "statusBarItem.remoteBackground": "#D4C8B5",
    // ========== 标签页 ==========
    "tab.activeBackground": "#FAF9F6",
    "tab.activeForeground": "#222222",
    "tab.inactiveBackground": "#F0EDE8",
    "tab.inactiveForeground": "#666666",
    "tab.border": "#E8E4DD",
    "tab.activeBorder": "#D4C8B5",
    "tab.activeBorderTop": "#C4B8A5",
    "tab.hoverBackground": "#F5F1EB",
    "tab.unfocusedHoverBackground": "#F5F1EB",
    // ========== 编辑器组和面板 ==========
    "editorGroupHeader.tabsBackground": "#F0EDE8",
    "editorGroup.border": "#E8E4DD",
    "panel.background": "#FAF9F6",
    "panel.border": "#E8E4DD",
    "panelTitle.activeForeground": "#444444",
    "panelTitle.inactiveForeground": "#888888",
    // ========== 输入框和下拉菜单 ==========
    "input.background": "#FFFFFF",
    "input.foreground": "#333333",
    "input.border": "#E8E4DD",
    "inputOption.activeBorder": "#C4B8A5",
    "dropdown.background": "#FFFFFF",
    "dropdown.border": "#E8E4DD",
    "dropdown.foreground": "#333333",
    // ========== 按钮 ==========
    "button.background": "#D4C8B5",
    "button.foreground": "#333333",
    "button.hoverBackground": "#C4B8A5",
    "button.border": "#C4B8A5",
    // ========== 滚动条 ==========
    "scrollbar.shadow": "#E8E4DD",
    "scrollbarSlider.background": "#D4C8B599",
    "scrollbarSlider.hoverBackground": "#C4B8A599",
    "scrollbarSlider.activeBackground": "#B4A89599",
    // ========== 列表和树视图 ==========
    "list.activeSelectionBackground": "#E8E4DD",
    "list.activeSelectionForeground": "#333333",
    "list.inactiveSelectionBackground": "#F0EDE8",
    "list.hoverBackground": "#F5F1EB",
    "list.focusBackground": "#E8E4DD",
    "list.focusForeground": "#333333",
    "tree.indentGuidesStroke": "#E8E4DD",
    // ========== 通知和消息 ==========
    "notification.background": "#F7F2E7",
    "notification.foreground": "#444444",
    "notification.buttonBackground": "#D4C8B5",
    "notification.buttonHoverBackground": "#C4B8A5",
    "notification.buttonForeground": "#333333",
    "notification.infoBackground": "#E8F0E8",
    "notification.warningBackground": "#F8F0E8",
    "notification.errorBackground": "#F8E8E8",
    // ========== 其他界面元素 ==========
    "focusBorder": "#D4C8B5",
    "contrastBorder": "#E8E4DD",
    "widget.shadow": "#E8E4DD80",
    "badge.background": "#D4C8B5",
    "badge.foreground": "#333333",
    "progressBar.background": "#D4C8B5",
    // ========== 终端 ==========
    "terminal.background": "#FAF9F6",
    "terminal.foreground": "#333333",
    "terminalCursor.background": "#333333",
    "terminalCursor.foreground": "#333333",
    "terminal.ansiBlack": "#333333",
    "terminal.ansiWhite": "#FAF9F6",
    "terminal.selectionBackground": "#E8E4DD"
  },

  "workbench.colorTheme": "Solarized Light",

  // ====== 格式化相关 ======
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",

  // ====== Prettier 配置(满足您的格式化规则) ======
  "prettier.semi": true, // 1. 有分号
  "prettier.trailingComma": "none", // 2. 无尾随逗号
  "prettier.arrowParens": "avoid", // 3. 精简箭头函数(单参数无括号)
  "prettier.singleQuote": true, // 4. JS 单引号
  "prettier.jsxSingleQuote": false, // 5. JSX 双引号
  "prettier.tabWidth": 2, // 6. 2 空格缩进
  "prettier.useTabs": false, // 6. 不使用 Tab
  "prettier.endOfLine": "lf", // 7. LF 换行符
  "prettier.printWidth": 100, // 8. 每行最多 100 字符

  // ====== 语言特定配置 ======
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },
  "[javascriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode", // 统一使用 Prettier
    "editor.tabSize": 2
  },
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },
  "[css]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },

  // ====== 代码编辑体验 ======
  "editor.tabSize": 2,
  "editor.insertSpaces": true,
  "editor.detectIndentation": false,
  "editor.wordWrap": "off",
  "editor.renderWhitespace": "selection",
  "editor.rulers": [100], // 显示 100 字符参考线

  // ====== ESLint 配置 ======
  "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
  "eslint.alwaysShowStatus": true,
  "eslint.codeActionsOnSave.mode": "problems",

  // ====== 文件保存 ======
  "files.autoSave": "onFocusChange",
  "files.eol": "\n", // 7. LF 换行符
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,

  // ====== 额外建议:更好地与 ESLint 集成 ======
  "prettier.eslintIntegration": false, // Prettier 3.x 已移除,使用下面配置
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
    "source.fixAll.stylelint": "explicit" // 如果需要样式检查
  },

  "files.associations": {
    "*.css": "tailwindcss"
  },
  "tailwindCSS.classAttributes": ["class", "className", "headerClassName"]
}

通过统一VS Code的setting.json来实现项目统一格式化的目的。在项目中没有使用Prettier包配置时,VS Code的setting会生效。

三、项目中使用Prettier(推荐)

1、安装Prettier依赖

bash 复制代码
# 安装 Prettier 作为开发依赖
npm install --save-dev prettier

# 或使用 yarn
yarn add --dev prettier

2、创建.prettierrc.cjs文件

javascript 复制代码
/** @type {import('prettier').Config} */
module.exports = {
  // 基础风格
  semi: true, // 有分号
  trailingComma: 'none', // 不要尾随逗号
  singleQuote: true, // 使用单引号,少按一次shift键

  // 箭头函数
  arrowParens: 'avoid', // 单参数不要括号,多参数保留

  // 代码布局
  printWidth: 100, // 每行最多100字符
  tabWidth: 2, // 缩进2个空格
  useTabs: false, // 用空格不是Tab

  // 括号处理
  bracketSpacing: true, // 对象括号内加空格 { key: value }
  bracketSameLine: true, // JSX结束标签换行

  // JSX特殊设置
  jsxSingleQuote: false, // JSX属性用双引号 <div className="test">

  // 其他
  endOfLine: 'lf', // 统一换行符(Linux/macOS风格)
  quoteProps: 'as-needed', // 只有必要时给属性加引号
  proseWrap: 'preserve', // Markdown文本保持原样

  // Next.js 相关扩展配置
  overrides: [
    {
      files: '*.{js,jsx,ts,tsx}',
      options: {
        // React/Next.js 相关优化
        parser: 'typescript',
        // 确保 JSX 属性合理换行
        jsxBracketSameLine: false,
        // 处理长链式调用
        singleAttributePerLine: false
      }
    },
    {
      files: '*.{css,scss}',
      options: {
        parser: 'css',
        singleQuote: true
      }
    },
    {
      files: '*.json',
      options: {
        parser: 'json',
        trailingComma: 'none'
      }
    },
    {
      files: '*.md',
      options: {
        parser: 'markdown',
        proseWrap: 'preserve' // Markdown 文本保持原样
      }
    }
  ],

  // 插件配置(如果有的话)
  // plugins: ['prettier-plugin-tailwindcss'],

  // 插件相关配置示例
  /*
  tailwindConfig: './tailwind.config.js',
  tailwindFunctions: ['clsx', 'cn', 'tw'],
  */

  // 格式化忽略的文件模式(也可以在 .prettierignore 中配置)
  ignorePath: '.prettierignore'
};

3、创建.prettierignore文件

javascript 复制代码
# 忽略文件
.next
node_modules
dist
build
out
public
coverage
*.log
.env*
*.local
.DS_Store
.vscode
.idea

4、有ESLint文件可以进行配置

javascript 复制代码
module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended' // 必须放在最后,关闭冲突规则
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true
    },
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  plugins: ['react', '@typescript-eslint'],
  settings: {
    react: {
      version: 'detect'
    }
  },
  rules: {
    // === 匹配你的 Prettier 偏好 ===
    semi: ['error', 'always'], // ✓ 改为有分号
    'comma-dangle': ['error', 'never'], // 无尾随逗号
    'arrow-parens': ['error', 'as-needed'], // 箭头函数括号精简

    // === React 规则 ===
    'react/react-in-jsx-scope': 'off', // React 17+ 不需要引入
    'react/prop-types': 'off', // TypeScript 项目不需要

    // === 代码质量 ===
    'no-console': 'warn',
    'no-unused-vars': 'off', // 使用 TypeScript 的规则
    '@typescript-eslint/no-unused-vars': ['error'],

    // === 简化规则 ===
    quotes: ['error', 'single'], // 单引号
    'jsx-quotes': ['error', 'prefer-double'] // JSX 双引号
  }
};

5、在package.json中加入命令

bash 复制代码
  "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx}'"

路径名称可以按照项目实际进行调整。

执行格式化脚本:

bash 复制代码
yarn run format

四、格式化

1、格式化说明

  1. 有分号 - 语句结尾加分号

  2. 无尾随逗号 - 对象/数组最后一项后不加逗号

  3. 精简箭头函数 - 单参数无括号,多参数保留括号

  4. JS 单引号 - JavaScript/TypeScript 代码用单引号

  5. JSX 双引号 - JSX 属性值用双引号

  6. 2 空格缩进 - 使用空格缩进,不用 Tab

  7. 换行符统一 - 使用 LF 换行符

  8. 代码行限制 - 每行最多 100 字符

2、格式化优先级

优先级顺序(Prettier 从高到低):

  1. 本地 .prettierrc* 配置文件

  2. package.json 中的 prettier 字段

  3. VS Code 的 prettier.* 设置

  4. Prettier 默认值

3、格式化案例

javascript 复制代码
/ ====== JavaScript/TypeScript 部分 ======

// 函数定义 - 单参数无括号
const getUser = id => {
  return { id, name: '张三' };
};

// 多参数有括号
const addUser = (name, age) => ({
  name,
  age,
  createdAt: new Date()
});

// 数组操作
const users = [
  { id: 1, name: '李四' },
  { id: 2, name: '王五' }
];

const activeUsers = users
  .filter(user => user.id > 0)
  .map(user => ({
    ...user,
    status: 'active'
  }));

// 对象定义 - 无尾随逗号
const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  retries: 3
};

// ====== React 组件部分 ======

import React, { useState } from 'react';

const UserList = ({ users, onSelect }) => {
  const [filter, setFilter] = useState('');

  // 事件处理 - 单参数无括号
  const handleClick = userId => {
    onSelect(userId);
  };

  const handleChange = e => {
    setFilter(e.target.value);
  };

  const filteredUsers = users.filter(user => user.name.includes(filter));

  return (
    <div className="user-list">
      <input type="text" value={filter} onChange={handleChange} placeholder="搜索用户" />

      <ul>
        {filteredUsers.map(user => (
          <li key={user.id}>
            <span>{user.name}</span>
            <button onClick={() => handleClick(user.id)}>选择</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

// ====== 工具函数部分 ======

const utils = {
  // 单参数无括号
  formatDate: date => new Date(date).toLocaleDateString(),

  // 多参数有括号
  debounce: (fn, delay) => {
    let timer;
    return (...args) => {
      clearTimeout(timer);
      timer = setTimeout(() => fn(...args), delay);
    };
  }
};

// ====== 类定义部分 ======

class ApiClient {
  constructor(baseURL) {
    this.baseURL = baseURL;
  }

  // 单参数无括号
  get = async path => {
    const response = await fetch(`${this.baseURL}${path}`);
    return response.json();
  };

  // 多参数有括号
  post = async (path, data) => {
    const response = await fetch(`${this.baseURL}${path}`, {
      method: 'POST',
      body: JSON.stringify(data)
    });
    return response.json();
  };
}

// ====== 导出部分 ======

export { getUser, addUser };
export default UserList;

以上就是项目统一格式化的全部内容!

相关推荐
To_OC11 小时前
LC 17 电话号码的字母组合:我的回溯算法,就是从这道题开窍的
javascript·算法·leetcode
vipbic11 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy11 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志11 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble12 小时前
c端系统,其实更像一个信息展示平台
前端
你怎么知道我是队长13 小时前
JavaScript的变量和数据类型介绍
开发语言·javascript·ecmascript
李姆斯13 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜14 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司14 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
心中有国也有家14 小时前
AtomGit Flutter 鸿蒙客户端:ModalBottomSheet 实战
android·javascript·学习·flutter·华为·harmonyos