从混乱旧项目到模块化可维护

576 阅读5分钟

前言

最近需要维护公司的 一个加密的 js 项目。 项目全部由 js 来构建,大概就是由几个 js 文件 最终使用 gulp 将所有的 js 文件成 合并成一个生成环境的 js 文件。 但是由于没有模块化,现在有几个很明显的问题 :

  1. 方法,变量来路不明。 (开发维护难)
  2. 污染 window 全局。 (容易与客户系统冲突,因为你没法决定客户的开发规范)
  3. 可能存在变量,方法并未使用或者重复,增加了生产环境代码体积

因为, 我们需要在客户的系统的基础之上进行数据的拦截加密, 而客户的系统极其的不稳定。 有新开发的,也有很旧的很老的例如: jsp + 纯静态的 html + css + js 项目。 很容易导致我们 和客户系统进行整合时候 出现很多的线上问题。而我们项目最初是没有进行规范的 模块化 的,这就使得我完完全全要求一行一行的看代码,而且也无法试用编辑器的智能性,帮我找到 这个方法的来自于哪里,需要传入什么,他会返回一个什么结果。这就很让人头疼。下面我总结,记录了一下我的处理流程:

1. 整理项目结构

首先这也是最基础的 ,依据项目所要实现的功能,进行了对应的文件拆分,这就像 一个规范的 Vue , React 项目。比如 下面是一个 vue 项目的大概文件夹关系:

src
|--- assets  // 静态资源文件夹
|--- components  // 组件文件夹
        |--- layout
                |---layout.vue
        |--- modal
        ...
|--- pages  // 页面文件夹
        |--- home
               |---index.vue
        |--- login
        ...
|--- utils  // 工具类文件夹
|--- api  // 接口统一管理文件夹
      |--- global.js
      |--- login.js
      ...
|--- main.js
|--- App.vue
|--- router.js

这样子,我们很快就能知道大概的 文件做的事什么事,pages 里面存放的是一个个的页面,他对应的是 router.js 文件当中的路由一一对应。我们就能很快的寻找到对应的文件,来修改对应的代码。

2. 拆分代码

由于混乱在全局,所有很多代码来源不明, 比如,a.js 文件中的一个方法, 他在该文件中并不能找到, 他可能是挂载在 window 全局上被 a 文件所引用着。这样循环嵌套,代码结构很不清晰。 所有 并不能很正确的判断这个方法或者变量有没有被使用,是不是无用代码。

于是,试着倒推一次。从最终的结果出发, 现在这样子认为,我最终打包出来的 js , 如果这里面没有使用到,那么就一定是 无用的代码 ,我们跨越删掉他们。当然, 这样子也只能去掉一部分。 如果有一些代码 他也是无用的, 但是他被引用着,最终也会去到我们 build 出来的包中。这就需要我们进行细看代码逻辑 进行判断是否需要了。

最终我想呈现出来的代码结构大致是这样的 :

// 导入需要的方法
import useHandleRequest from './request/index.js'
improt { enData, deData } from './XXX/XXX.js'
...


// 使用
const handleRequest = useHandleRequest()

handleRequest.onBefore = (req) => {
    // 拦截请求加密数据
    // 做一些事情
}

handleRequest.onAfter = (req) => {
    // 拦截响应解密数据
    // 做一些事情
    
}

首先, 来源清晰了,哪里出现了问题 ,我们可以第一时间找到问题所在。对客户系统进行对应的适配

其次,可能我们需要对新的需求进行叠加,我们就可以很方便的基于原先的代码进行扩展。

这样子, 就把一个 1w,和 5k 行的 js文件拆成了很多单一的 js 文件。每个文件只实现一个功能, 大大提高了代码的可读性。

3. 搭配 webpack

原先的项目代码中,并没有使用任何第三方的 npm 包, 我觉得这是一种损失。 我个人决定,应当进行适量的项目调研, 当有一个能够满足你需求,且在其他方面,例如(项目代码体积)你也可以接受的情况下, 还是应当去使用 npm 上优秀的库的。他们经过了很多攻城狮的努力迭代,可能远比你写的要来的简洁明了。 而且大大降低了你的项目开发周期。

使用 webpack + uglifyjs-webpack-plugin 进行区分环境打包配置 webpack.config.js

const path = require("path");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");

module.exports = (env, argv) => {
  // 基本配置配置
  const config = {
    entry"./src/main.js",
    output: {
      filename"enc.js",
      path: path.resolve(__dirname, "dist"),
    },
  };
  
  if (argv.mode === "development") {
  } else {
    // 生产环境 使用uglifyjs 进行代码压缩
    config.plugins = [
      new UglifyJsPlugin({
        uglifyOptions: {
          warningsfalse,
          parse: {},
          compress: {
            drop_consoletrue, // 去除console
          },
          mangletrue// Note `mangle.properties` is `false` by default.
          outputfalse,
          toplevelfalse,
          nameCachenull,
          ie8true,
          keep_fnamesfalse,
          paralleltrue,
        },
      }),
    ];
  }
  return config;
};

4. 扩展

dev 环境 我们想代码修改就打包新的 js , 不需要我们再去手动去 build 打包文件。 增加 webpack-dev-server , 开启本地服务,运行开发环境。

修改 package.json , 分开两个环境 一个 devnpm run dev 命令运行 ,另一个生产环境, npm run build 运行

"scripts": {

    "dev": "webpack-dev-server",

    "build": "webpack --mode=production"

  },

修改 webpack.config.js : dev 开启本地服务,方便测试代码效果。 build 环境我们只要经过压缩后的 release js 文件即可

const path = require("path");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");

module.exports = (env, argv) => {
  // 基本配置配置
  let baseConfig = {
    mode"development",
    entry"./src/main.js",  //入口文件
  };
  
  if (argv.mode === "development") {
    // 开发环境
    config = {
      ...baseConfig,
      watchtrue,   // 监听文件变化 自动打包
      devServer: {},   // 开启本地服务
    };
  } else {
    // 生产环境
    config = {
      ...baseConfig,
      output: {
        filename"enc.js",
        path: path.resolve(__dirname, "dist"),
      },
      plugins: [
        new UglifyJsPlugin({
          uglifyOptions: {
            warningsfalse,
            parse: {},
            compress: {
              drop_consoletrue,
            },
            mangletrue// Note `mangle.properties` is `false` by default.
            output: {
              commentsfalse,
            },
            toplevelfalse,
            nameCachenull,
            ie8true,
            keep_fnamesfalse,
            paralleltrue,
          },
        }),
      ],
    };
  }
  return config;
};

webpack 相关的配置都是阅读文档,以及查阅资料(baidu)。 不对之处请指出。