从生产到消费,设计基于物料的前端开发链路-------------引用

 

什么是物料?

物料(Material)这个概念在前端领域大家都不陌生。让我们从前端应用的构成上说起,在 DOM 中 节点(Node)是最小单位,再之上是元素(Element)。React 带来了组件(Component) 的概念,一个组件是由一个或多个元素构成的,组件是元素的超集。

  1. // 在项目中定义一个组件

  2. export default function Component(props) {

  3. return (<h1>Hello, {props.name}</h1>);

  4. }

  5.  

  6. // 在项目中使用该组件

  7. import Component from './Component';

  8. function Home() {

  9. return (<div><Component name="ICE" /></div>);

  10. }

面向特定的前端领域,前端的组成部件在设计和交互上是可枚举、可抽象以及通用的,于是一些组件成为了该领域的前端开发的基石。它们就是基础组件(Base Component)。例如在企业级中后台领域中的组件库 Fusion Design / Ant Design 。

  1. // 在基础组件库中定义一个组件

  2. export function Button(props)

  3. // 一些处理逻辑

  4. return (<button {...props}>{props.children}</button>);

  5. }

  6.  

  7. // 在项目中使用基础组件库的的组件

  8. import { Button } from '@alifd/next';

  9. function Home() {

  10. return (<div>

  11. <Button type="normal">普通按钮</Button>

  12. <Button type="primary">主要按钮</Button>

  13. <Button type="secondary">次要按钮</Button>

  14. </div>);

  15. }

基础组件粒度小,强调通用性,难以覆盖所有场景。对于垂直业务而言,会有特定交互逻辑或数据处理逻辑,例如阿里的花名选择器、钉钉的唤醒图标、淘宝的小蜜机器人等等,它们就是业务组件(Business Component)。通常面向一个垂直业务,会有一个业务组件库,例如小二工作台业务组件。

  1. import { Button } from '@alifd/next';

  2. export default function DingTalk(orginProps) {

  3. const props = {

  4. ...orginProps,

  5. /* Business Logic */

  6. };

  7. return (<Button {...props}>{ /* Business Logic */ }</Button>);

  8. }

  9.  

  10. // 在项目中使用业务组件

  11. import DingTalk from '@ali/ding-talk';

  12. function Home() {

  13. return (<div>

  14. <DingTalk userId="foo" />

  15. </div>);

  16. }

对区块进行组合,就形成了页面(Page)。页面是一个浏览器窗口中所有功能的集合。一个或多个页面则组成了应用(Application)。开发应用的组织模式,就是前端项目(Project)。

自此,我们完成了对前端应用的析构,组件(基础/业务)、区块、页面这些构成应用的不同粒度单元就是物料。

为什么要基于物料?

 

基于组件进行前端开发已经是业界的共识了。实际场景中,区块、页面、脚手架在业务域中也有广泛的复用价值,各业务域存在的设计和交互规范,可以让前端对 UI 的抽象到更高更细的层次。因此如果能够抽丝剥茧,将业务域的物料进行整合,形成一套物料源,在业务域内进行流通,能够在业务域内有广泛的覆盖度进行复用和组合。物料这一层抽象,对于团队的分工协作,提升前端系统的可维护性,也大有裨益。

如何基于物料呢?需要有一定的开发模式。

我们对不同粒度的物料进行整合形成物料源(Material Collection),把物料源的组织模式称为物料项目(Material Project),它和前端项目中的物料对应关系如下:

 

 

 

然后设计基于物料的前端开发链路和角色,借助工具保障和提效各环节,从而保障生产质量、提升生产效率

初始化物料项目

物料项目中包含业务组件、区块、页面和脚手架多种粒度的物料。前面讲到了需要配套物料开发工具,我们提供的是物料开发命令行工具:Iceworks CLI,通过 $ iceworks init 创建一个物料项目,其目录结构如下:

  1. .

  2. ├── .eslintrc.js

  3. ├── .stylelintrc.js

  4. ├── README.md

  5. ├── package.json

  6. ├── blocks/ 区块集合

  7. │ └── ExampleBlock/ 单个区块包

  8. │ └── package.json

  9. ├── components/ 组件集合

  10. | └── ExampleComponent/ 单个业务组件包

  11. | └── package.json

  12. ├── pages/ 页面模板集合

  13. | └── ExamplePage/ 单个页面包

  14. | └── package.json

  15. └── scaffolds/ 脚手架集合

  16. └── ExampleScaffold/ 单个脚手架包

  17. └── package.json                                   项目内的 components/blocks/pages/scaffolds 文件夹是单种物料类型的集合,其子文件夹是一个个单独的物料包。

 

 

 

