前言

本文主要对 IUAP 应用平台开发中构建前端工程中的实践做简单说明,基于 ucf-web 微服务框架构建前端工程,会描述一般场景的前端项目结构脚手架搭建配置依赖包的管理方式、和公共组件的维护办法

用友云平台战略项目交付团队

第一章 构建前端工程

1.1 脚手架

现行的项目脚手架我们推荐使用 ucf-web 微前端框架,详细内容请查看使用手册 之 快速上手 目录下内容。

通常情况下 ucf-cli 会自动生成配置文件,详细的 API 在次不做累赘,不过我们需要更具实际情况做一些调整,同时有一些比较实用的插件。

  • babel-plugin-import-bee:如果使用了 tinper-bee 组件库,我们可以启用定制的按需加载插件,默认的配置中没有启用,启用后主要体现在构建结束后的资源文件会变小。
  • babel-plugin-react-intl:这个插件主要用于 react-intl 国际化方案的处理,在实际开发中不用人工抽取字符ID,启用后会生成对应的 json 文件,方便提供给翻译人员参考。
  • 启用res_extra:启用资源优化会在构建后产出抽取的公共资源文件,以及优化一些静态资源文件,具体参考 ucf-script配置 之 res_extra 说明
  • bootList:这个配置主要控制微服务启动加载的模块,和打包是打包的模块,通常我们操作那个模块加入那个模块。

ucf.config.js 配置:

  1. require('@babel/polyfill');
  2. const path = require('path');
  3. module.exports = (env, argv) => {
  4. return {
  5. // 启动所有模块,默认这个配置, 速度慢的时候使用另外的配置
  6. context:"my-demo",
  7. // bootList: true,
  8. // 启动这两个模块,启动调试、构建
  9. bootList: [
  10. 'app'
  11. ],
  12. // 代理的配置
  13. proxy: [
  14. {
  15. "enable": true,
  16. "headers": {
  17. "Referer": "http://127.0.0.1:8000"
  18. },
  19. "router": ["/api"],
  20. "url": "http://127.0.0.1:8000"
  21. },
  22. ],
  23. // 启用用sourceMap
  24. open_source_map: true,
  25. res_extra: true,
  26. // CSS loader 控制选项
  27. css: {
  28. modules: false
  29. },
  30. // 全局环境变量
  31. global_env: {
  32. GLOBAL_HTTP_BASE: JSON.stringify("/api"),
  33. },
  34. // 静态资源路径
  35. // static: 'ucf-common/src/static', // 别名配置
  36. //'ucf-apps': path.resolve(__dirname, 'ucf-apps/')
  37. alias: {
  38. components: path.resolve(__dirname, "ucf-common/src/components"),
  39. utils: path.resolve(__dirname, "ucf-common/src/utils"),
  40. static: path.resolve(__dirname, "ucf-common/src/static"),
  41. styles: path.resolve(__dirname, "ucf-common/src/styles"),
  42. "ucf-common": path.resolve(__dirname, "ucf-common/")
  43. },
  44. babel_plugins: [
  45. [require.resolve("babel-plugin-import-bee"),
  46. {
  47. "libraryName": "tinper-bee"
  48. }],
  49. //这里属于多语配置只会在处理多语的时候启用
  50. // [require.resolve("babel-plugin-react-intl"), {
  51. // "messagesDir": "./intl/"
  52. // }]
  53. ],
  54. // 构建排除指定包
  55. externals: {},
  56. // 加载器Loader
  57. loader: [],
  58. // 调试服务需要运行的插件
  59. devPlugins: [],
  60. // 构建服务需要运行的插件
  61. buildPlugins: []
  62. }
  63. }

1.2 依赖包(package.json)

实行统一管理原则,即:

  1. 禁止私自添加依赖工具,由技术管理员统一提供依赖包,和依赖版本。
  2. 固化业务依赖包,例如 UI 组件库必须固化到某一个版本,禁止私自升级版本。具体实现办法是去除package.json版本号前面的符号。

    同时为防止规则僵化带来的开发进度受阻,实行谁使用谁验证的原则,即在没有通过审核或验证的情况下,实际的开发人员可以自己验证需要依赖的工具包,若符合业务即可通过管理员提交至 git 仓库。

