阅读视图

发现新文章,点击刷新页面。

React基础框架搭建10-webpack配置:react+router+redux+axios+Tailwind+webpack

webpack配置

npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react
npm install --save-dev html-webpack-plugin clean-webpack-plugin
npm install --save-dev css-loader style-loader
npm install --save-dev file-loader url-loader
npm install --save-dev mini-css-extract-plugin
npm install --save-dev dotenv-webpack

在根目录创建webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const Dotenv = require('dotenv-webpack');

module.exports = {
    mode: 'development', // 开发模式
    entry: './src/index.js', // 入口文件
    output: {
        path: path.resolve(__dirname, 'dist'), // 输出目录
        filename: 'bundle.js', // 输出文件名
        publicPath: '/', // 公共路径
    },
    resolve: {
        extensions: ['.js', '.jsx'], // 解析的文件扩展名
        alias: {
            '@': path.resolve(__dirname, 'src'), // 设置路径别名
        },
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/, // 处理 JavaScript 和 JSX 文件
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env', '@babel/preset-react'], // Babel 配置
                    },
                },
            },
            {
                test: /\.css$/, // 处理 CSS 文件
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.(png|jpg|gif|svg)$/, // 处理图片文件
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[path][name].[ext]', // 保持原有路径和文件名
                        },
                    },
                ],
            },
        ],
    },
    devServer: {
        static: {
            directory: path.join(__dirname, 'dist'), // 更新为 static
        },
        compress: true, // 启用 gzip 压缩
        port: 3000, // 端口号
        historyApiFallback: true, // 支持 HTML5 History API
    },
    plugins: [
        new CleanWebpackPlugin(), // 清理输出目录
        new HtmlWebpackPlugin({
            template: './public/index.html', // HTML 模板
            filename: 'index.html', // 输出的 HTML 文件名
        }),
    ],
};

在 package.json 中添加 Webpack 的构建和开发脚本:

"scripts": {
    "start": "webpack serve --open", // 启动开发服务器
    "build": "webpack --mode production" // 构建生产版本
}

前端向架构突围系列 - 架构方法(三):前端设计文档的写作模式

Gemini_Generated_Image_awm4poawm4poawm4.png

引言:架构师的“身后事”

  • 痛点直击:你是否遇到过这种情况?新项目启动时写了几十页 文档 (打个比方) ,三个月后代码改得面目全非,文档却再也没人打开过。
  • 核心冲突:代码是写给机器看的(追求准确),文档是写给未来的团队看的(追求理解)。
  • 观点抛出:一份好的架构文档(ADD - Architecture Design Document)不是繁文缛节,它是团队协作的“契约”和技术决策的“黑匣子”。

1. 法则一:升维思考 —— 引入 C4 模型

上一篇我们讲了 UML(微观的画笔),这一篇我们要讲宏观的地图。

  • 为什么要引入 C4?

    • 传统的 4+1 视图对敏捷开发来说有时过于厚重。
    • C4 模型 (Context, Containers, Components, Code) 像 Google Maps 一样,提供了从“全球”到“街道”的 4 个缩放级别,更适合现代 Web 应用。
  • 前端视角的 C4 拆解(图文结合):

    • Level 1: System Context (系统上下文)
    • 画什么:你的 Web App 和外部系统(支付网关、老后端、CDN)的关系。
    • 给谁看:非技术人员、产品经理。
    graph TD
      A[电商前端] -->|HTTPS| B[支付网关]
      A -->|WebSocket| C[实时推荐服务]
      D[老后端] -->|REST| A
      E[CDN] -->|静态资源| A
    
    • Level 2: Containers (容器)

      • 画什么这是前端架构师的主战场。SPA 客户端、BFF 层 (Node.js)、微前端子应用、移动端 WebView。
      • 给谁看:开发团队、运维。
    graph TB
      subgraph 前端架构
        A[SPA客户端] -->|GraphQL| B[BFF层]
        B -->|RPC| C[微前端子应用]
        D[移动端WebView] -->|REST| B
      end
    
    • Level 3: Components (组件)

      • 画什么:不是 React UI 组件,是业务功能模块(如:购物车控制器、身份认证服务、日志模块)。
    graph LR
      A[购物车控制器] -->|事件总线| B[库存校验服务]
      A -->|LocalStorage| C[本地缓存]
      D[身份认证模块] -->|JWT| E[API网关]
    
    • Level 4: Code (代码)

      • 观点不要画! 代码变化太快,图通过 IDE 自动生成即可,画了必死。

