近期关于前端架构设计的一些思考

一个成功的项目需要一个合理的架构设计,这个架构设计需要考虑到项目的需求、技术栈、团队规模、团队技术水平、项目规模、项目周期、项目预算等多方面的因素。在这篇文章中,我将分享一些关于前端架构设计的思考,希望对您有所帮助。

首先,让我们来看一下一个典型的现代Web应用的架构设计。本文梳理思路时,采用的技术栈是React + Vite + TypeScript,后端假设是使用restful接口的方式,会配置好跨域,前端部署采用Docker容器化,部署到Azure云平台。

架构设计宗旨

前端架构:使用现代化的前端技术栈,如 React 或者 Vue,配合 Vite 或者 Webpack 进行构建,使用 TypeScript 进行开发,使用状态管理库(如 Redux、MobX、Zustand)进行状态管理,使用路由库(如 React Router、Vue Router)进行路由管理,使用UI库(如 Ant Design、Element UI)进行UI设计,网络请求方面使用swr对axios进行封装,使用Jest、Playwright等工具进行测试,使用Lighthouse等工具进行性能测试和优化,使用Storybook进行组件驱动开发。

后端架构:这块我们可能简单的带过一下,假设后端使用restful接口的方式,提供数据服务,采用OAuth 2.0和JWT进行身份验证和授权,使用Swagger生成API文档。

部署架构:使用Docker容器化应用,部署到云平台,使用DevOps进行持续集成/持续部署。

具体的实施的原则

性能优化:应用在各种网络条件下都能提供良好的性能,可以使用Lighthouse等工具进行性能测试和优化。

安全性:应用有足够的安全措施,包括身份验证、数据加密、输入验证等。

可扩展性:应用可以轻松扩展,包括水平和垂直扩展,以应对未来的增长。

可维护性:代码易于维护,包括良好的文档、清晰的代码结构、合理的命名等。

测试覆盖率:应用有足够的测试覆盖率,包括单元测试、集成测试和端到端测试。

监控和日志:应用有足够的监控和日志记录,以便及时发现和解决问题。

文档:应用有足够的文档,包括用户文档、API文档、架构文档等。

团队协作:团队有良好的协作机制,包括代码审查、持续集成、持续部署等。

用户体验:应用提供良好的用户体验,包括响应式设计、无障碍访问、国际化等。

成本优化:应用在云平台上的成本是可控的,包括资源利用率、自动伸缩等。

灾难恢复:应用有灾难恢复计划,包括备份策略、故障转移等。

用户反馈:应用有良好的用户反馈机制,包括用户调查、错误报告等。

一个可能的技术栈

下面是一个可能的技术栈,基于上述架构设计的考虑的实践,

  • react + vite + typescript: 基本的架子

  • zustand: 状态管理

  • react-router: 路由管理

  • arco-design: UI库

  • docker: 容器化部署

  • cos: 静态资源存储

  • jest + playwright: 测试工具

  • lighthouse: 性能工具

  • prometheus + grafana + ELK Stack: 监控和日志

  • storybook: 组件驱动开发

  • oauth2.0/jwt: 身份验证

  • azure devops/github actions: 持续集成/持续部署

  • swagger: 文档工具

  • hotjar: 用户反馈

  • owasp zap: 静态代码扫描

  • eslint + prettier: 代码规范和风格指南

下面是一些关于这些技术的简要说明:

React + Vite + TypeScript:这是一个强大的组合,React 提供了灵活的组件模型,Vite 作为下一代前端工具提供了极快的冷启动和即时模块热更新,TypeScript 提供了静态类型检查,可以提高代码质量和可维护性。

状态管理(Zustand):Zustand 是一个轻量级的状态管理库,它提供了简单直观的API,易于上手,且不需要像 Redux 那样的繁琐配置,适合中小型项目,而且配合 persist 可以实现状态持久化。以下是一个简单的示例:

javascript 复制代码
import create from 'zustand';
//persist
import { persist } from 'zustand/middleware';