package.json 配置:

  1. {
  2. "name": "my-demo",
  3. "version": "1.0.0",
  4. "description": "工程实例",
  5. "main": "",
  6. "scripts": {
  7. "dev": "npm start",
  8. "start": "ucf-scripts start --homepage=index.html",
  9. "build": "ucf-scripts build"
  10. },
  11. "devDependencies": {
  12. "babel-plugin-import-bee": "^2.1.0",
  13. "babel-plugin-react-intl": "^3.0.1",
  14. "ucf-scripts": "1.1.6"
  15. },
  16. "dependencies": {
  17. "@babel/polyfill": "7.2.5",
  18. "@babel/runtime": "7.3.1",
  19. "ac-attachment": "0.2.9",
  20. "async-validator": "1.10.0",
  21. "axios": "^0.18.0",
  22. "bee-affix": "1.0.15",
  23. "bee-anchor": "0.0.4",
  24. "bee-cascader": "2.0.3",
  25. "bee-complex-grid": "2.0.7",
  26. "bee-datepicker": "2.0.28",
  27. "classnames": "2.2.6",
  28. "core-js": "^2.6.1",
  29. "mirrorx": "^0.2.12",
  30. "moment": "^2.23.0",
  31. "prop-types": "15.7.2",
  32. "query-string": "5.1.1",
  33. "react": "16.8.2",
  34. "react-dom": "16.8.2",
  35. "react-intl": "^2.8.0",
  36. "ref-multiple-table": "1.1.4-beta",
  37. "ref-multiple-table-ui": "1.0.4",
  38. "ref-tree": "1.1.3-beta",
  39. "ref-tree-table": "1.1.3-beta",
  40. "shallowequal": "1.1.0",
  41. "tinper-bee": "2.0.7",
  42. "yyuap-bpm": "0.3.26",
  43. "yyuap-ref": "1.1.55"
  44. }
  45. }

第二章 项目结构

通用工程结构:

  1. ├── docs # 开发业务说明文档目录
  2. └── README.md
  3. ├── ucf-apps # 【目录名不可修改】微服务应用根目录,用于加载微服务
  4. ├── demo-app-org # 组织管理示例
  5. └── demo-app-staff #
  6. ├── src
  7. └── README.md # 模块说明
  8. ├── ucf-common # 【目录名不可修改】公共组件、样式、图片、字体等静态资源存放
  9. ├── src
  10. └── Button
  11. ├── index.js #
  12. ├── index.less #
  13. └── README.md # 通用组件使用说明,必须包含使用API
  14. └── README.md # 描述公共组件库的简单说明,其中包含发布版本,以及包含的组件列表
  15. ├── ucf-publish # 【目录名不可修改】构建出来的静态资源
  16. ├── demo-app-org # 组织管理示例
  17. └── demo-app-staff
  18. ├── ucf.config.js # ucf 核心配置文件
  19. ├── package.json # npm packages 依赖包
  20. └── README.md # 工程说明,必须包含快速上手说明

第三章 公共组件(common)

