用React重写Tomcat中的前端项目
前言
最近接到一个活, 问我能不能调整这么个页面的导航栏, 项目是跑在Tomcat中的.
因客户原因, 项目展示图不给放了, 请自行脑补一个带侧边栏的后台管理系统.
我都不知道啥是Tomcat, 花十分钟官网下了个demo, 起了个服务, 看了看依然还都是基础的html + css, 就应了下来.
一期很快很顺利, 就是写jQuery操作操作dom, 加一些样式复写. 一顿操作猛如虎, 还交了文档表示如何最小程度影响老的代码, 客户很满意. 问我能不能重写前端. 因为现在交出去的html文件很原始, 他一个外行都能靠devtool找到html与css文件操作一番, 这是一个部在局域网的项目, 希望交出去能有一些保密性.
呵, 小小项目, 我还能做不了?
困难
当然, 靠谱如我当然没有直接应下来, 因为没有后端文档, 后端也动不了, 只有Java编译后的class文件.
Tomcat配置我也几乎不懂, 所以, 我先调研评估了一下. 主要两个问题能解决就行:
- 生产环境部署
- 登录验证
也是本博客主要想写的东西.
打包部署
我们现代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-app和Vue-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, 挺有意思.

UI重写调研
项目干了两期.
第一期因为工期太紧, 十几个接口, 没文档只靠看老代码, 4天干完. 所以完全保持原样式库, 主要是基于Bootstrap5的tabler.css.
第二期, 客户想要换套UI, 没有设计让我看着整. 那我这不得趁着这个付费实操的机会好好熟悉一下Tailwind?
我调研搜索了一下, 给挑了Tailwind系的比较高star的几个UI库.
不知道为啥感觉很像中国同胞设计的daisyui
这个是比较纯的html样式库, 自己写React组件的话, 可定制强度会大一些.

最后当然还有tailwind官网自己的那套, 我是没咋看上.
后来我选了NextUI.
叨叨两句Tailwind和Bootstrap
我之前一直是用styled-component手搓css, 这次小项目恰好让我有机会对这两个作为样式封装UI库的顶流, 直接横向比较一番.
Bootstrap存在很多年了, 扎实好用, 但是没有像Tailwind突然爆火, 我觉得Tailwind的火一大部分是靠其系列的ui库带起来.
而Bootstrap的衍生UI库没那么多, 主要还是他的那套!important原则, 让各种样式类很难叠加再次创造新的样式库.
原来在公司code review, 都建议同事非必要不要写!important, 不要写内联, 因为后期再改动或更新, 确实很头疼.
最后项目
因客户原因, 最后展示图不给放了, 请自行脑补一个带light/dark切换的, 很酷炫的新页面.

