天天看點

從生産到消費,基于物料的前端開發鍊路

梧忌
從生産到消費,基于物料的前端開發鍊路

什麼是物料?

物料(Material) 這個概念在前端領域大家都不陌生。讓我們從前端應用的構成上說起,在 DOM 中 節點(Node) 是最小機關,再之上是 元素(Element) 。React 帶來了 元件(Component) 的概念,一個元件是由一個或多個元素構成的,元件是元素的超集。

// 在項目中定義一個元件 
export default function Component(props) {
  return (<h1>Hello, {props.name}</h1>);
}

// 在項目中使用該元件
import Component from './Component';
function Home() {
  return (<div><Component name="ICE" /></div>);
}           

面向特定的前端領域,前端的組成部件在設計和互動上是可枚舉、可抽象以及通用的,于是一些元件成為了該領域的前端開發的基石。它們就是基礎元件(Base Component)。例如在企業級中背景領域中的元件庫 Fusion Design / Ant Design 。

// 在基礎元件庫中定義一個元件 
export function Button(props) 
  // 一些處理邏輯
  return (<button {...props}>{props.children}</button>);
}

// 在項目中使用基礎元件庫的的元件
import { Button } from '@alifd/next';
function Home() {
  return (<div>
    <Button type="normal">普通按鈕</Button>
    <Button type="primary">主要按鈕</Button>
    <Button type="secondary">次要按鈕</Button>
  </div>);
}           
從生産到消費,基于物料的前端開發鍊路

基礎元件粒度小,強調通用性,難以覆寫所有場景。對于垂直業務而言,會有特定互動邏輯或資料處理邏輯,例如阿裡的花名選擇器、釘釘的喚醒圖示、淘寶的小蜜機器人等等,它們就是業務元件(Business Component)。通常面向一個垂直業務,會有一個業務元件庫,例如小二工作台業務元件。

// 定義一個業務元件
import { Button } from '@alifd/next';
export default function DingTalk(orginProps) {
  const props = {
    ...orginProps,
  /* Business Logic */
  };
  return (<Button {...props}>{ /* Business Logic */ }</Button>);
}

// 在項目中使用業務元件
import DingTalk from '@ali/ding-talk';
function Home() {
  return (<div>
    <DingTalk userId="foo" />
  </div>);
}           
從生産到消費,基于物料的前端開發鍊路

元件是一個高内聚的封裝,有單獨的開發周期,外部可以通過傳遞屬性(Props)的方式對其進行定制。通過對元件進行組合、嵌套,形成了更高階的前端功能組成單元 —— 區塊(Block)。可以簡單地把區塊了解為「用元件組成的代碼片段」,但通常區塊内部還包含事件處理、狀态管理、資料請求等邏輯。使用方式上,區塊與元件不同,區塊不對外提供可配置的屬性,是通過拷貝代碼的形式放到項目中的。這帶來的好處是區塊與前端項目無依賴關系,對區塊定制是通過修改項目中的區塊代碼來實作的。

// 定義一個區塊
import { Form, Input } from '@alifd/next';
import DingTalk from '@ali/ding-talk';

const FormItem = Form.Item;

function LoginForm() {
  return (<div>
    <Form inline>
      <FormItem label="使用者名:"><Input name="first"/></FormItem>
      <FormItem label="密碼:" required><Input htmlType="password" name="inlinePass"/></FormItem>
      <FormItem label=" "><Form.Submit>送出</Form.Submit></FormItem>
    </Form>
    <div>聯系我們:<DingTalk userId="foo" /> </div>
  </div>);
}

// 在項目中進行使用
import LoginForm from './LoginForm'; 
import Banner from './Banner';  
import Game from './Game'; 
function Home() {
  return (<div>
  <Banner />
    <LoginForm />
    <Game />
  </div>);
}           
從生産到消費,基于物料的前端開發鍊路

對區塊進行組合,就形成了頁面(Page)。頁面是一個浏覽器視窗中所有功能的集合。一個或多個頁面則組成了應用(Application)。開發應用的組織模式,就是前端項目(Project)。

從生産到消費,基于物料的前端開發鍊路

自此,我們完成了對前端應用的析構,元件(基礎/業務)、區塊、頁面這些構成應用的不同粒度單元就是物料。

為什麼要基于物料?