项目的 package.json 中重要字段是 materialConfig,它标明了当前物料项目是使用哪个物料模板资源包初始化的,后续也会用这个物料模板资源包来生成单个物料。

 

  1. {

  2. "materialConfig": {

  3. "template": "@icedesign/ice-react-ts-material-template",

  4. "type": "react"

  5. }

  6. }

Iceworks CLI 当前默认提供了多语言(TypeScript/JavaScript)以及多 DSL(React/Vue/Rax)的物料模板资源包,如果不满足(例如要开发基于 Angular 的物料项目),则可以通过开发相应的物料模板资源包,然后在初始化物料项目时指定使用的资源包来满足:$ iceworks init material-collection npmName

单个物料包的开发

 初始化物料项目完成,进入到单个物料包的开发流程。通过 $iceworks add 向物料项目添加单个物料包

 

 

 

 

 

业务组件

业务组件的开发与常见的 React 组件开发无太大差别。Iceworks 主要提供了组件本地开发调试和构建的能力。一个业务组件的物料包的组织如下:

 

  1. .

  2. ├── README.md 文档

  3. ├── build.json 构建配置

  4. ├── demo 使用示例,一个 md 文件一个示例

  5. │ └── usage.md

  6. ├── package.json

  7. ├── src 源代码

  8. │ ├── index.scss

  9. │ └── index.tsx

  10. └── tsconfig.json

需要特别说明的是:组件的 package.json 中的 componentConfig 是 Iceworks 专用的:

  1. {

  2. "componentConfig": {

  3. "name": "ExampleComponent", // 生成代码时使用的导入名

  4. "title": "demo component", // 用于展示标题

  5. "category": "Information" // 用于展示时进行的分类名,任意值

  6. }

  7. }

以开发一个业务组件为例的命名行执行过程:

  1. $ iceworks add component

  2. $ cd components/ExampleComponent

  3. $ npm install

  4. $ npm run start # 启动本地调试

  5. $ npm publish # 开发完成,执行 npm 发布

页面模板

页面物料和区块物料一样,是以源代码复制的方式被前端项目使用的。执行 $ iceworks add page 向物料项目添加一个页面模板资源包,其目录结果如下:

 

  1. .

  2. ├── README.md

  3. ├── build.json

  4. ├── config 模板配置文件

  5. │ ├── mock.js 模拟配置

  6. │ └── settings.json 配置设置

  7. ├── package.json

  8. ├── src 模板源文件

  9. │ ├── components

  10. │ │ └── User

  11. │ │ └── index.tsx.ejs

  12. │ └── index.tsx.ejs

  13. └── tsconfig.json

在页面资源包中,src 内存放的都是模板文件,模板使用 ejs 语法。一个模板示例(模板里面有 isShowUser 和 title 两个模板变量):

 

 

  1. import React, { useEffect, useState } from 'react';

  2. <% if (isShowUser) { %>

  3. import User from './components/User';

  4.  

  5. async function fetchUser() {

  6. return { name: 'ICE', age: '18' };

  7. }

  8. <% } %>

  9.  

  10. export default function() {

  11. <% if (isShowUser) { %>

  12. const [ user, setUser ] = useState({});

  13. useEffect(() => {

  14. async function initUser() {

  15. setUser(await fetchUser());

  16. }

  17. initUser();

  18. }, []);

  19. <% } %>

  20.  

  21. return (

  22. <>

  23. <div><%= title %></div>

  24. <% if (isShowUser) { %>

  25. <User {...user} />

  26. <% } %>

  27. </>

  28. );

  29. }

在 config/mock.js 中声明本地调试使用的模板变量模拟数据

  1. export default {

  2. isShowUser: true,

  3. title: '标题'

  4. };

在 config/setting.json 中声明模板变量的 Schema,Schema 字段使用 Formily Schema 协议,用于生成前台配置化表单:

 

  1. {

  2. "schema": {

  3. "title": "用户任务列表",

  4. "description": "显示用户信息",

  5. "type": "object",

  6. "required": [

  7. "isShowUser"

  8. ],

  9. "properties": {

  10. "isShowUser": {

  11. "type": "boolean",

  12. "title": "是否显示用户信息",

  13. "default": true

  14. },

  15. "title": {

  16. "type": "string",

  17. "title": "标题"

  18. }

  19. }

  20. }

  21. }

页面物料开发完成,执行 npm publish,将会依次执行:

  • 构建测试:检测是否有语法错误。

  • 生成缩略图:用于在物料中心和物料面板进行展示。

  • 发布 npm 包:发布 npm 目的是为了托管源代码到 npm,后续 Iceworks 将使用 npm 的 tarball 下载该源代码并使用。

自此,完成了页面物料的创建、开发和发布全流程。

 

posted @ 2020-10-12 19:02  又回到了起点  阅读(134)  评论(0编辑  收藏  举报