2. 法则二:决策留痕 —— 架构决策记录 (ADR)

这是本文最“硬核”、最能体现架构师价值的部分。

  • 什么是 ADR?

    • 文档不仅要记录“由于什么(Result)”,更要记录“为什么(Why)”。
    • 很多时候,新同事骂代码烂,是因为他们不知道当年的约束条件
  • ADR 标准模板(直接给干货):

    • 标题:ADR-001 采用 Tailwind CSS 替代 Styled-components

    • 状态:已通过 / 已废弃 / 提议中

    • 背景 (Context) :现有 CSS-in-JS 方案导致 Bundle 体积过大,且团队命名困难。

    • 决策 (Decision) :全线引入 Tailwind CSS。

    • 后果 (Consequences)

      • (+) 这里的 HTML 会变丑。
      • (+) 样式文件体积减少 40%。
      • (-) 需要统一配置 ESLint 插件进行类名排序。
  • 建议

    • 不要把 ADR 写在 Word 里,要放在代码仓库的 /docs/adr 目录下。

3. 法则三:文档即代码 (Docs as Code)

如何保证文档“活着”?让它和代码住在一起。

  • 工具链推荐

    • 存储:Git 仓库(与 package.json 同级)。
    • 编写:Markdown。
    • 画图:Mermaid(直接在 Markdown 里写代码生成图,便于 Git Diff 对比修改)。
    • 发布:VitePress / Docusaurus(自动构建成静态站点)。
  • 目录结构示例

4. 落地模板:一份“不被嫌弃”的架构文档骨架

  1. 背景与目标 (1句话说明项目价值)

    • [痛点/现状] + [解决方案] + [量化价值]
    • 示例 : “打造企业级前端微服务基座,通过微前端架构解耦巨石应用,实现多团队独立部署,并统一全线产品的 UI 交互体验与鉴权逻辑。”

    image.png

  2. 约束条件 (必须兼容 IE?必须 2 周上线?)

    • 根据内部自定义
  3. 系统架构图 (示例)

    graph LR
    %% 重构类项目
    P1["老旧系统"] --> 
    S1["技术升级<br/>React 18 + Vite"] --> 
    V1["性能提升<br/>维护成本降低"]
    
    %% 高并发项目
    P2["CSR瓶颈"] --> 
    S2["SSR渲染<br/>CDN分发"] --> 
    V2["SEO优化<br/>转化率提升"]
    
    %% 中台项目
    P3["巨石应用"] --> 
    S3["微前端<br/>模块解耦"] --> 
    V3["独立部署<br/>团队协作优化"]
    
    %% 样式
    classDef pStyle fill:#ffebee,stroke:#f44336,color:#b71c1c
    classDef sStyle fill:#e3f2fd,stroke:#2196f3,color:#0d47a1
    classDef vStyle fill:#e8f5e9,stroke:#4caf50,color:#1b5e20
    
    class P1,P2,P3 pStyle
    class S1,S2,S3 sStyle
    class V1,V2,V3 vStyle
    
  4. 关键技术选型 (链接到具体的 ADR 文件)

    graph LR
    %% 技术分类
    框架选型 --> React
    构建工具 --> Vite
    渲染模式 --> NextJS
    架构方案 --> Qiankun
    
    %% 具体技术
    React["React 18"] --> ADR1[" ADR-001"]
    Vite["Vite 5.x"] --> ADR2["ADR-002"]
    NextJS[" Next.js SSR"] --> ADR3[" ADR-003"]
    Qiankun[" qiankun"] --> ADR4[" ADR-004"]
    
    %% 替代说明
    React -.->|替代 jQuery| Legacy1
    Vite -.->|替代 Webpack| Legacy2
    NextJS -.->|优化首屏| Target1["FCP < 1.5s"]
    Qiankun -.->|微前端基座| Target2["模块解耦"]
    
    %% 样式
    classDef cat fill:#f5f5f5,stroke:#616161,font-weight:bold
    classDef tech fill:#bbdefb,stroke:#1976d2,color:#0d47a1
    classDef adr fill:#c8e6c9,stroke:#388e3c,color:#1b5e20
    
    class 框架选型,构建工具,渲染模式,架构方案 cat
    class React,Vite,NextJS,Qiankun tech
    class ADR1,ADR2,ADR3,ADR4 adr
    
  5. 非功能性需求 (NFRs)

    • 性能:FCP < 1.5s
    • 安全:XSS 防护策略
    • 监控:Sentry 报警规则
    graph LR
        %% 根节点
        NFRs["非功能性需求"] --> Perf
        NFRs --> Sec
        NFRs --> Mon
    
        %% 性能需求
        Perf["性能需求<br/>Performance"] --> P1["首屏<1.5s"]
        Perf --> P2["交互<100ms"]
        Perf --> P3["资源优化"]
    
        %% 安全需求
        Sec["安全需求<br/>Security"] --> S1["XSS防护"]
        Sec --> S2["CSRF防护"]
        Sec --> S3["数据加密"]
    
        %% 监控需求
        Mon["监控需求<br/>Monitoring"] --> M1["错误率<0.1%"]
        Mon --> M2["性能告警"]
        Mon --> M3["用户追踪"]
    
        %% 样式
        classDef rootStyle fill:#34495e,stroke:#2c3e50,color:white,font-size:16px
        classDef perfStyle fill:#3498db,stroke:#2980b9,color:white
        classDef secStyle fill:#e74c3c,stroke:#c0392b,color:white
        classDef monStyle fill:#2ecc71,stroke:#27ae60,color:white
    
        class NFRs rootStyle
        class Perf,P1,P2,P3 perfStyle
        class Sec,S1,S2,S3 secStyle
        class Mon,M1,M2,M3 monStyle
    

