2024年7月3日
By: Chase

用React重写Tomcat中的前端项目

前言

最近接到一个活, 问我能不能调整这么个页面的导航栏, 项目是跑在Tomcat中的.

因客户原因, 项目展示图不给放了, 请自行脑补一个带侧边栏的后台管理系统.

我都不知道啥是Tomcat, 花十分钟官网下了个demo, 起了个服务, 看了看依然还都是基础的html + css, 就应了下来.

一期很快很顺利, 就是写jQuery操作操作dom, 加一些样式复写. 一顿操作猛如虎, 还交了文档表示如何最小程度影响老的代码, 客户很满意. 问我能不能重写前端. 因为现在交出去的html文件很原始, 他一个外行都能靠devtool找到html与css文件操作一番, 这是一个部在局域网的项目, 希望交出去能有一些保密性.

呵, 小小项目, 我还能做不了?

困难

当然, 靠谱如我当然没有直接应下来, 因为没有后端文档, 后端也动不了, 只有Java编译后的class文件. Tomcat配置我也几乎不懂, 所以, 我先调研评估了一下. 主要两个问题能解决就行:

  1. 生产环境部署
  2. 登录验证

也是本博客主要想写的东西.

打包部署

我们现代React, Vue等常见的SPA部署方案, 无论是Nginx, 还是用Vercel, 都是需要启动专属前端的服务解决前端路由的问题.

而在我们的项目中, 因为Tomcat本身已经是个服务了, 他服务直接就启在部署后的80端口上, 在之前的项目里, html资源的加载与路由全部都由java服务操控.

Tomcat能不能启两个端口的服务再说, 这个项目的接口访问是不允许跨域的. java动不了, 所以我的决定方案是 用NextJS静态导出.

解决跨域

单纯的解决跨域手段有挺多, 最简单的是next.config.mjs中的rewrite(), 但是我主要面临的难点是set-cookie, 需要同源才能使得登录session生效.

所以本地另启nginx, 或express等做代理转发并无效, 因为代理转发的服务端口和我开发环境的3000端口必然又是跨域.

解决setCookie

不能再起一个端口转发, 那我直接3000端口自己转呗.

这一点NextJS不如Create-react-appVue-cli, 这两个都自带了proxy配置, config设置下就可以自身端口转发了.

这个需要自己写个proxy.js, 启动的话用node proxy.js, 等于在原始的next dev外面包了一层拦截转发, 代码如下:

const express = require('express')
const { createProxyMiddleware } = require('http-proxy-middleware')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
  const server = express()

  server.use((req, res, nextStep) => {
    res.setHeader('Access-Control-Allow-Origin', '*')
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
    if (req.method === 'OPTIONS') {
      res.sendStatus(200)
    } else {
      nextStep()
    }
  })

  // set proxy middleware
  const apiProxy = createProxyMiddleware({
    target: 'http://localhost:8080', // replace to your own backend api address
    changeOrigin: true,
    pathRewrite: {
      '^/api': '' // the proxy path replacement
    }
  })

  // all the request starts with '/stream/api' will proxy to your target backend server
  server.use('/api', apiProxy)

  // return all the rest request to Next.js
  server.all('*', (req, res) => handle(req, res))

  // server port
  const PORT = process.env.PORT || 3000
  server.listen(PORT, (err) => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${PORT}`)
  })
})

解决Cookie中带path

他不光用set-cookie, cookie还带/path参数. 也就是说我得给他整个匹配的相应的path才能搞定.

这个方案NextJS里倒是现成的, 开发环境在next.config.mjs里配置basePath即可.

生产环境的话, 既然导出就是静态文件, 加个path的文件夹包裹, 前缀自然就有二级路由了.

老项目亮点

在老的堆html的项目中, 无法有全局组件的概念. navbar, footer这种组件每次页面需要跳转后需要重载.

改写的这个项目对a链接跳转拦截, 利用iframe作为容器加载新的html, 挺有意思.

图-0

UI重写调研

项目干了两期.

第一期因为工期太紧, 十几个接口, 没文档只靠看老代码, 4天干完. 所以完全保持原样式库, 主要是基于Bootstrap5tabler.css.

第二期, 客户想要换套UI, 没有设计让我看着整. 那我这不得趁着这个付费实操的机会好好熟悉一下Tailwind?

我调研搜索了一下, 给挑了Tailwind系的比较高star的几个UI库.

程序员性冷淡风之shadcn图-0

叫Next但不是Vercel亲儿子的NextUI图-2

不知道为啥感觉很像中国同胞设计的daisyui 这个是比较纯的html样式库, 自己写React组件的话, 可定制强度会大一些. 图-1

最后当然还有tailwind官网自己的那套, 我是没咋看上.

后来我选了NextUI.

叨叨两句Tailwind和Bootstrap

我之前一直是用styled-component手搓css, 这次小项目恰好让我有机会对这两个作为样式封装UI库的顶流, 直接横向比较一番.

Bootstrap存在很多年了, 扎实好用, 但是没有像Tailwind突然爆火, 我觉得Tailwind的火一大部分是靠其系列的ui库带起来.

而Bootstrap的衍生UI库没那么多, 主要还是他的那套!important原则, 让各种样式类很难叠加再次创造新的样式库.

原来在公司code review, 都建议同事非必要不要写!important, 不要写内联, 因为后期再改动或更新, 确实很头疼.

最后项目

因客户原因, 最后展示图不给放了, 请自行脑补一个带light/dark切换的, 很酷炫的新页面.

Tags: NextUI tomcat 代理 react 跨域