V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
zhangfg
V2EX  ›  分享创造

腿夹腿,带你用 react 撸后台,系列一(Vite 篇)

  •  
  •   zhangfg · 1 天前 · 2549 次点击

    Github 地址 | 文档地址 | 预览地址

    react-antd-console 是一个后台管理系统的前端解决方案,封装了后台管理系统必要功能(如登录、鉴权、菜单、面包屑、标签页等),帮助开发人员专注于业务快速开发。项目基于 React 18Ant design 5ViteTypeScript 等新版本。对于使用到的各项技术,会被持续更新至最新版本。可放心用于生产环境。

    为了方便大家更好的掌握和使用本项目,推出系列文章:

    • 腿夹腿,带你用 react 撸后台,系列一( Vite 篇)

    如果你喜欢这个项目或认为对你有用,欢迎使用体验和 Star

    1. 概述

    首先我们需要搞定构建工具问题,我们使用了 Vite 作为构建工具

    Vite 是一个超快速的前端构建工具,推动着下一代网络应用的发展

    Vite 最大的特点是启动极速(通常 1s 内)、轻量快速的热更新、对 TypeScript 、JSX 、CSS 等支持开箱即用。相较于 Webpack 传统构建工具,其配置极简,并同样可以实现我们想要的诸多功能,维护心智负担极低

    1.1 Vite 的问题

    如果一个构建工具存在瓶颈,那么哪怕其他有再好的方面,最终也无法选用。所以我们不能忽视 Vite 的缺点。那就是:

    1.1.1 刷新页面慢?

    Vite 因为减少了源文件( JS/TS/CSS )的工作量,导致并发请求多而拖慢刷新页面的速度。但结合启动和热更新,在速度上,相比 Webpack ,本文档认为仍然具有明显的优势

    本项目在开发启动后,刷新首页,共有 168 项请求,耗时 150 至 200 毫秒。作为参考

    1.1.2 开发和打包不一致?

    理论上是有可能的,因为 Vite 开发使用 esbuild, 打包使用 rollup 。但实际情况中,作者从没有碰到过不一致的情况。而且 Vite 即将使用 Rolldown 作为底层打包工具。Rolldown 将保证开发和打包结果完全一致,并提供更快的打包速度。届时可平滑升级

    2. Vite 内置

    Vite 内置了很多开箱即用的功能,本项目用到的内置功能有:

    2.1 样式

    样式预处理器我们使用的是 Less。在 Vite 中,只需要安装 less 模块即可直接使用

    npm i -D less
    

    本项目没有额外配置 less 选项,若需要进一步配置,可参考 Vite 配置 css.preprocessorOptions

    2.1.1 打包后,样式名自动加前缀

    对于样式名,不同浏览器可能有不同的前缀,例如 -webkit--ms--moz- 等。但我们写代码时并不想写这些前缀,但打包时可以自动生成。Vite 中如果项目包含有效的 PostCSS 配置 (任何受 postcss-load-config 支持的格式,例如 postcss.config.cjs),它将会自动应用于所有已导入的 CSS 。

    安装 PostCSS 插件 autoprefixer

    npm i -D autoprefixer
    

    <root>/postcss.config.cjs 中配置自动前缀插件即可生效:

    // postcss.config.cjs
    module.exports = {
      plugins: [
        require('autoprefixer'),
      ],
    };
    

    参考文档:

    2.2 入口

    • html 入口为根目录的 <root>/index.html,可在该 html 中引入入口 ts/tsx 文件
    • 入口 ts/tsx 文件 位于 src/main.tsx,在该文件中,初始化了 react 等

    说明:

    • 在开发时,访问本地服务根路径,会返回上述 html 文件
    • 在打包后,根目录的 <root>/dist 文件夹中也会包含打包后的 html 文件,其源码被引入的 ts/tsx 文件和路径,会被自动转换成打包后的文件和路径

    打包前:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>react-antd-console</title>
      </head>
      <body>
        <div id="root"></div>
        <script type="module" src="/src/main.tsx"></script>
      </body>
    </html>
    

    打包后:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>react-antd-console</title>
        <script type="module" crossorigin src="/assets/index-B68Xj7Fq.js"></script>
        <link rel="stylesheet" crossorigin href="/assets/index-CHnsXl1V.css">
      </head>
      <body>
        <div id="root"></div>
      </body>
    </html>
    

    2.3 打包

    当我们通过 package.json 中的 npm run build:prod 命令打包时,其实是调用了 vite build --mode prod命令。默认情况下,它使用 <root>/index.html 作为其构建入口点,并生成能够静态部署的应用程序包 <root>/dist/。若要部署,我们将打完的包放到 nginx 等服务上即可

    我们还可以指定打包后的文件所支持的浏览器目标,例如指定为支持 es2015 浏览器

    // vite.config.js
    export default defineConfig({
      build: {
        target: 'es2015',
      },
    })
    

    参考文档:

    2.4 public 目录

    public 目录 位于根目录的 <root>/public 文件夹。该目录中的资源在开发时能直接通过 / 根路径访问到,并且打包时会被完整复制到目标目录的根目录下

    3. Vite 配置

    另外有些功能是需要配置的,Vite 配置极其简洁。配置文件位于根目录的 <root>/vite.config.ts 如下:

    // vite.config.ts
    export default defineConfig({
      plugins: [
        react(),
        createSvgIconsPlugin({
          iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')],
          symbolId: 'icon-[dir]-[name]',
        }),
      ],
      resolve: {
        alias: {
          '@': path.resolve(__dirname, './src'),
          '@@': path.resolve(__dirname, './examples'),
        },
      },
      server: {
        host: true,
        port: 9527,
        proxy: {
          '/api': {
            target: 'http://localhost:3000',
            changeOrigin: true,
            rewrite: (path) => path.replace(/^\/api/, ''),
          },
        },
      },
      esbuild: {
        target: 'chrome65',
      },
      build: {
        target: 'es2015',
      },
    });
    

    以下功能为配置后生效的功能:

    3.1 开发服务

    // vite.config.js
    export default defineConfig({
      server: {
        host: true,
        port: 9527,
        proxy: {
          '/api': {
            target: 'http://localhost:3000',
            changeOrigin: true,
            rewrite: (path) => path.replace(/^\/api/, ''),
          },
        },
      },
    })
    
    • server.host 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址
    • server.port 指定开发服务器端口
    • server.proxy 为开发服务器配置自定义代理规则。具体配置继承自 http-proxy
      • 解释: 当请求 /api 开头的 url 时,该请求会被代理到 http://localhost:3000 ,并且请求路径会自动去除 /api

    启动服务后,Vite 会使用 esbuild 作为编译工具,我们指定下编译的文件所支持的浏览器版本为 chrome65 以上:

    // vite.config.js
    export default defineConfig({
      esbuild: {
        target: 'chrome65',
      },
    })
    

    3.2 react 支持

    使用官方的 react 插件 @vitejs/plugin-react,支持:

    • 在开发中启用热更新 (需要 react >= 16.9)
    • 使用自动 JSX 运行时
    • 使用安装体积小的自定义 Babel 插件/预设
    // vite.config.js
    import react from '@vitejs/plugin-react'
    
    export default defineConfig({
      plugins: [react()],
    })
    

    3.3 路径别名

    import 文件时,我们常常会把 <root>/src 别名为 @,这样编写代码就比较方便

    // vite.config.js
    export default defineConfig({
      resolve: {
        alias: {
          '@': path.resolve(__dirname, './src'),
        },
      },
    })
    

    3.4 多环境

    多环境采用 vite 内置的方案。

    • 当使用 vite --mode localhost 启动项目时,环境的配置文件,对应的是根目录的 <root>/.env.localhost 文件。
    • .env.localhost 文件中定义的环境变量,可通过 const { VITE_API_HOST } = import.meta.env 在代码中引入。

    如何新增环境,并新增环境变量?

    1. 在根目录新建 .env.newEnv 文件
    2. .env.newEnv 文件中定义环境变量: VITE_SOME_KEY = someValue
    3. src/vite-env.d.ts 定义 VITE_SOME_KEY 的类型
    4. 在项目的 ts/tsx 文件中引入环境变量 const { VITE_SOME_KEY } = import.meta.env;

    3.4.1 指定环境构建

    添加构建命令:

    // package.json
    {
      "scripts": {
        "build:newEnv": "vite build --mode newEnv",
      }
    }
    

    执行构建:

    npm run build:newEnv
    

    4. 其他 Vite 不相关的工程化配置

    4.1 编码规范

    项目总体按最小约束原则约束编码规范,只使用了 eslint。你可以根据自己的需求自行添加各规范,如 stylelintprettier

    [!TIP] 我们认为在编码规范方面,应当在工程统一性灵活性之间找到一个平衡,而不是一味地使用各种 lint 类工具作强制约束。你可以找到自己团队的平衡点,定制适合自己团队的编码规范

    4.1.1 eslint 规则

    本项目采用官方建议的通用 eslint 规则,如下:

    • @typescript-eslint/recommendedeslint 官方赞助的社区 typescript 规则)
    • eslint:recommendedeslint 官方推荐规则)
    • eslint-plugin-react (社区流行的 react 规则)

    详见 <root>/.eslintrc.cjs

    eslint 可配合 huskylint-staged 实现 git commit 时自动校验 eslint,其他文档和教程很多,在此不再赘述

    5. 完整版预览

    5.1 深/浅色主题

    Light Dark

    5.2 任意主色切换

    5.3 任意背景色切换

    Background Light Background Dark

    5.4 4 种布局

    侧分栏 侧单栏
    头分栏 头单栏

    5.5 丰富的主题配置

    6. 系列文章

    • 腿夹腿,带你用 react 撸后台,系列一( Vite 篇)

    如果你喜欢这个项目或认为对你有用,欢迎使用体验和 Star

    Github 地址 | 文档地址 | 预览地址

    60 条回复    2024-10-25 17:49:35 +08:00
    russ44
        1
    russ44  
       1 天前 via Android
    cool
    cbythe434
        2
    cbythe434  
       1 天前
    腿夹腿撸和手把手撸体验上有差吗
    ZGame
        3
    ZGame  
       1 天前
    挺好看的 学习一下
    michaelluang
        4
    michaelluang  
       1 天前
    写得很棒,期待下一篇。
    zhangfg
        5
    zhangfg  
    OP
       1 天前   ❤️ 1
    @cbythe434 手摸手,已经有用 vue 撸的了。腿夹腿用 react 撸,是一种新的体验😊
    zhangfg
        6
    zhangfg  
    OP
       1 天前
    @russ44 谢谢
    zhangfg
        7
    zhangfg  
    OP
       1 天前
    @ZGame 感谢,欢迎体验使用
    zhangfg
        8
    zhangfg  
    OP
       1 天前
    @michaelluang 感谢,后面会继续编写
    ZGame
        9
    ZGame  
       1 天前
    @zhangfg #7 功能挺全 但是为啥感觉丑丑的 ,可以参考下 vben 那个
    zclzone
        10
    zclzone  
       1 天前
    写得很好,已 star ,顺便推荐一下 vue-naive-admin ,使用 vue3 + vite ,https://github.com/zclzone/vue-naive-admin
    zhangfg
        11
    zhangfg  
    OP
       1 天前
    @ZGame 基本上用的 antd 原来样式,没做很多修改,没有专业 UI 设计,组合起来确实不太好看
    starcoming
        12
    starcoming  
       1 天前
    支持一下
    zhangfg
        13
    zhangfg  
    OP
       1 天前
    @zclzone 感谢,这个项目 https://github.com/zclzone/vue-naive-admin ,看了也很棒,已 star
    zhangfg
        14
    zhangfg  
    OP
       1 天前
    @starcoming 感谢,欢迎体验使用
    ZGame
        15
    ZGame  
       1 天前
    @zhangfg #11 是,我感觉建议参考一下别的修改下样式, 还有希望可以支持一下 monorepo 那种模式。
    zhangfg
        16
    zhangfg  
    OP
       1 天前
    @ZGame 这块我再参考和学习一下,后续继续更新
    shintendo
        17
    shintendo  
       1 天前
    但实际情况中,作者从没有碰到过不一致的情况
    ------
    有一个挺常见的坑,开发和打包后的 CSS 顺序不一致,相关 issue 开了 4 年了至今未解决
    Ma4cus
        18
    Ma4cus  
       1 天前
    厉害了,有 vue 的吗
    ColdBird
        19
    ColdBird  
       1 天前
    还好不是手把腿
    zhangfg
        20
    zhangfg  
    OP
       1 天前
    @shintendo 是在什么特定 case 下产生的吗,我去瞅瞅
    zhangfg
        21
    zhangfg  
    OP
       1 天前
    @Ma4cus 有,评论区就有一个 vue 的
    zhangfg
        22
    zhangfg  
    OP
       1 天前
    @ColdBird 要用心
    HHAO2019
        23
    HHAO2019  
       1 天前
    好奇问一下, 多标签页怎么实现的 antd 好像默认不支持
    zclzone
        24
    zclzone  
       1 天前
    代码运行跟你预览地址的不一样,是有代码还没提交吗
    randomstream
        25
    randomstream  
       1 天前
    端口编号 9527
    344457769
        26
    344457769  
       1 天前


    使用 Firefox 会有很大概率出现页面空白,闪一下页面内容然后就消失了。
    zhangfg
        27
    zhangfg  
    OP
       1 天前   ❤️ 1
    @HHAO2019 antd 有 Tabs 组件。传 items 就会展示多标签,传 activeKey 会高亮指定的 tab 。所以只需要管理好 items 数据即可。items 相关数据存到 localstorage,刷新页面就还会继续展示。另外封装好拖拽和右键逻辑以复用,我们就可以只写样式,便可产出多个不同样式的标签页。
    zhangfg
        28
    zhangfg  
    OP
       1 天前
    @zclzone 是的。目前是一个相对比较干净的模板,只包含必要的功能,在这个基础上做二开,是比较方便的。功能越多,二开就越麻烦,尤其是主题那块。后续我再写写后面的系列文章,根据大家使用的情况补功能进来(如果大家还感兴趣的话)
    zhangfg
        29
    zhangfg  
    OP
       1 天前
    @randomstream 都没用 8964
    randomstream
        30
    randomstream  
       1 天前
    @zhangfg #29 好家伙,搜了才知道,🐮
    1622346252
        31
    1622346252  
       1 天前
    先 start 后看
    bao3
        32
    bao3  
       1 天前
    广大女性心头一紧。
    yaroga
        33
    yaroga  
       1 天前
    学习下,不用 monorepo 么
    zhangfg
        34
    zhangfg  
    OP
       1 天前
    @1622346252 老哥,谢谢你,你是好人
    zhangfg
        35
    zhangfg  
    OP
       1 天前
    @bao3 其实男性也可以的
    zhangfg
        36
    zhangfg  
    OP
       1 天前
    @yaroga 没有呢,目前没有什么地方有需要用到
    Vitumoc
        37
    Vitumoc  
       1 天前
    还是你们前端圈子奔放,上一个还是手摸手呢=。=
    到这就腿夹腿了
    以后的我都不敢想
    Vitumoc
        38
    Vitumoc  
       1 天前
    看了一下,爽,打算把我之前 vue2 + element 的老后台改过来了
    zhangfg
        39
    zhangfg  
    OP
       1 天前
    @Vitumoc 只要东西里面过硬,什么姿势都无所谓
    zhangfg
        40
    zhangfg  
    OP
       1 天前
    @Vitumoc react 感觉后端用起来更顺手,写法更贴近语言本身
    godymho
        41
    godymho  
       21 小时 37 分钟前
    你这个动态多标签是基于什么的呀
    SimonWoo
        42
    SimonWoo  
       10 小时 40 分钟前
    @zhangfg 兄弟你这端口...我怀疑你意识形态有问题啊
    zclzone
        43
    zclzone  
       10 小时 18 分钟前
    @zhangfg 预览版本的很多功能都没有,如果是想保持干净的模板可以提供多个版本的,让用户去选择使用哪个,很多这类开源项目都是这样做的。预览是完整版,开源的是阉割版,多少有点挂羊头卖狗肉的嫌疑,当然,你可能有别的想法或者顾虑,开源的东西不能要求太多,我仅仅只是建议
    yurenfeijing
        44
    yurenfeijing  
       9 小时 59 分钟前
    挺好的,已经 star 了,另外 github 代码是不是最新的啊,怎么找不到主题和 debugger.html 那块的代码?
    zhangfg
        45
    zhangfg  
    OP
       9 小时 7 分钟前
    @zclzone 谢谢你的建议。所谓的阉割版是一个干净的模板,它是通用的。所谓的完整版,是在模板的基础上丰富的,它还未完全准备好,还没准备完全开源。如果哪些功能有必要并且是通用的,会根据大家使用的情况按需加到模板里。所谓的“完整版”,是我个人的完整版,不是所有人的完整版。我会把这个情况在 github 里说明下,或许会再开一个链接,两个预览链接都放着。(无论如何,我不太喜欢阉割版这个说法,我们可以多讨论技术问题本身)
    zhangfg
        46
    zhangfg  
    OP
       9 小时 6 分钟前
    @yurenfeijing 那您可千万别 star 啊
    zhangfg
        47
    zhangfg  
    OP
       9 小时 4 分钟前
    @SimonWoo 那只是一个端口...
    zclzone
        48
    zclzone  
       8 小时 55 分钟前
    @zhangfg 期待你的完全开源
    zhangfg
        49
    zhangfg  
    OP
       8 小时 53 分钟前
    @godymho 上面有回复类似问题:antd 有 Tabs 组件。传 items 就会展示多标签,传 activeKey 会高亮指定的 tab 。所以只需要管理好 items 数据即可。items 相关数据存到 localstorage,刷新页面就还会继续展示。另外封装好拖拽和右键逻辑以复用,我们就可以只写样式,便可产出多个不同样式的标签页。
    再补充一些,如何管理 items 数据:当点击标签,需要跳转路由;当路由切换,需要新增 item ;当点击关闭标签,需要删除当前 item 并需要跳转到下一个 item ;右键菜单还有一些关闭其他,关闭右侧,关闭左侧的逻辑,和上述关闭逻辑是类似的。把这些逻辑封装封装。
    zhangfg
        50
    zhangfg  
    OP
       8 小时 44 分钟前
    @zclzone 感谢你给这个小项目的一些生存空间
    yurenfeijing
        51
    yurenfeijing  
       8 小时 19 分钟前
    @zhangfg 这有啥,那就取消呗😅谁能想到放的截图是完整的,代码是阉割的,也只有一个分支,我有疑问不是很正常吗?
    zhangfg
        52
    zhangfg  
    OP
       8 小时 17 分钟前
    @yurenfeijing 好嘞
    zhangfg
        53
    zhangfg  
    OP
       7 小时 35 分钟前
    更新:
    [在线预览]( https://template.react-antd-console.site) | [个人 pro 版在线预览]( https://react-antd-console.site) | [文档]( https://doc.react-antd-console.site)
    jones2000
        54
    jones2000  
       7 小时 32 分钟前
    Vite 很不好用, 每次改 node_modules 里面插件得源码, 都不会自动编译, 还要删 vite 得缓存, 然后在重新编译, 麻烦得要死。
    zhangfg
        55
    zhangfg  
    OP
       7 小时 25 分钟前 via Android
    @jones2000 一般不会改 node_modules 里的源码吧...或许应该提 issue 或 fork 或 monorepo 或私仓
    zhangfg
        56
    zhangfg  
    OP
       7 小时 22 分钟前 via Android
    @jones2000 而且 node_modules 里一般多是打包后的代码
    jones2000
        57
    jones2000  
       7 小时 20 分钟前
    @zhangfg 发”issue“要等到什么时候。 公司都是内网,不能访问外网。 一次性把包下完,移到内网。不满足需求得, 直接手动 node_modules 里面改。
    zhangfg
        58
    zhangfg  
    OP
       7 小时 19 分钟前 via Android
    @jones2000 感觉这是包的问题,不是 vite 需要覆盖解决的问题呢
    hutoer
        59
    hutoer  
       2 小时 13 分钟前
    OP ,开源版,内容会不少了些?你看看 https://www.v2ex.com/t/1039863 这位和你用的技术栈很像
    zhangfg
        60
    zhangfg  
    OP
       1 小时 47 分钟前
    @hutoer 我看看,我再加点东西进来
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2670 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 11:36 · PVG 19:36 · LAX 04:36 · JFK 07:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.