概括总结

“架构师的产出不是文档,而是共识。”

好的架构文档,不是为了证明你通过了答辩,而是为了让新入职的同学在一年后看到这行代码时,能通过文档里的 ADR 明白: “哦,原来当初是为了性能才写得这么‘奇怪’的。”

这就是文档的价值——穿越时间的沟通。

前端向架构突围系列 - 架构方法(一):概述 4+1 视图模型

Gemini_Generated_Image_wtlcmdwtlcmdwtlc.png

这个模型由 Philippe Kruchten 在 1995 年提出。它的本质含义是:没有一种单一的视图能够涵盖系统的方方面面。不同的利益相关者(Stakeholders)关心的是不同的东西。

  • 业务方关心功能(能不能用?)。
  • 开发关心代码结构(好不好写?)。
  • 运维关心部署和硬件(稳不稳定?)。
  • 用户关心操作流程(顺不顺畅?)。

架构师的职责,就是通过这 5 个视角,把这些“鸡同鸭讲”的需求统一成一个完整的系统设计。

为了让你更好理解,我将这个经典的后端/通用架构概念,完整“翻译”成前端架构师的视角


1. 场景视图 (Scenarios / Use Cases View) —— “+1” 的那个核心

本质:系统的灵魂,它驱动了其他 4 个视图。 这是架构设计的起点。如果不知道系统要干什么,设计就无从谈起。

  • 关注点:用户怎么用这个系统?核心业务流程是什么?

  • 谁看:所有利益相关者(产品经理、测试、开发、用户)。

  • 前端架构视角

    • 这不是指某个具体的 Button 点击事件,而是关键链路 (Critical User Journeys)
    • 例子:用户进入首页 -> 登录 -> 浏览商品 -> 加入购物车 -> 结算。
    • 架构决策:如果“秒杀”是核心场景,那么你在后续的“处理视图”中就必须设计高并发的防抖策略;在“物理视图”中就要考虑 CDN 缓存。