基于元件進行前端開發已經是業界的共識了。實際場景中,區塊、頁面、腳手架在業務域中也有廣泛的複用價值,各業務域存在的設計和互動規範,可以讓前端對 UI 的抽象到更高更細的層次。是以如果能夠抽絲剝繭,将業務域的物料進行整合,形成一套物料源,在業務域内進行流通,能夠在業務域内有廣泛的覆寫度進行複用群組合。物料這一層抽象,對于團隊的分工協作,提升前端系統的可維護性,也大有裨益。

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

我們對不同粒度的物料進行整合形成物料源(Material Collection),把物料源的組織模式稱為物料項目(Material Project),它和前端項目中的物料對應關系如下:

從生産到消費,基于物料的前端開發鍊路

然後設計基于物料的前端開發鍊路和角色,借助工具保障和提效各環節,進而保障生産品質、提升生産效率:

從生産到消費,基于物料的前端開發鍊路

如何開發物料?

在物料開發環節,需要的是規範物料源的開發流程以及配套的開發工具進行保障和提效。我們定義的一個物料源的開發流程如下:

從生産到消費,基于物料的前端開發鍊路

初始化物料項目

物料項目中包含業務元件、區塊、頁面和腳手架多種粒度的物料。前面講到了需要配套物料開發工具,我們提供的是物料開發指令行工具:Iceworks CLI,通過 $ iceworks init 建立一個物料項目,其目錄結構如下:

基礎元件庫的存量和增量都比較少,業務開發者通常不會接觸到這個領域,是以在本文不進行展開,有興趣的同學可以參考 alibaba-fusion/next 倉庫的組織。
.
├── .eslintrc.js
├── .stylelintrc.js
├── README.md
├── package.json
├── blocks/                         區塊集合
│   └── ExampleBlock/               單個區塊包
│       └── package.json
├── components/                     元件集合
|   └── ExampleComponent/           單個業務元件包
|       └── package.json
├── pages/                          頁面模闆集合
|   └── ExamplePage/                單個頁面包
|       └── package.json
└── scaffolds/                      腳手架集合
    └── ExampleScaffold/            單個腳手架包
        └── package.json           
完整的物料項目可參考 Fusion Materials

項目内的 components/blocks/pages/scaffolds 檔案夾是單種物料類型的集合,其子檔案夾是一個個單獨的物料包。

從生産到消費,基于物料的前端開發鍊路

項目的 package.json 中重要字段是 materialConfig,它标明了目前物料項目是使用哪個物料模闆資源包初始化的,後續也會用這個物料模闆資源包來生成單個物料。

{
  "materialConfig": {
    "template": "@icedesign/ice-react-ts-material-template",
    "type": "react"
  }
}           

Iceworks CLI 目前預設提供了多語言(TypeScript/JavaScript)以及多 DSL(React/Vue/Rax)的物料模闆資源包,如果不滿足(例如要開發基于 Angular 的物料項目),則可以通過開發相應的物料模闆資源包,然後在初始化物料項目時指定使用的資源包來滿足:$ iceworks init material-collection npmName。

單個物料包的開發

初始化物料項目完成,進入到單個物料包的開發流程。通過 $iceworks add 向物料項目添加單個物料包。

從生産到消費,基于物料的前端開發鍊路

業務元件

業務元件的開發與常見的 React 元件開發無太大差别。Iceworks 主要提供了元件本地開發調試和建構的能力。一個業務元件的物料包的組織如下:

.
├── README.md             文檔
├── build.json            建構配置
├── demo                  使用示例,一個 md 檔案一個示例
│   └── usage.md
├── package.json
├── src                   源代碼
│   ├── index.scss
│   └── index.tsx
└── tsconfig.json           

需要特别說明的是:元件的 package.json 中的 componentConfig 是 Iceworks 專用的:

{
  "componentConfig": {
    "name": "ExampleComponent", // 生成代碼時使用的導入名
    "title": "demo component", // 用于展示标題
    "category": "Information" // 用于展示時進行的分類名,任意值
  }
}           

以開發一個業務元件為例的命名行執行過程:

$ iceworks add component
$ cd components/ExampleComponent
$ npm install
$ npm run start # 啟動本地調試
$ npm publish # 開發完成,執行 npm 釋出           
業務元件示例: Anchor 或參考 《業務元件開發教程》

頁面模闆

頁面物料和區塊物料一樣,是以源代碼複制的方式被前端項目使用的。執行 $ iceworks add page 向物料項目添加一個頁面模闆資源包,其目錄結果如下:

.
├── README.md
├── build.json                    
├── config                         模闆配置檔案
│   ├── mock.js                   模拟配置
│   └── settings.json             配置設定
├── package.json
├── src                           模闆源檔案
│   ├── components
│   │   └── User
│   │       └── index.tsx.ejs
│   └── index.tsx.ejs
└── tsconfig.json           