const useStore = create(
  persist(
    (set) => ({
      count: 0,
      increment: () => set((state) => ({ count: state.count + 1 })),
      decrement: () => set((state) => ({ count: state.count - 1 })),
    }),
    {
      name: 'counter-store', // unique name
    }
  )
);

const Counter = () => {
  const count = useStore((state) => state.count);
  const increment = useStore((state) => state.increment);
  const decrement = useStore((state) => state.decrement);

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

export default Counter;

路由(React Router):React Router 是一个流行的路由库,它提供了强大的路由功能,适合构建单页面应用,最新的版本还支持了路由懒加载和代码分割,可以提高应用的性能,而且还支持loaders,可以实现路由级别的数据预加载,提高用户体验。一下是一个loader的示例:

javascript 复制代码
const HomeLoader = () => import('home/HomeLoader');
const AboutLoader = () => import('about/AboutLoader');

const routes = [
  {
    path: '/',
    component: HomeLoader,
  },
  {
    path: '/about',
    component: AboutLoader,
  },
];

const App = () => (
  <Router routes={routes} />
);

export default App;

UI库(Arco Design):Arco Design 是一个相对较新的组件库,它提供了一套企业级产品的UI解决方案,相对于 Ant Design 和 Element UI,它更加现代化,更加灵活,更加易于定制,适合构建现代化的Web应用。

Docker部署:使用Docker可以确保环境一致性,简化部署流程,是当前的行业标准。 Azure提供了一套完整的容器服务,可以帮助您轻松部署和管理容器化应用。当然国内可以使用阿里云或者 腾讯云的容器服务。具体的做法是将前端打包后的静态资源放到Nginx容器中,然后部署到云平台。下面是一个简单的Dockerfile示例:

dockerfile 复制代码
# 使用官方的nginx镜像作为基础镜像
FROM nginx:alpine

# 将打包后的静态资源复制到Nginx的默认目录
COPY build /usr/share/nginx/html

# 暴露80端口
EXPOSE 80

CDN:使用CDN可以加速静态资源的加载,提高应用的性能。Azure提供了一套完整的CDN服务,可以帮助您轻松部署和管理CDN。前端打包后的静态资源可以上传到CDN,加速用户访问。当然还需要哦提供一个发布脚本,将静态资源上传到CDN。下面是一个可能的发布打包后的静态资源到腾讯云cos的 node.js脚本示例:

javascript 复制代码
const COS = require('cos-nodejs-sdk-v5');
const fs = require('fs');

// 初始化COS客户端
const cos = new COS({
  SecretId: 'yourSecretId
    SecretKey: 'yourSecretKey', // 注意信息安全,不要将密钥暴露在代码中
    Region: 'ap-guangzhou',
    Bucket: 'yourBucket',
    // 可选参数
    FileParallelLimit: 3,
    ChunkParallelLimit : 3,
    ChunkSize: 1024 * 1024,
    ProgressInterval: 1000,
    Proxy: '',
    Protocol: 'https',
});

// 上传静态资源到COS
cos.putObject({
  Bucket: 'yourBucket',
  Region: 'ap-guangzhou',
  Key: 'yourKey',
  Body : fs.createReadStream('yourStaticResource'),
}, function (err, data) { console.log(err || data); });

测试工具(Jest + Playwright):Jest 是一个广泛使用的JavaScript测试框架,适合单元和集成测试。Playwright 是一个强大的端到端测试工具,支持多浏览器测试。这里有一些最佳实践,什么时候使用单元测试,什么时候使用端到端测试,如何编写测试用例,如何集成测试工具到CI/CD流程:

javascript 复制代码
    // 单元测试
    test('adds 1 + 2 to equal 3', () => {
      expect(sum(1, 2)).toBe(3);
    });

    // 端到端测试
    test('should display the correct title', async () => {
      await page.goto('https://example.com');
      const title = await page.title();
      expect(title).toBe('Example Domain');
    });
yaml 复制代码
   # GitHub Actions配置文件
   name: CI

   on:
       push:
       branches:
           - main
       pull_request:
       branches:
           - main

   jobs:
       test:
           runs-on: ubuntu-latest

           steps:
           - name: Checkout code
               uses: actions/checkout@v2

           - name: Install dependencies
               run: npm install

           - name: Run tests
               run: npm test

可以看到,我们在这里使用了Jest进行单元测试,Playwright进行端到端测试,同时使用GitHub Actions进行持续集成。单元测试适合测试单个函数或模块,端到端测试适合测试整个应用的功能,持续集成可以确保每次提交都会自动运行测试,确保代码质量。

性能工具Lighthouse:Lighthouse 是一个开源的自动化工具,用于改进网络应用的质量,非常适合进行性能测试。可以集成到CI/CD流程中,确保每次提交都会自动运行性能测试,以便及时发现和解决性能问题。方式是在CI/CD流程中添加一个Lighthouse测试的步骤,如下所示:

yaml 复制代码
# GitHub Actions配置文件
name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
    test:
        runs-on: ubuntu-latest

        steps:
        - name: Checkout code
            uses: actions/checkout@v2

        - name: Install dependencies
            run: npm install

        - name: Run tests
            run: npm test

        - name: Run Lighthouse test
            run: npx lighthouse https://example.com --output json --output-path=./lighthouse-report.json

日志监控(Prometheus + Grafana + ELK Stack):这是一套强大的监控和日志管理组合,可以帮助您及时发现和解决问题。以下是一个简单的配置示例:

yaml 复制代码
# Prometheus配置文件
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
    - job_name: 'node'
        static_configs:
        - targets: ['localhost:9100']

# Grafana配置文件
apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://localhost:9090
    isDefault: true

# ELK Stack配置文件
input {
  file {
    path => "/var/log/nginx/access.log"
    start_position => "beginning"
  }
}

filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
  }
}

