如何升级一个旧项目

起因

在公司中接手导师很早以前开发的一个系统,需要在其基础上进行权限审核以及新需求的开发。 因为导师代码写的很漂亮,啃了一段时间源码加对源码做系统注释,对于新需求的迭代还是很顺利的进行下去并学到了很多东西。 因为一些不可描述的原因,接到一个任务就是完成近期的需求后考虑对系统做一次升级。 年轻的我,认为,一切都没有问题。于是完成需求测试通过后,开始规划升级计划。 (后来的我,脑子盘旋的是为什么那么多问题QAQ)

旧项目配置

首先我们来看一下旧项目的配置,大概了解一下:


"react": "15.4.0",
"react-dom": "15.4.0",
"react-redux": "4.4.5",
"react-router": "2.6.1",
"redis": "^2.6.5",
"redux": "3.5.2",
"redux-router": "2.1.2",
"redux-thunk": "2.0.1",
"reselect": "^2.5.4",
"koa": "1.1.2",
"webpack": "^1.14.0",

这是一个前后端都一人完成的项目,所以采用的是当时比较稳定的版本。当然很多没接触过该版本的人还不是很了解这个这个旧系统旧在哪。


1.webpack的配置写法1.x 在后期版本是大改的,因此基本上旧版本的webpack算废了。

2.router 需要对细节做处理。

3.最主要是 react 的版本,以及那个时候还没有能够自动化处理一些模块的情况下,样式用的是`stylename`。旧项目中为了实现函数继承复用,在jsx里面写函数需要手工绑定缓存this指向。

4.对antd旧版本进行了封装处理。

当然一个旧系统的升级难点肯定不会只在这些基础依赖上。 项目大量封装了很多组件,以及抽象了很多模块。 比如对 antd 2.7 做了一些业务方向的抽象处理。

在升级一个项目之前需要想清楚几件事

思考升级项目,肯定是有它的目的,我们可能一开始没法考虑的很细,但是我们升完级后回过来再好好对比一番,到了以后就会更加有经验。 其实这个旧项目之所以考虑升级,有一部分是为了升级而升级。但是升完级后,在后续的需求开发,代码调试上都更加得心应手。原因是这么几点:

  1. 升级后的开发环境更加顺手。
  2. 升级后对之前冗余代码的处理使项目变得更加简洁。
  3. 升级之后才对旧项目有更深的理解,明白当初这些模块为什么这么设计,在新配置下需要做怎样的调整才能正常运行。
  4. 升级的整个过程中,会碰到各种各样奇奇怪怪的玄学问题,很多都是因为依赖版本的不匹配,这时候需要读文档,google, stackoverflow,读源码,甚至反复对比旧项目,这需要很多耐心。但是一个坑你不会踩第二次,前期慢后期会熟练一些。

升级后整个项目大小从6m可以缩减到2m。

升级一个旧项目需要几步

1.熟悉你的旧项目。

这点其实最重要,在我真正准备升级之前,我其实已经接手一段时间,并且在其基础上已经开发了几个功能。流程要熟悉之外,还需要对原有的代码风格尽量保持一致。如果自己整改不要改太多。

2.改造你的开发环境

很早之前我就倡议开发配置先行。每一个开发工作都需要做对应的环境配置。而旧项目的配置升级其实也挺复杂,需要面临的情况有点多。而我遇到的情况有点复杂,需要整个换掉。因为它是webpack1.0 :)

下面是部分思考的摘记


对依赖进行升级:
主要需要解决 webpack1.x -> webpack3 / webpack4

经过测试 发现这样升级问题太大了。准备直接借壳重构

升级几个方向:
1.通过create-react-app 生成新的最新版的环境,然后替换进去。

结果:修改了一堆最后白屏


2.通过找一个稳定的react全家桶开发环境(如webpack3.0 + ...),然后替换。
发现直接迁移 代码改动量很大。尤其是以前的一些写法。。
思考该如何解决这些问题。。。
实验失败
测试了两种方式,一种是通过缓慢更新webpack的版本,通过修改配置来完成,而且在此之前通过旧版本webpack打包是成功的。但是配置和依赖改成webpack3.0之后,打包成功。但是页面一片白。。。另一种方式是通过已有的项目,替换文件。然后一片白。