在頁面資源包中,src 記憶體放的都是模闆檔案,模闆使用 ejs 文法。一個模闆示例(模闆裡面有 isShowUser 和 title 兩個模闆變量):

import React, { useEffect, useState } from 'react';
<% if (isShowUser) { %>
import User from './components/User';

async function fetchUser() {
  return { name: 'ICE', age: '18' };
}
<% } %>

export default function() {
  <% if (isShowUser) { %>
  const [ user, setUser ] = useState({});
  useEffect(() => {
    async function initUser() {
      setUser(await fetchUser());
    }
    initUser();
  }, []);
  <% } %>

  return (
    <>
      <div><%= title %></div>
      <% if (isShowUser) { %>
      <User {...user} />
      <% } %>
    </>
  );
}           

在 config/mock.js 中聲明本地調試使用的模闆變量模拟資料:

export default {
  isShowUser: true,
  title: '标題'
};           

在 config/setting.json 中聲明模闆變量的 Schema,Schema 字段使用 Formily Schema 協定,用于生成前台配置化表單:

{
  "schema": {
    "title": "使用者任務清單",
    "description": "顯示使用者資訊",
    "type": "object",
    "required": [
      "isShowUser"
    ],
    "properties": {
      "isShowUser": {
        "type": "boolean",
        "title": "是否顯示使用者資訊",
        "default": true
      },
      "title": {
        "type": "string",
        "title": "标題"
      }
    }
  }
}           

頁面物料開發完成,執行 npm publish,将會依次執行:

  • 建構測試:檢測是否有文法錯誤。
  • 生成縮略圖:用于在物料中心和物料面闆進行展示。
  • 釋出 npm 包:釋出 npm 目的是為了托管源代碼到 npm,後續 Iceworks 将使用 npm 的 tarball 下載下傳該源代碼并使用。

自此,完成了頁面物料的建立、開發和釋出全流程。

頁面模闆示例: UserLogin 《頁面模闆開發指南》

更多

受限于文章的篇幅,區塊和腳手架的開發在此不再展開,其中腳手架物料的開發與元件類似,區塊物料的開發與頁面物料類似。有興趣的同學可以參考:

釋出物料源

生成資料

所有物料包開發并釋出完成,在物料項目根目錄執行:$ iceworks generate 可生成物料源的資料到 build/material.json 檔案。指令行是根據物料項目的 package.sjon 和單個物料中的 package.json 檔案來生成這些資訊的。生成的資料中包含了開發工具需要用到的物料源資訊:

  • 物料源的名稱 name 和描述 description
  • 什麼類型的物料源 type:React/Vue/Rax
  • 有哪些物料集合:blocks/page/components/scaffolds
  • 單個物料的資訊:
    • 名稱和描述
    • 所屬分類:categories
    • 首頁:homepage
    • 代碼源:source
    • 依賴的包:dependencies
    • 截圖:screenshot

一個物料源資料示例如下:

參考完整的線上示例
{
   "name": "@iamalvin/material-collection",
   "type": "react",
  "template": "@icedesign/ice-react-ts-material-template",
  "description": "This is a ice material project",
  "author": "alvinhui",
  "blocks": [
    {
      "name": "ExampleBlock",
      "title": "demo block",
      "category": "Information",
      "description": "intro block",
      "homepage": "https://unpkg.com/@iamalvin/[email protected]/build/index.html",
      "categories": [
        "Information"
      ],
      "source": {
        "type": "npm",
        "npm": "@iamalvin/example-block",
        "version": "0.1.0",
        "registry": "https://registry.npmjs.org"
      },
      "dependencies": {
        "prop-types": "^15.5.8"
      },
      "screenshot": "https://unpkg.com/@iamalvin/[email protected]/screenshot.png"
    }
  ],
  "components": [
  ],
  "scaffolds": [
  ],
  "pages": [
  ]
}           
在《如何使用物料》章節将會描述開發工具是如何使用物料源資料來展示物料、下載下傳物料代碼。

釋出資料

在物料項目根目錄執行 npm publish 将物料源釋出到 npm ,得到 npm 的 CDN 托管服務 unpkg 的 URL 位址。釋出到 npm 本質是希望将 material.json 托管到 unpkg,這樣就能通過 unpkg 服務得到物料源的 URL 位址。