graph LR
    %% 样式定义
    classDef icon fill:#fff9c4,stroke:#fbc02d,stroke-width:3px,color:#333,rx:50,ry:50;
    classDef step fill:#fff,stroke:#fbc02d,stroke-width:2px,color:#333,rx:10,ry:10;
    classDef note fill:#fffde7,stroke:none,color:#666;

    %% 左侧:核心概念
    User((用户<br/>User)):::icon

    %% 右侧:关键链路 (Critical Journey)
    subgraph Journey [关键链路: 秒杀场景]
        direction LR
        Step1[进入详情页]:::step --> Step2[抢购点击]:::step
        Step2 --> Step3[排队等待]:::step
        Step3 --> Step4[创建订单]:::step
        Step4 --> Step5[支付成功]:::step
    end

    User ==> Step1

    %% 架构决策点
    Note1(架构决策点:<br/>CDN缓存, 骨架屏):::note -.-> Step1
    Note2(架构决策点:<br/>高并发防抖, 乐观UI):::note -.-> Step2

2. 逻辑视图 (Logical View) —— “功能是怎么组织的?”

本质:系统的抽象模型。 这是最接近业务逻辑的一层,忽略具体的代码文件,只看概念

  • 关注点:系统有哪些“部件”?它们之间是什么关系?

  • 谁看:开发人员、业务分析师。

  • 前端架构视角

    • 组件模型:原子组件 vs 业务组件。
    • 领域模型:User, Product, Order 等实体定义(TypeScript Interface 定义)。
    • 状态管理设计:全局状态(Redux/Pinia)存什么?局部状态存什么?模块间如何通信?
    • 例子:画一张图,展示 OrderList 组件依赖 UserStoreAPI Service,而不关心它们具体写在哪个文件里。
graph LR
    %% 样式定义
    classDef icon fill:#e1f5fe,stroke:#039be5,stroke-width:3px,color:#333,rx:50,ry:50;
    classDef layer fill:#fff,stroke:#039be5,stroke-width:2px,color:#333,rx:5,ry:5;
    classDef rel stroke:#90caf9,stroke-width:2px,stroke-dasharray: 5 5;

    %% 左侧
    Logic((抽象<br/>逻辑)):::icon

    %% 右侧:分层架构
    subgraph LayerSystem [前端逻辑分层]
        direction TB
        UI[<b>表现层 UI Layer</b><br/>Button, Layout, Page]:::layer
        Adapter[<b>适配层 Adapter</b><br/>Hooks, Presenters]:::layer
        Domain[<b>领域层 Domain</b><br/>UserEntity, CartModel]:::layer
        Infra[<b>基础层 Infra</b><br/>Axios, Storage, Logger]:::layer
    end

    Logic ==> UI

    %% 依赖关系 (单向依赖是架构的关键)
    UI --> Adapter
    Adapter --> Domain
    Adapter --> Infra

3. 开发视图 (Development / Implementation View) —— “代码是怎么写的?”

本质:系统的静态组织结构。 这是程序员每天面对的 IDE 里的样子。

  • 关注点:文件目录怎么分?用什么框架?依赖怎么管?

  • 谁看:开发人员、构建工程师。

  • 前端架构视角

    • 工程化结构:Monorepo (Nx/Turborepo) 还是 Multirepo?
    • 目录规范src/components, src/hooks, src/utils 怎么归类?
    • 依赖管理package.json 里的依赖,公共库(Shared Library)如何抽取?
    • 构建工具:Vite/Webpack 配置,分包策略(Chunking)。
    • 例子:决定把所有的 API 请求封装在 @api 目录下,并禁止组件直接调用 axios,这就是开发视图的约束。
graph LR
    %% 样式定义
    classDef icon fill:#f3e5f5,stroke:#8e24aa,stroke-width:3px,color:#333,rx:50,ry:50;
    classDef file fill:#fff,stroke:#8e24aa,stroke-width:2px,color:#333,rx:2,ry:2;
    classDef tool fill:#f3e5f5,stroke:#8e24aa,stroke-width:1px,color:#333,stroke-dasharray: 5 5;

    %% 左侧
    Dev((工程<br/>代码)):::icon

    %% 右侧:目录与工具
    subgraph ProjectStructure [工程化与目录规范]
        direction TB
        
        subgraph Mono [Monorepo 仓库]
            Pkg1[packages/ui-lib]:::file
            Pkg2[apps/web-client]:::file
            Config[tsconfig.json]:::file
        end

        subgraph Toolchain [构建工具链]
            Vite(Vite / Webpack):::tool
            Lint(ESLint / Prettier):::tool
        end
    end

    Dev ==> Mono
    Mono -.-> Toolchain