思考该如何升级
只 升级 webpack的 举动经过测试是不可行的,大概就是要项目的依赖都进行升级了。。。


发现因为 旧项目router的写法已经不适合新版本。升级依赖已经无法实现兼容共存。


3.通过创建新的开发环境,代码一点点重构迁移。
这个迁移手段也不存在重构。
就是创建新项目,重新配置路由等等。然后将旧项目的部分内容改一改扔进来。。。相当于开一个新项目~

因此新环境 需要用新的依赖的写法,需要支持
react - redux - router - antd - less

由于 github 开源项目中上未有最新的 环境配置
自己手动配置

现在复盘一下: 最终是通过构建一个最新的全家桶配置环境,然后一部分一部分将路由,将页面迁移过来。然后再加入功能模块,期间还需要改大量废弃的代码片段,这里推荐 vscode编辑器 ,改这类代码很方便。 但是这个方法在我后来看是比较慢的,但是它很稳妥。其中经历的一些问题不仅包括 antd 依赖包的引入,旧项目的 router升级后不兼容,项目爆出冷门问题

  
  Uncaught Error: Actions may not have an undefined "type" property. Have you misspelled a constant?
  

这是一部分记录


一开始以为是版本升级后的 不能这么写
然后又google到另一种情况是async的问题
这个时候思路被带歪了
研究很久回过来重新看 thunk的配置 以为是自己引用问题
但是之前为了排错已经写了一个简单的reducer 的应用。
说明该配置下正常都能运行。
然后我觉得可能是
[CALL_API]: {
types: [
getAction(actionPrefix, name, defines.ACTION_STATUS_LOAD),
getAction(actionPrefix, name, defines.ACTION_STATUS_SUCCESS),
getAction(actionPrefix, name, defines.ACTION_STATUS_FAIL)
], 

猜测不能以types写
但是我搜了一下github,16年到17年不同版本都能这么写。
这属于常规操作。
最后我觉得可能旧项目有东西在变动。导致问题。
新旧项目同时跑起来然后一行行代码仔细对比。
发现因为把 异步ajax封装出去后。旧项目会在 Middleware中重新引入。而新项目因为配置全新,并没注意到这个点。

3.向上兼容你的旧项目

我们知道每次升级肯定会造成大量改动,但是必须考虑你是在升级,因此一些新的写法如果和旧项目有冲突,那么以旧项目为准。 我们尽量修改旧项目以及不合适的部分,以及为了更加简洁做一部分的修改。 但是千万不要打算将核心模块给动了,如果要动,至少用装饰者模式来做。

4.双开新旧项目验收

升级的目的是为了更快更好,那么在没有做新需求的情况下,它的原有功能模块,界面交互都需要保存一致。因此需要双开一个个功能做对比验收。这里还会遇到很多细节的问题。

这里是部分记载:


现阶段 前后端分离
前端用 proxy 来调用Node端接口
后期需要做处理。与旧项目保持一致。

前端路由写法和之前预判的改动一点点不一样,它改动很大。
旧项目是需要把之前的配置思想转为 page-路由,现在子路由需要写在父组件里面。
Router不能够嵌套使用。
子组件之前参数传递需要去match里面找
Link 必须引自 react-router-dom,因为旧版的不兼容。

开启两个项目 调试验证发现部分css样式不同
发现是css module 问题,根据旧项目界面表现一一对比然后修改。

结尾

项目升级中会遇到很多玄学问题,这里我采用的是小黄鸭改Bug法:) 。遇到问题抱着一种肯定能解决的心态,二分法定位,断点调试,以及关键模块替换验证等等都进行尝试。这都成了之后工作的经(套)验(路)。这里比较有心得的是借位替换,我在测试一个旧项目能否在新项目跑的通的模块,比如redux,它是否生效了,我会写一个适应新项目的test模块,先测试一下,跑的通,说明整个流程是可行的,那么我再把旧项目的代码转移过来,跑不通,说明是旧项目里肯定有部分问题,这样的好处是心理有个底,不会对整个环境或者依赖产生质疑。

Table of Contents