组件目录结构:

  1. 目录结构
  2. ├── ucf-common # 公共组件、公共方法目录
  3. ├── components # 公共组件
  4. ├── Button # 示例组件:Button
  5. ├── index.js # 默认出口文件
  6. ├── index.less # 默认样式文件
  7. └── README.md # 组件使用文档
  8. └── README.md # common 说明文档
  • ucf-common/components/Button/index.js 文件
  1. /* 订单表格的查询面板[文件功能描述]
  2. * @Author: [作者名](联系方式)
  3. * @Date: [创建时间]
  4. * @Last Modified by: [作者名]
  5. * @Last Modified time: [最后修改时间]
  6. */
  7. import React, { Component } from 'react';
  8. import PropTypes from 'prop-types';
  9. import './index.less';
  10. import classnames from 'classnames';
  11. //业务组件不强制要求使用状态声明
  12. const propTypes = {
  13. back: PropTypes.bool,
  14. title: PropTypes.string.isRequired
  15. };
  16. const defaultProps = {
  17. back: false,
  18. title: ''
  19. };
  20. // 若存在状态判断的样式修改,强制要求使用 classnames 包做处理
  21. const headerStyle = classnames({
  22. 'title': true,
  23. 'title-develop': true
  24. });
  25. // 命名规范可参考规则:[业务名] | [逻辑功能名] | [视觉效果名]
  26. // [业务名]:OrderGridSreachPanel
  27. // [逻辑功能名]:SreachPanel
  28. // [视觉效果名]:ExpandFormPanel
  29. // 采用优先级: [业务名] > [逻辑功能名] > [视觉效果名]
  30. class SreachPanel extends Component {
  31. constructor(props) {
  32. super(props);
  33. this.state = {};
  34. }
  35. render() {
  36. return (
  37. <Row className={headerStyle}>
  38. </Row>
  39. )
  40. }
  41. }
  42. SreachPanel.propTypes = propTypes;
  43. SreachPanel.defaultProps = defaultProps;
  44. export default SreachPanel;

在文件顶部描述组件功能或需求,以及编写人员的信息,可采用以下格式:

  1. /* [文件功能描述]
  2. * @Author: [作者名](联系方式)
  3. * @Date: [创建时间]
  4. * @Last Modified by: [作者名]
  5. * @Last Modified time: [最后修改时间]
  6. */
  • 尽可能的使用 PropTypes 做组件的属性预判,业务组件中可不做处理,common 下的尽量使用。
  • 使用 classnames 做样式(className)包装。
  • 多人维护的组件例如业务参照组件必须在每个构造方法前写明功能、作者等信息。格式请参考jsdco

例如:

  1. /**
  2. * 一个组件
  3. * @constructs
  4. * @param {ReactComponent} component - 待包装的组件
  5. * @author 妞妞
  6. */
  • 组件的命名规范可参考规则 [业务名] | [逻辑功能名] | [视觉效果名],例如:

[业务名命]:OrderGridSreachPanel
[逻辑功能名]:SreachPanel
[视觉效果名]:ExpandFormPanel
采用优先级 [业务名] > [逻辑功能名] > [视觉效果名]

  • ucf-common/components/Button/index.less 文件
  1. //采用上下文做约束,命名规范为
  2. // .[项目名]-common-[组件名]
  3. .baseorder-common-button{
  4. }
  • ucf-common/components/Button/README.md
  1. # 通用按钮组件 [需要描述组件名称]
  2. >通用项目及按钮组件,可实现添加默认的点击效果 [描述组件功能]
  3. ## 使用示例 [描述使用示例]
  4. ```javascript
  5. <Button />

API [描述重要API]

参数 类型 默认值 说明 必选
title string 打开上传的模态框显示的标题文字
className string 参照class样式,作用于弹出层的样式,默认为空。
  1. - ucf-common/components/README.md
  2. 该文档主要描述组件库的一些概览信息,记录历史版本等一些指导性说明
  3. ```markdown
  4. # IUAP通用组件 [组件库适用项目描述]
  5. > 此通用组件库适用 IUAP 项目,组件内部业务相关只适配当前工程[适应场景描述]
  6. ## 当前版本1.0 [若使用了版本控制需再次描述版本]
  7. - [新增] 按钮组件
  8. - [修复] 一些错误
  9. ## 通用组件说明
  10. - Button 通用项目及按钮组件,可实现添加默认的点击效果请参考(Button Api)[./components/Button/README.md]
  11. ## 历史版本
  12. - 1.0 添加Button组件
  13. - 0.1 创建组件库

其他说明:若同一个业务组件的文件下需拆分组件可按照其对应的功能名命名,而非命名为 index.js