4. 处理视图 (Process View) —— “系统是怎么运行的?”

本质:系统的动态行为、并发与性能。 对于前端来说,这是最容易被忽视,但最考验功底的一层。

  • 关注点:性能、并发、同步/异步、时序。

  • 谁看:系统集成人员、高级开发。

  • 前端架构视角

    • 异步流控:接口竞态问题(Race Condition)怎么处理?Promise 并发限制。
    • 生命周期:SSR(服务端渲染)的数据注水(Hydration)流程是怎样的?
    • 性能优化:Web Worker 处理复杂计算,避免阻塞主线程(UI 线程)。
    • 通信机制:WebSocket 怎么保持心跳?跨 Tab 通信(SharedWorker/LocalStorage)怎么做?
    • 例子:设计一个“大文件分片上传”的功能,你需要画出切片、上传、暂停、续传的时序图,这属于处理视图。

graph LR
    %% 样式定义
    classDef icon fill:#e8f5e9,stroke:#43a047,stroke-width:3px,color:#333,rx:50,ry:50;
    classDef action fill:#fff,stroke:#43a047,stroke-width:2px,color:#333,rx:10,ry:10;
    classDef async fill:#c8e6c9,stroke:none,color:#333,rx:5,ry:5;

    %% 左侧
    Run((运行<br/>时序)):::icon

    %% 右侧:大文件上传时序
    subgraph AsyncProcess [大文件分片上传流程]
        direction TB
        Start[开始上传]:::action --> Check{检查文件}:::action
        Check -->|太大| Slice[Web Worker<br/>进行切片计算]:::async
        Slice --> Upload[并发上传切片<br/>Promise.all]:::action
        Upload --> Pause{网络中断?}:::action
        Pause -->|是| Wait[暂停 & 记录断点]:::async
        Pause -->|否| Finish[合并请求]:::action
    end

    Run ==> Start

5. 物理视图 (Physical / Deployment View) —— “代码跑在哪里?”

本质:软件到硬件的映射。 前端代码最终是要通过网络传输并运行在用户设备上的。

  • 关注点:部署、网络拓扑、硬件限制。

  • 谁看:运维工程师 (DevOps)、系统管理员。

  • 前端架构视角

    • 部署策略:静态资源上 CDN,Nginx 反向代理配置。
    • 运行环境:BFF 层运行在 Docker 容器里;前端代码运行在用户的 Chrome/Safari 里(考虑兼容性)。
    • 网络环境:弱网情况下如何降级?离线包(PWA)策略。
    • 多端适配:同一套代码是跑在 PC 浏览器,还是内嵌在 App 的 WebView 里?
    • 例子:决定使用“灰度发布”系统,将新版本的 JS 文件只推给 10% 的用户,这属于物理视图的范畴。
graph LR
    %% 样式定义
    classDef icon fill:#fff3e0,stroke:#fb8c00,stroke-width:3px,color:#333,rx:50,ry:50;
    classDef device fill:#fff,stroke:#fb8c00,stroke-width:2px,color:#333,rx:5,ry:5;
    classDef net fill:#ffe0b2,stroke:none,color:#333,rx:20,ry:20;

    %% 左侧
    Deploy((部署<br/>环境)):::icon

    %% 右侧:部署拓扑
    subgraph NetworkTopology [资源分发与运行环境]
        direction LR
        
        subgraph Cloud [云端设施]
            CICD[CI/CD 构建产物]:::device --> OSS[对象存储]:::device
            OSS --> CDN((CDN 边缘节点)):::net
        end

        subgraph Client [用户终端]
            CDN --> Browser[PC 浏览器]:::device
            CDN --> Mobile[手机 WebView]:::device
            CDN --> Hybrid[小程序]:::device
        end
    end

    Deploy ==> Cloud