组件驱动开发(Storybook):Storybook 是一个出色的工具,用于构建和测试UI组件,它可以提高开发效率并确保组件质量。关键是可以解决组件的复用性和可维护性问题。引入storybook后,可以在本地开发环境中独立开发和测试组件,然后将组件集成到应用中。以下是一个简单的配置示例:

step1. 安装storybook

bash 复制代码
npx sb init

step2. 编写组件,假设我们有一个Button组件

javascript 复制代码
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import Button from './Button';

storiesOf('Button', module)
  .add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
  .add('with emoji', () => (
    <Button onClick={action('clicked')}>
      <span role="img" aria-label="so cool">
        😀 😎 👍 💯
      </span>
    </Button>
  ));

身份验证(OAuth2.0/JWT):OAuth 2.0 和 JWT 是当前Web应用中常用的身份验证和授权机制,它们可以提供安全的用户认证流程。 OAuth 2.0 是一个开放标准,它允许用户授权第三方应用访问其资源,而无需提供用户名和密码。他的原理是通过授权码的方式,获取access token,然后使用access token访问资源。以下是一个简单的 GitHub OAuth 2.0示例:

javascript 复制代码
const express = require('express');
const axios = require('axios');
const qs = require('querystring');

const app = express();

const CLIENT_ID = 'your-github-client-id';
const CLIENT_SECRET = 'your-github-client-secret';

app.get('/login/github', (req, res) => {
  res.redirect(`https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}`);
});

app.get('/github/callback', async (req, res) => {
  const { code } = req.query;

  const response = await axios({
    method: 'post',
    url: `https://github.com/login/oauth/access_token?client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&code=${code}`,
    headers: {
      accept: 'application/json'
    }
  });

  const accessToken = response.data.access_token;
  console.log(`Access Token: ${accessToken}`);

  res.redirect(`/welcome`);
});

JWT 是一种轻量级的身份验证和授权机制,它使用JSON Web Token(JWT)来传递用户信息,可以提供安全的用户认证和授权流程。下面是一个简单的JWT示例:

javascript 复制代码
// 假设服务端的实现是这个样子,但可能你的后端使用go来实现
const express = require('express');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');

const app = express();

app.use(bodyParser.json());

const SECRET_KEY = 'your-secret-key';

app.post('/login', (req, res) => {
  const { username, password } = req.body;

  // 这里应该添加验证用户名和密码的逻辑
  // 为了简单起见,我们假设任何用户都可以登录

  const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' });

  res.json({ token });
});

app.get('/protected', (req, res) => {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) return res.sendStatus(401);

  jwt.verify(token, SECRET_KEY, (err, user) => {
    if (err) return res.sendStatus(403);

    res.send(`Hello ${user.username}, you accessed protected route!`);
  });
});

app.listen(3000, () => console.log('Server started on port 3000'));


// 假设客户端的实现是这个样子

async function login(e) {
  const username = document.getElementById('username').value;
  const password = document.getElementById('password').value;

  const response = await fetch('http://localhost:3000/login', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ username, password })
  });
  const data = await response.json();
  token = data.token;
  // 保存token到本地存储
  localStorage.setItem('token', token);
}

async function accessProtected() {
  const token = localStorage.getItem('token');
  const response = await fetch('http://localhost:3000/protected', {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });

  const data = await response.text();
  alert(data);
}

持续集成/持续部署(Azure DevOps/GitHub Actions):Azure DevOps 和 GitHub Actions 都是流行的CI/CD工具,可以帮助您自动化测试和部署流程, 以下是一个简单的配置示例:

yaml 复制代码
# Azure DevOps配置文件
trigger:
  branches:
    include:
      - main

pool:
    vmImage: 'ubuntu-latest'

steps:
- task: NodeTool@0
  inputs:
    versionSpec: '14.x'
  displayName: 'Install Node.js'

- script: |
    npm install
    npm test
    displayName: 'Install and test'

- task: PublishPipelineArtifact@1
    inputs:
        targetPath: '$(System.DefaultWorkingDirectory)/dist'
        artifact: 'dist'
        publishLocation: 'pipeline'

# GitHub Actions配置文件
name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
    test:
        runs-on: ubuntu-latest

        steps:
        - name: Checkout code
            uses: actions/checkout@v2

        - name: Install dependencies
            run: npm install

        - name: Run tests
            run: npm test

文档工具(Swagger):Swagger 是一个流行的API文档工具,它可以帮助您自动生成API文档,并提供交互式API测试功能。以下是一个简单的配置示例:

用户反馈(Hotjar):Hotjar 是一个流行的用户反馈工具,它可以帮助您了解用户行为和需求,以便改进产品,他的使用方式是在页面中添加一个脚本,然后就可以收集用户行为数据了。

html 复制代码
<!-- Hotjar Tracking Code for https://your-website.com -->
<script>
    (function(h,o,t,j,a,r){
        h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
        h._hjSettings={hjid:1234567,hjsv:6};
        a=o.getElementsByTagName('head')[0];
        r=o.createElement('script');r.async=1;
        r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
        a.appendChild(r);
    })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>

国内可以使用神策分析或者GrowingIO等工具,示例代码如下:

javascript 复制代码
// 神策分析
sensorsdata.track('button_click', {
  button_id: 'your-button-id',
  button_text: 'your-button-text'
});

// GrowingIO

gio('track', 'button_click', {
  button_id: 'your-button-id',
  button_text: 'your-button-text'
});

安全工具(OWASP ZAP):OWASP ZAP 是一个流行的安全测试工具,它可以帮助您发现和解决安全问题,如跨站脚本(XSS)、SQL注入、CSRF等。静态扫描工具可以在CI/CD流程中集成,以便及时发现和解决安全问题。以下是一个简单的配置示例:

yaml 复制代码
# GitHub Actions配置文件
name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
    test:
        runs-on: ubuntu-latest

        steps:
        - name: Checkout code
            uses: actions/checkout@v2

        - name: Install dependencies
            run: npm install

        - name: Run tests
            run: npm test

        - name: Run OWASP ZAP test
            run: docker run -t owasp/zap2docker-stable zap-baseline.py -t https://example.com -l Low