也可以将物料資料釋出到 阿裡巴巴物料中心。不管是将物料資料托管到阿裡巴巴物料中心還是 unpkg,本質上都是要有一個 URL 來讓開發工具通過 HTTP GET 請求擷取物料資料,是以,除了以上方式,你也可以将物料資料的 JSON 檔案放到你的 CDN (例如阿裡雲 OSS)或在某個後端接口中傳回該 JSON。

如何使用物料?

物料使用環節,核心是如何讓使用物料更簡單更高效。我們的開發工具 Iceworks 對 VS Code 進行了內建,隻需要 安裝插件,就可以在編輯器中可視化地使用物料搭建前端應用。使用流程如下:

從生産到消費,基于物料的前端開發鍊路

設定物料源

Iceworks 預設提供了官方的物料源來快速開始。對于打造定制物料源的業務鍊路,可以通過設定将定制物料源添加到 Iceworks。

  1. 有兩種方式打開設定面闆:
    • 點選 VS Code 左側活動欄的 Iceworks 圖示,再點選快速入口視圖中的「設定」;
    • 通過快捷鍵 ⇧⌘P 喚起 VS Code 命名面闆,在輸入框中輸入:Iceworks: 設定。
  2. 在設定面闆中點選自定義物料源右側的「添加」按鈕,輸入物料源名稱和位址,點選「确定」。
物料源的使用高度依賴 npm ,是以設定中提供了 npm 用戶端和鏡像源的設定。

元件&區塊

日常開發需要查找需要的元件,可以通過以下方式快速查找元件的文檔和示例:

從生産到消費,基于物料的前端開發鍊路
  • 查找所有元件的文檔和示例:
    • 點選 VS Code 左側活動欄的 Iceworks 圖示,再點選快速入口視圖中的「查找元件」;
    • 通過快捷鍵 ⇧⌘P 喚起 VS Code 命名面闆,在輸入框中輸入:Iceworks: 查找元件;
  • 查找目前檔案中用到的元件的文檔和示例:
    • 在編輯視窗點選滑鼠右鍵,在右鍵清單中選擇「Iceworks: 查找目前檔案的元件」;
    • 通過快捷鍵 ⇧⌘P 喚起 VS Code 命名面闆,在輸入框中輸入:Iceworks: 查找目前檔案的元件;
  • 查找目前代碼行元件的文檔和示例:滑鼠停留在元件使用處,在出現的懸浮框中點選「xxx 文檔」。
從生産到消費,基于物料的前端開發鍊路

然後是區塊的使用。區塊在物料源中,是以源代碼的形式存在的。在開發工具側,我們提供了物料面闆,一鍵将區塊(元件)添加到項目,操作流程和示範:

從生産到消費,基于物料的前端開發鍊路
  • 區塊的上一級粒度是頁面,是以目前限定區塊隻能添加到頁面檔案中,是以需要先打開頁面的入口檔案 page//index.;
  • 目前物料面闆中預設展示了所有的物料源,需要先選擇需要使用的物料源。

Iceworks 将插入元件&區塊代碼并自動引用區塊&元件,下載下傳區塊源代碼,安裝需要的依賴包。下面的流程圖描述了 Icework 在添加區塊的内部處理過程。通過流程中,即可了解到為什麼在物料源中,區塊不需要通過 npm install 的方式進行使用,還是需要釋出 npm :原因是開發工具将 npm 鏡像源當做了代碼托管平台。

從生産到消費,基于物料的前端開發鍊路

頁面是通過區塊組成的。是以除了能夠一鍵把區塊添加到頁面的代碼檔案中,還可以通過區塊組裝的方式來生成頁面,操作流程和示範如下:

從生産到消費,基于物料的前端開發鍊路

Iceworks 将自動下載下傳區塊源代碼并處理,然後再生成頁面的入口檔案。

頁面級物料是通過模闆的形式來承載的。在開發物料時,編寫的是模闆和配置描述。在實際使用時,物料源中的頁面模闆配置将在前台生成表單,開發者通過填寫表單的方式配置模闆,使用模闆代碼來生成頁面。使用流程和示範如下:

從生産到消費,基于物料的前端開發鍊路
從生産到消費,基于物料的前端開發鍊路

案例

在阿裡集團内部,已經有非常多的團隊運用物料開發鍊路到業務場景中,以下是一些案例:

從生産到消費,基于物料的前端開發鍊路

參考

從生産到消費,基于物料的前端開發鍊路

關注「Alibaba F2E」

把握阿裡巴巴前端新動向

繼續閱讀