总结:软件开发的本质是什么?

通过 4+1 视图,我们可以得出软件开发的本质:

  1. 控制复杂度 (Managing Complexity) : 如果没有分层和视图,系统就是一团乱麻。4+1 试图把复杂问题拆解成 5 个维度分别解决。

  2. 沟通与妥协 (Communication & Trade-offs) : 架构不是追求“完美的代码”,而是平衡各方利益。

    • 为了物理视图的加载速度(上 CDN),可能要牺牲开发视图的便利性(复杂的构建流程)。
    • 为了处理视图的流畅度(虚拟列表),可能要增加逻辑视图的复杂度。

此时此刻,你可以做的 Next Step

作为想转型的架构师,不要只写代码,开始写文档

你可以挑选你当前负责的一个复杂模块,尝试写一份简易版的技术设计文档 (TDD) ,强制自己包含以下三点:

  1. 逻辑图:用方块图画出组件和数据流。
  2. 处理图:用时序图画出关键的用户交互流程。
  3. 部署说明:说明代码构建后怎么发布,有没有缓存策略。

年薪 50W 的前端,到底比年薪 15W 的强在哪里?

65ef63f6bd30ab838939a4ae_Developer productivity tools 2024.webp

昨天我看新年第一波简历 看破防了

最近团队缺人,我连着看了一周的简历。

说实话,看得我挺难受的。😖

我发现一个特别普遍的现象:很多工作了四五年的兄弟,期望薪资填个 25k 甚至 30k,但你仔细翻他的项目经历,全是后台管理系统,全是 H5 拼图页面,全是表单增删改查。

你问他:这几年你遇到的最大技术难点是啥?🤔

他回你:表单字段太多了,校验逻辑太复杂。或者说,产品经理改需求太频繁。😖

听到这种回答,我心里大概就有了底:这兄弟的薪资上限,大概率锁死在 20W 以内了。

这就是咱们常说的 CRUD 困局。

你会 Vue,你会 React,你会用 Antd 画页面,你会调接口。兄弟,这些在 2018 年也许能让你拿高薪,但现在是 2026 年了,这些东西是基建,是培训班出来的应届生两个月就能上手的。🤣

那么问题来了,那个坐在你隔壁工位、平时话不多、但年薪能拿 50W 的大佬,他到底比你强在哪?

是他敲键盘比你快?还是他发量比你少?

都不是。

我觉得最核心的差距,就只有三点。听我细说。


你在做填空,他在设计整张试卷

web-development-programmer-engineering-coding-website-augmented-reality-interface-screens-developer-project-engineer-programming-software-application-design-cartoon-illustration_107791-3863.avif

这事儿特别明显。就拿新开一个项目来说。

15W 的兄弟是怎么干的?

找个脚手架,create-react-app 一把梭。然后开始堆页面,写组件。遇到要用的工具函数?去百度搜一个粘贴进来。遇到样式冲突?加个 !important 搞定。代码格式乱了?不管了,先跑通再说。

他的脑子里只有一个字:做。

50W 的兄弟是怎么干的?

他在写第一行业务代码之前,会先在脑子里过一遍这几件事:

大家代码风格不一样怎么办?先把 ESLint + Prettier + Husky 这一套流水线配好,谁提交的代码格式不对,连 git push 都推不上去。

这个项目以后会不会变大?要不要直接上 Monorepo 管理?

公共组件怎么抽离?是不是该搭个私有 npm 库?

打包速度怎么优化?Vite 的配置能不能再调调?

这就是差距。🤔

老板愿意给他 50W,不是因为他页面画得快,而是因为他制定了标准。他一个人,能让团队剩下 10 个人的产出质量变高。这叫工程化视野,这才是值钱的玩意儿。


出了事,你只会甩锅,他能兜底

software-developer-vs-software-engineer-illustration.jpg

场景再具体点:用户投诉页面卡顿,加载慢。

15W 的兄弟通常反应是这样的:

打开控制台 Network 看一眼。