一些额外的考虑点

代码规范和风格指南:确保团队遵循统一的编码标准,可以使用ESLint和Prettier等工具自动化代码格式化和质量检查。必要的时候可以使用Husky和Lint-staged等工具在提交代码前进行代码检查。同时也可以自己编写一些eslint的规则,以确保代码质量。

备份和灾难恢复:确保应用有足够的备份策略,以便在发生灾难时能够及时恢复。可以使用Azure的备份服务,或者自己编写一个备份脚本。不过有docker的话,可以使用docker的备份和恢复功能。至于更加强的方式,比如两地三中心,这里就不展开了。

安全性:除了身份验证,还要考虑其他安全措施,如输入验证、CSRF保护、CORS策略等。即便在静态代码扫描环节有些漏掉的,也可以在部署环节使用WAF等工具进行安全防护。

可访问性(Accessibility):应用遵循WCAG指南,使其对所有用户都是可访问的,比如说盲人、色盲、聋哑等。但是这个一般是在产品上线后,再进行优化。

国际化(i18n):如果您的应用需要支持多语言,那么从一开始就考虑国际化是很重要的,因为在后期添加国际化会比较麻烦,需要修改大量的代码。不止是前端,后端也需要考虑国际化。如error message,返回的数据等。

响应式设计(Responsive Design):确保应用在各种设备上都能提供良好的用户体验,可以使用CSS媒体查询和弹性布局等技术实现响应式设计。这部分通常来讲可能不太容易处理,因为涉及到设计和前端的协作。而且移动端的体验和PC端的体验天然是不一样的,举一个例子,PC端的表格是可以横向滚动的,但是移动端的表格是不可以横向滚动的。pc端用户可以做适当的编辑工作,移动端因为屏幕小,所以尽量不要让用户做过重的编辑工作。

下面是一个响应式设计的示例:

css 复制代码
/* pc上可以是网格布局 */
.container {
  display: grid;
  grid-template-columns: auto auto auto;
  grid-gap: 10px;
  padding: 10px;
}

/* 响应式设计,移动端变为flex */
@media (max-width: 600px) {
  .container {
    display: flex;
    flex-direction: column;
  }
}

关于前端架构设计的思考就到这里,希朝对您有所帮助。当然,这只是一些思考,实际的项目中可能会有更多的考虑点,比如说项目的特殊需求、团队的特殊情况等。希望您在实际项目中能够根据实际情况进行合理的架构设计,确保项目的成功。

欢迎关注我的微信公众号老码沉思录和我一起交流!

相关推荐
白总Server3 小时前
多智能体系统的中间件架构
linux·运维·服务器·中间件·ribbon·架构·github
萌萌哒草头将军4 小时前
⚡⚡⚡尤雨溪宣布开发 Vite Devtools,这两个很哇塞 🚀 Vite 的插件,你一定要知道!
前端·vue.js·vite
小彭努力中4 小时前
7.Three.js 中 CubeCamera详解与实战示例
开发语言·前端·javascript·vue.js·ecmascript
浪裡遊5 小时前
跨域问题(Cross-Origin Problem)
linux·前端·vue.js·后端·https·sprint
LinDaiuuj5 小时前
判断符号??,?. ,! ,!! ,|| ,&&,?: 意思以及举例
开发语言·前端·javascript
敲厉害的燕宝5 小时前
Pinia——Vue的Store状态管理库
前端·javascript·vue.js
uhakadotcom5 小时前
过来人教你写简历的技巧(如何写简历,个人评价 / 个人优势如何写)
面试·架构·github
Aphasia3115 小时前
react必备JavaScript知识点(二)——类
前端·javascript
玖玖passion5 小时前
数组转树:数据结构中的经典问题
前端
呼Lu噜5 小时前
WPF-遵循MVVM框架创建图表的显示【保姆级】
前端·后端·wpf