哎呀,接口这就 800ms 了,这后端不行啊,锅在服务端。

嗨🙂‍↔️,这图片 UI 给得太大了,切图没切好。

这数据量几万条,浏览器渲染本来就慢,我也没办法!

总之,只要不是 JS 报错,这事儿就跟我没关系。

50W 的兄弟会干嘛?

他不会废话,他直接打开 Chrome 的 Performance 面板,像做外科手术一样分析。

这一段掉帧,是不是触发了强制重排?

内存这一路飙升,是不是哪个闭包没释放,或者 DOM 节点没销毁?

主线程卡死,是不是长任务阻塞了渲染?能不能开个 Web Worker 把计算挪出去?

网络慢,是不是 HTTP/2 的多路复用没吃满?关键资源的加载优先级设对了吗?

这就叫底层能力。🤔

平时写业务看不出来,一旦遇到高并发、大数据量、若网环境这种极端场景,只会调 API 的人两手一摊,而懂底层原理的人能从浏览器内核里抠出性能。

这种 兜底能力,就是你的溢价。


他是业务合伙人!

How-to-become-a-Backend-Developer.jpg

这点最扎心。

产品经理提了个不靠谱的需求,比如要在手机端展示一个几百列的超级大表格。

15W 的兄弟:

心里骂娘:这傻X产品,脑子有坑。😡🤬

嘴上老实:行吧,我尽量试试。

结果做出来卡得要死,体验极差,上线被用户骂,回来接着改,陷入无尽加班。

这种思维模式下,你就是个执行资源,也就是个 打工人。

50W 的兄弟:

他听完需求直接就怼回去了:

哥们,在手机上看几百列表格,用户眼睛不要了?你这个需求的业务目标是啥?是为了让用户核对数据?

如果是核对数据,那我们要不要换个方案,只展示关键指标,点击再下钻看详情?这样开发成本低了 80%,用户体验还好。

这就叫技术变现。

高端的前端,不仅仅是写代码的,他是懂技术的业务专家。他能用技术方案去纠正产品逻辑,帮公司省钱,帮业务赚钱。

在老板眼里,你是成本,他是投资。🤷‍♂️


哪怕现在是 15W,咱也能翻盘

如果你看上面这些话觉得膝盖中了一箭,别慌。谁还不是从切图仔过来的?

想打破这个 CRUD 的怪圈,从明天上班开始,试着变一下:

别再只盯着那几个 API 了

Vue 文档背得再熟也就是个熟练工。去看看源码,看看人家是怎么设计响应式的,看看 React 为什么要搞 Fiber。懂了原理,你就不怕框架变。

别做重复工作

下次想复制粘贴工具函数的时候,停一下。试着自己封装一个通用的,甚至试着把你们项目里重复的逻辑抽成一个库。工程化就是这么一点点做起来的。

钻进去一个细分领域

别啥都学,啥都学不精。

可视化、低代码、Node.js 中间件、音视频,随便挑一个,把它钻透。在任何一个细分领域做到前 5%,你都有议价权。


还是那句话!前端并没有死,死的是那些 只会切图和调接口 的工具人。

50W 的年薪,买的不是你的时间,而是你 解决复杂问题 的能力,和你 避免团队踩坑 的经验。

别再满足于重复做一个 CRUD 了。下次打开编辑器的时候,多问自己一句:

除了把这个功能做出来,我还能为这段代码多做点什么?

共勉🙌

Suggestion (2).gif

React基础框架搭建7-测试:react+router+redux+axios+Tailwind+webpack

现在可以对之前弄得一些内容进行测试了

npm下载:

npm install --save-dev @testing-library/react @testing-library/jest-dom

有些可能需要安装:

npm install --save-dev @babel/plugin-proposal-private-property-in-object

单元测试请按如下方式进行:

//src/views/Home/__tests__/Home.test.js

import React from 'react';
import { render, screen } from '@testing-library/react';
import Home from '../Home';

test('renders welcome message', () => {
    render(<Home />);
    const linkElement = screen.getByText(/Hello/i);
    expect(linkElement).toBeInTheDocument();
});

运行:

npm test
❌