1. 程式人生 > 前端設計 >是時候搭建你們團隊的 UI 元件庫了

是時候搭建你們團隊的 UI 元件庫了

一、技術棧

我們先簡單瞭解一下要搭建一個團隊的 UI 元件庫,會涉及到哪些技術棧:

  • Create React App:官方支援的 CLI 腳手架,提供一個零配置的現代構建設定;
  • React: 用於構建使用者介面的 JavaScript 庫;
  • Ant Design:一套企業級 UI 設計語言和 React 元件庫;
  • Storybook: 輔助 UI 控制元件開發的工具,通過story建立獨立的控制元件,讓每個控制元件開發都有一個獨立的開發除錯環境;
  • TypeScript:2020 最火的前端語言,是JavaScript型別的超集;
  • ESLint && husky:統一團隊程式碼風格;
  • Jest:JavaScript 測試框架,用於元件庫的單元測試;
  • Travis CI: 提供持續整合服務,用於進行專案的持續整合以及持續部署;

二、專案準備

2.1 建立元件庫的工程環境

使用 Create React App 建立 UI 元件庫的前端工程環境。

npx create-react-app ii-admin-base --typescript

2.2 安裝 Storybook

採用自動方式安裝 Storybook,命令如下:

npx -p @storybook/cli sb init --type react_scripts

  • 引數 react_scripts 用來告訴 Storybook 當前專案使用 Create React App
    建立的,Storybook會根據該引數來自動安裝合適的包。

2.3 安裝 Storybook 外掛

2.3.1 addon-info 外掛

addon-info 外掛會自動識別元件傳遞的 props 生成表格。

yarn add @storybook/addon-info -D yarn add @types/storybook__addon-info -D

三、配置 Storybook

在配置 Storybook 之前,先簡單瞭解下 stories 的載入流程。

stories 的載入是在 .storybook/main.js.storybook/preview.js 這兩個檔案中進行。載入 stories 的最簡便方式是按檔名進行載入。假設你的 stories 檔案位於 src/components

目錄,則可以通過如下方式進行載入:

// .storybook/main.js

module.exports = {
  stories: ['../src/components/**/*.stories.js'],};
複製程式碼

或者可以在 .storybook/preview.js 中載入所有的 stories

import { configure } from '@storybook/react';

configure(require.context('../src/components',true,/\.stories\.js$/),module);
複製程式碼

注意:在 .storybook/preview.js 檔案中,只能呼叫一次 configure 函式。

configure 函式接收引數為:

  • 單個 require.context “req”
  • 從多個地方載入檔案的 “req”s 陣列;
  • 返回值是 voidan array of module exports 的載入函式;

如果想從多個地方進行載入,可採用陣列方式,如下所示:

import { configure } from '@storybook/react';

configure(
  [
    require.context('../src/components',require.context('../lib',],module
);
複製程式碼

注:

如果想引入一個資料夾下面的所有檔案,或者引入能匹配一個正則表示式的所有檔案,可以使用函式require.context()require.context() 函式有 3 個引數:

  • 要搜尋的資料夾目錄;
  • 是否還應該搜尋它的子目錄;
  • 以及一個匹配檔案的正則表示式;

3.1 配置 stories 顯示順序

若想改變 stories 的顯示順序,該如何操作?示例如下,將 welcome.stories.tsx 先新增至陣列中,從而改變 stories 的顯示順序:

import { configure } from '@storybook/react';

// 將 welcome 文件說明置於頂部
const loaderFn = () => {
  const allExports = [require('../src/welcome.stories.tsx')];
  const req = require.context('../src/components',/\.stories\.tsx$/);
  req.keys().forEach((fname) => allExports.push(req(fname)));

  return allExports;
};

// automatically import all files ending in *.stories.tsx
configure(loaderFn,module);
複製程式碼

3.2 支援 Typescript

要搭建的基礎元件庫是基於 Typescript 進行編寫的,因此還需新增 Typescript 支援。配置 ./storybook/main.js 檔案,內容如下:

  webpackFinal: async (config) => {
    config.module.rules.push({
      test: /\.(ts|tsx)$/,use: [
        {
          loader: require.resolve('babel-loader'),options: {
            presets: [require.resolve('babel-preset-react-app')],},});

    return config;
  }
複製程式碼

3.3 配置 less

要搭建的基礎元件庫是基於 Ant Design 做的二次封裝,因此就不得不支援 less。針對 less,配置 ./storybook/main.js 檔案,內容如下:

 // .storybook/main.js

 webpackFinal: async (config) => {
    config.module.rules.push({
      test: /\.(ts|tsx)$/,});

    config.module.rules.push({
      test: /\.less$/,loaders: [
        'style-loader','css-loader',{
          loader: 'less-loader',options: {
            lessOptions: {
              javascriptEnabled: true,include: [path.resolve(__dirname,'../src'),/[\\/]node_modules[\\/].*antd/],});

    return config;
  },複製程式碼

完成上述內容配置,發現匯入的 less 檔案不生效。針對這一問題,進行了以下幾點排查。

問題1:
如果 less-loader 版本是 6.0 以上,則如下配置會報錯

{
  loader: "less-loader",options: {
    javascriptEnabled: true
  }
}
複製程式碼

需修改成:

 {
   loader: 'less-loader',options: {
       lessOptions: {
         javascriptEnabled: true,}
複製程式碼

問題2:
storybook 5.3.0 與 storybook 5.2.x 存在一些差異,見參考連結。cra(create-react-app)的 file-loader 會攔截所有其他檔案,導致less 檔案不能進入less-loader中。針對這一問題,需配置 @storybook/preset-create-react-app,配置內容如下:

{
  name: '@storybook/preset-create-react-app',options: {
      craOverrides: {
        fileLoaderExcludes: ['less'],}
複製程式碼

問題3:
此次搭建的基礎元件庫是基於 Ant Design 做的二次封裝,再對 Ant Design 元件進行引用時,發現樣式不生效。針對這一問題,可以在 preview.tsx 進行如下配置:

import { configure } from '@storybook/react';
import 'antd/dist/antd.less'    // 引入 antd 樣式
複製程式碼

3.4 新增全域性裝飾器

啟動 Storybook,會發現右側 stories 內容緊靠著左側選單欄,整體感覺非常緊湊、不美觀。針對這種情況通常可以通過新增 padding 來解決。那麼該如何讓 padding 對 Storybook 中的所有 stories 進行生效呢?這個時候就需使用到全域性裝飾器。

企業微信20200620091122.png
.storybook 目錄下,建立全域性裝飾器,如下所示:

// .storybook/decorators/WrapperDecorator/index.tsx

import React from 'react';

const wrapperStyle: React.CSSProperties = {
  padding: '20px 40px',};

// 建立一個樣式包裹的裝飾器
const WrapperDecorator = (storyFn) => <div style={wrapperStyle}>{storyFn()}</div>;

export default WrapperDecorator;
複製程式碼

然後在 preview.tsx 新增該裝飾器即可。

// .storybook/preview.tsx 

import { addDecorator,configure } from '@storybook/react';
import WrapperDecorator from './decorators/WrapperDecorator';

import 'antd/dist/antd.less';

// 通過addDecorator新增外掛
addDecorator(WrapperDecorator);
複製程式碼

最後效果如下所示。

WX20200620-092009.png

四、元件開發

4.1 驗證碼輸入元件

此次要示例的驗證碼輸入元件是一個帶驗證碼傳送功能的 Input 元件,如下圖所示。

Kapture 2020-06-27 at 9.55.02.gif
整個元件是在 Ant Design 的 Input 元件上進行的二次開發,詳細程式碼如下圖示所示:

import React,{ useState,FC } from 'react';
import { Input } from 'antd';
import { InputProps } from 'antd/lib/input';
import classNames from 'classnames';

export interface InputVerifyProps extends InputProps {
  /** 傳送驗證碼介面函式 */
  sendCode: () => void;
  /** 倒計時時間 */
  countDown?: number;
  /** 初始驗證碼文字內容 */
  initCodeText?: string;
  /** 重新發送驗證碼文字內容 */
  reCodeText?: string;
  /** 驗證碼類名 */
  codeClassname?: string;
}

export const InputVerify: FC<InputVerifyProps> = (props) => {
  const { sendCode,countDown,initCodeText,reCodeText,codeClassname,...restProps } = props;

  const [codeText,setCodeText] = useState(initCodeText);
  const [codeStatus,setCodeStatus] = useState(false);
  
  const handleCountDown = (timer: ReturnType<typeof setTimeout> | null,count: number) => {
    if (timer) {
      clearTimeout(timer);
    }

    if (count <= 0) {
      setCodeText(reCodeText);
      setCodeStatus(false);
    } else {
      setCodeText(`${count} s`);

      const newTimer: ReturnType<typeof setTimeout> = setTimeout(() => {
        handleCountDown(newTimer,count - 1);
      },1000);
    }
  };

  const handleCodeClick = () => {
    if (codeStatus) return;

    sendCode && sendCode();
    setCodeStatus(true);
    handleCountDown(null,countDown as number);
  };

  const codeCls = classNames('ii-verify-button',{
    'ii-verify-button-disabled': codeStatus,});

  return (
    <Input
      data-testid="test-input-verify"
      {...restProps}
      suffix={
        <span className={codeCls} onClick={handleCodeClick}>
          {codeText}
        </span>
      }
    />
  );
};

InputVerify.defaultProps = {
  countDown: 60,initCodeText: '傳送驗證碼',reCodeText: '重新發送',};

export default InputVerify;
複製程式碼

4.2 新增單元測試

完成元件開發任務後,接下來就需新增單元測試。針對驗證碼輸入元件,單元測試主要分兩個方面,一方面測試 antd 原生 Input 元件是否正常工作,另一方面則是測試驗證碼輸入元件是否正常工作。

import React from 'react';
import { render,fireEvent,wait,RenderResult } from '@testing-library/react';
import '@testing-library/jest-dom';
import '@testing-library/jest-dom/extend-expect';
import InputVerify,{ InputVerifyProps } from './InputVerify';

const antdProps: InputVerifyProps = {
  placeholder: 'antd input placeholder',size: 'large',sendCode: jest.fn(),onPressEnter: jest.fn(),onChange: jest.fn(),};

const selfProps: InputVerifyProps = {
  countDown: 3,initCodeText: '傳送驗證碼',reCodeText: '再次傳送',};

let wrapper: RenderResult,inputElement: HTMLInputElement;

describe("Test InputVerify component on the props of antd's input component",() => {
  beforeEach(() => {
    wrapper = render(<InputVerify {...antdProps} />);
    inputElement = wrapper.getByTestId('test-input-verify') as HTMLInputElement;
  });

  it("should have the input's class of antd",() => {
    expect(inputElement).toBeInTheDocument();
    expect(inputElement).toHaveClass('ant-input');
  });

  it('should support size',() => {
    expect(inputElement).toHaveClass('ant-input-lg');
  });

  it('should trigger onChange event correctly',() => {
    fireEvent.change(inputElement,{ target: { value: 'input test' } });
    expect(antdProps.onChange).toHaveBeenCalled();
    expect(inputElement.value).toEqual('input test');
  });
});

describe("Test InputVerify component on the self's props",() => {
  beforeEach(() => {
    wrapper = render(<InputVerify {...selfProps} />);
  });

  it('should render the correct InputVerify component',() => {
    const suffixElement = wrapper.getByText('傳送驗證碼');

    expect(suffixElement).toBeInTheDocument();
    expect(suffixElement).toHaveClass('ii-verify-button');
  });

  it('click verify button should call the right callback ',async () => {
    const suffixElement = wrapper.getByText('傳送驗證碼');

    fireEvent.click(suffixElement);
    expect(selfProps.sendCode).toHaveBeenCalled();

    await wait(
      () => {
        expect(wrapper.getByText('再次傳送')).toBeInTheDocument();
      },{ timeout: 4000 }
    );
  });
});

複製程式碼

4.3 元件說明文件

當開發完單個元件,還需新增相應的文件說明,告訴其他人該如何使用這個元件。

4.3.1 自動生成說明文件

如果想通過註釋方式來自動生成元件的說明文件,這個時候就需藉助 react-docgen 外掛。由於 @storybook/addon-info依賴包對 react-docgen 外掛已進行了整合,所以編寫註釋的時候只需按照 JSDoc 標準來編寫就會生成相應的說明文件。

/**
 * 帶驗證碼功能的輸入元件,適用於要傳送驗證碼的場景。
 *
 * ## 引用方法
 *
 * ~~~javascript
 * import { InputVerfiy } from 'ii-admin-base'
 * ~~~
 */
export const InputVerify: FC<InputVerifyProps> = (props) => {
複製程式碼

注意: react-docgen 外掛要求元件還需通過 export 方式進行匯出。

4.3.2 過濾 Prop Types

@storybook/addon-info 外掛在自動生成 Prop Types 的說明文件時,會連元件繼承的 Props 也自動生成,這裡面不僅包括了第三方依賴包攜帶的 props,還可能包括 HTML 元素的原生 Props。若要過濾這些 Props,就需藉助依賴包 react-docgen-typescript-loader

先安裝該依賴:

yarn add react-docgen-typescript-loader -D

然後配置 main.js檔案,配置內容如下:

// .storybook/main.js

config.module.rules.push({
  test: /\.(ts|tsx)$/,use: [
    {
      loader: require.resolve('babel-loader'),options: {
        presets: [require.resolve('babel-preset-react-app')],// 過濾 node_modules 中的 props
    {
      loader: require.resolve('react-docgen-typescript-loader'),options: {
        // 將列舉或者聯合型別轉換成字串形式,避免字串字面量顯示別名。
        shouldExtractLiteralValuesFromEnum: true,// 避免顯示原生內建屬性
        propFilter: (prop) => {
          if (prop.parent) {
            return !prop.parent.fileName.includes('node_modules');
          }

          return true;
        },});
複製程式碼

注意:

在使用最新的 Storybook v5.3.19 版本時,發現上述配置並不生效。針對這一問題,可以將 Storybook 版本降至 5.3.18 來進行規避。

WX20200620-165852.png

五、構建及測試

5.1 打包構建

5.1.1 建立元件庫的模組入口檔案

src/index.tsx 檔案中將所有元件都匯入,再匯出。這樣就可以從入口檔案直接匯入所有元件。

export { default as InputVerfiy } from './components/InputVerify';
複製程式碼

5.1.2 編譯 TS 檔案

使用 CRA(Create-React-App) 預設會建立一個 tsconfig.json 檔案,該配置檔案是與開發環境相關的。要針對元件庫進行打包編譯,並生成標準的 ES modules,還需單獨建立一個 tsconfig.build.json 檔案。

/**
 * 用於最後打包編譯
 */
{
  "compilerOptions": {
    // 檔案輸出目錄
    "outDir": "dist",// ESNext: 是標準的ES Modules形式
    "module": "esnext",// 指定編譯以後符合什麼樣的ES標準
    "target": "es5",// 為每一個js檔案生成一個對應的.d.ts型別檔案,方便使用元件庫的使用者可以獲得型別檢查和ts提示
    "declaration": true,// jsx 是一種語法糖,是React.createElement的縮寫。此處置為react,編譯出來的檔案就可以用React.createElement來代替JSX語法的過程
    "jsx": "react",// tsc 處理模組的方式和node不一樣,預設處理方式是"classic",針對絕對路徑有的時候會找不到檔案(一直向上找檔案),所以需設定成'node'。
    "moduleResolution": "node",// 預設不支援 import React from 'react',只支援 import * as React from 'react'
    "allowSyntheticDefaultImports": true
  },// 要編譯哪些檔案
  "include": ["src"],"exclude": ["src/**/*.test.tsx","src/**/*.stories.tsx"]
}

複製程式碼

然後在 package.json 檔案中新增 build:ts 指令碼,用於將 TS 檔案編譯成 ES modules 檔案。

"build:ts": "tsc -p tsconfig.build.json",

5.1.3 編譯 less 檔案

package.json 檔案中新增 build:css 指令碼,用於將 less 檔案編譯成 css 。

"build:css": "lessc ./src/styles/index.less ./dist/index.css"

5.1.4 配置最終構建指令碼

在 package.json 中配置最終的構建指令碼 build,如下所示:

 "clean": "rimraf ./dist","build:ts": "tsc -p tsconfig.build.json","build:css": "lessc ./src/styles/index.less ./dist/index.css","build": "npm run clean && npm run build:ts && npm run build:css",複製程式碼
  • 使用 rimraf 來完成跨平臺檔案的刪除;

5.2 本地測試元件庫

5.2.1 新增入口檔案

在進行本地元件庫測試之前,還需新增元件庫的入口檔案。配置 package.json 檔案,新增如下欄位:

"main": "dist/index.js","module": "dist/index.js","types": "dist/index.d.ts",複製程式碼

其中:

  • main 欄位:定義了 npm 包的入口檔案;
  • module 欄位:定義了 npm 包的 ES6 模組規範的入口檔案;

注: 此處使用 main 欄位和 module 欄位,相當於在一個包內同時釋出了兩種模組規範的版本。當打包工具遇到我們的模組時:

  1. 如果它已經支援 pkg.module 欄位則會優先使用 ES6 模組規範的版本,這樣可以啟用 Tree Shaking 機制;
  2. 如果它還不識別 pkg.module 欄位則會使用我們已經編譯成 CommonJS 規範的版本,也不會阻礙打包流程。

5.2.2 使用 npm link 測試本地元件庫

在元件庫目錄下,執行 npm link 命令,即建立軟連結到全域性的 node_modules 下。

/Users/xxx/.nvm/versions/node/v12.14.0/lib/node_modules/ii-admin-base -> /Users/xxx/Job/ii-admin-base

在專案外層,建立一個測試目錄 test-ii-admin-base,然後在該目錄下執行 npm link ii-admin-base 命令,將測試目錄的元件庫 ii-admin-base 連結到全域性:

➜ test-ii-admin-base npm link ii-admin-base /Users/xxx/Job/test-ii-admin-base/node_modules/ii-admin-base -> /Users/xxx/.nvm/versions/node/v12.14.0/lib/node_modules/ii-admin-base -> /Users/xxx/Job/ii-admin-base

然後修改測試目錄 test-ii-admin-base 的 package.json檔案,手動新增依賴:

 "dependencies": {
    ...,"ii-admin-base": "0.1.0"
複製程式碼

這樣就可以在測試目錄中引用元件庫 ii-admin-base

import { InputVerfiy } from 'ii-admin-base'
import 'ii-admin-base/dist/index.css'
import 'antd/dist/antd.css'
複製程式碼

注: 如果在測試的過程中,報如下錯誤:

企業微信20200626052311.png
這是因為我們開發元件庫時使用了一個React版本,測試目錄又使用了一個React版本,當一個專案中如果出現多個 React 版本就會報上述錯誤。針對這種情況,只需要在元件庫目錄下執行如下命令: npm link ../test-ii-admin-base/node_modules/react,即將元件庫的 react 版本連結到測試元件目錄下,然後重新執行專案即可。

六、釋出至 NPM

6.1 登入 NPM 賬號

先切換官方映象源。

npm config set registry registry.npmjs.org/

檢測當前賬號是否登入:

npm whoami

如果未登入,則使用 npm adduser 進行賬號登入。

6.2 釋出至 NPM

6.2.1 新增描述資訊

在釋出到 NPM 之前,還需配置 package.json 檔案,新增一些必要的描述資訊:

{
  "name": "ii-admin-base","version": "0.1.0","private": false,"description": "A library of react components,which mainly stores components that can be reused by all business lines of AI-Indeeded Company.","author": "ShiMu","license": "MIT","keywords": [
    "React","Component"
  ],"homepage": "https://lagrangelabs.github.io/ii-admin-base","repository": {
    "type": "git","url": "https://github.com/LagrangeLabs/ii-admin-base.git"
  },"files": [
    "build"
  ],"scripts": {
    "start": "react-scripts start","build": "react-scripts build","test": "react-scripts test","eject": "react-scripts eject","storybook": "start-storybook -p 9009 -s public","build-storybook": "build-storybook -s public","prepublishOnly": "npm run build"
  },...
}
複製程式碼

其中:

  • private 欄位置為 false,表示非私有包;
  • 新增 descriptionauthorlicensekeywords 等相關欄位;
  • 新增 homepage 欄位,即專案主頁URL;
  • 新增 repository 欄位,即專案倉庫地址URL;
  • 新增 files 欄位,表示要將哪些檔案上傳到 npm 上去。如果什麼都不寫,則預設會使用 .gitignore 裡面的資訊。但要注意,不管 .gitignore 怎麼配置,一些檔案會始終釋出到 package 上,這些檔案包括 package.jsonREADME.mdLICENSE 等等;
  • 新增 prepublishOnly 鉤子函式,在該鉤子函式中執行 npm run build ,用來確保 NPM 包釋出之前採用的是最新編譯的程式碼;

6.2.2 配置 peerDependencies 欄位

此次搭建的元件庫是在 React 基礎上對 Ant Design 進行的二次封裝。為了減少元件庫體積,通常不會將React、Ant Design 等第三方依賴打包進去,其次若打包進去,可能還會造成各個版本之間的衝突。

針對這種情況,可以提示使用者如果要想使用當前元件庫,還需安裝以下核心依賴,如 reactAnt Design 等,這個時候就需利用 package.json 中的 peerDependencies 欄位。當使用 npm install 安裝依賴時, peerDependencies 宣告的依賴不會被自動安裝,而是通過輸出 warining 日誌告訴使用者需安裝以下依賴。

"peerDependencies": {
    "react": ">= 16.8.0","react-dom": ">= 16.8.0","antd": ">= 4.3.5"
 },複製程式碼
  • react 版本需大於等於 v16.8.0,因為在 v16.8.0 以上版本才引入了 React Hooks;

6.2.3 程式碼規範檢查和單元測試檢查

對於一個元件庫來說,程式碼質量是非常重要的。為了防止不符合團隊規範的程式碼或未通過單元測試的程式碼被commit 亦或者被 publish,需要使用一些鉤子函式來驗證開發者是否通過程式碼規範檢查和單元測試檢查。

6.2.3.1 新增程式碼規範檢查

package.json檔案中,新增 lint 指令碼,針對 src 目錄下的檔案進行 eslint 檢查。

 "lint": "eslint --ext js,ts,tsx,src --max-warnings 5",複製程式碼
  • --max-warnings 5 : 表示最大允許的 warnings 警告是 5;
6.2.3.2 新增單元測試檢查

在使用 CRA 建立專案時,預設會建立 test 指令碼,但該指令碼是用於開發環境,執行完後不會返回執行結果(即不會返回執行通過還是未通過),而是一直處於 watch 模式下。針對這一情況,可以設定環境變數 CI=true ,即可返回測試執行結果。

 "test:nowatch": "cross-env CI=true npm run test"
複製程式碼
  • 在不同的作業系統環境下,設定環境變數方式不一樣。故需藉助 cross-env 依賴包完成跨平臺的環境變數設定。
6.2.3.3 commit 或 publish 前的流程檢查

針對 commit 程式碼,安裝 husky 依賴,在程式碼提交前先進行單元測試檢查和程式碼規範檢測,如下所示。在釋出NPM 包之前也進行同樣配置。

"scripts": {
    ...,"prepublishOnly": "npm run test:nowatch && npm run lint && npm run build"
  },"husky": {
    "hooks": {
      "pre-commit": "npm run test:nowatch && npm run lint"
    }
  },複製程式碼

完成上述配置後,執行命令 npm publish 即可完成 NPM 包的釋出。

七、配置持續整合環境

通常從各個業務線上抽離的基礎元件庫,會是各個業務線的團隊成員一起來維護,這個時候就可以利用 Github 提供的 Github Organization 來共同維護這個元件庫。

在這種情況下,使用 Travis CI 進行持續整合就沒有那麼簡單了。之前寫過一篇文章如何使用Travis CI對Github Organization下的程式碼進行持續整合,可以參照該文章完成基礎元件庫的持續整合環境配置。

八、持續釋出

Travis CI 還可以自動將元件庫釋出到 NPM 上,具體設定如下:

  1. 進入 npm 個人賬號中心,生成一個新的Token(許可權選擇 Read and Publish),用於Travis CI 進行 npm 包的釋出。

image.png

  1. 在元件庫目錄下,執行 travis setup npm --force 命令,注意該命令會改寫之前的 travis.yml 檔案。此時會提示輸入 NPM api key,如下所示,將剛才生成的Token值複製貼上此處即可。

NPM api key: ************************************

改寫後的 travis.yml 檔案:

language: node_js
node_js:
  - stable
cache:
  directories:
    - node_modules

env:
  matrix:
    - CI=true

script:
  - npm run build-storybook

deploy:
  # 釋出到 gh-pages 上
  - provider: script
    skip_cleanup: true
    script: bash scripts/deploy.sh
    on:
      branch: master
  # 釋出到 npm 上
  - provider: npm
    skip_cleanup: true
    email: [email protected]
    api_key:
      secure: Lsb1/coESXgnDgcotaObyV7QKDVeZJWpAcduyZt/bxAqspN/EdOR2duraPpBHKzme7tOHT4ybIAQusJqSl36K/WX2WFXqhKHw+FoFOobK1aa/azQDkpwllgdxrlx0fCbLpxBPDdKxbJspXwphSgCi2rjY8F/PBdy4+g8IEh/FJQckuFHAEhpTuk+SZPJT5eAqhctxXSaNKB712x4vX9AJLHRT791nB388dsjKOz2NWGNJ14arxukvnb/Yt02hHWKpGQPgQQY9QjfENYnspFYBXYssKV2nhC+0EFoXNn6UK3C4gXo96hV2yqFbP0AhZdHiYxOJ/v1KN7xt+I3popw+puETFyno4TgepGqU/EvkB5r3DnB9CrYsOpeN4+wZtfVtwxMxxxJ8q/EbC7RH45b39056B0i7PnJViIHLWps3XxFQ/bi1CgWdiFyzNofwCYVV6uT0UNR0XZDqUzre10GBrvDogMNWPKMaTmJCWVA8c6AkB4XjfU/jY1xaWxbNuD+Z+p3uLSTKm+c2xrUJFl5KW4/ocyS8No/J+e/9uNkXYcTEdkwnBioWfT7OaBrIpzrkKL9RftkDzjkeUo8h9/XpXNHEUGMK6ZDO0n3zlQ8/qcMHJvS5dXbKmvwZ9GNnOS1EvR1X32MlTfcW0EzDgCXufyAK6UdUGm7jm+dfJJkD60g=
    on:
      branch: master
      repo: LagrangeLabs/ii-admin-base
複製程式碼

注: Travis CI 在對元件庫進行持續釋出的時候,如果報如下問題:

sh: 1: cross-env: not found
npm ERR! code ELIFECYCLE
npm ERR! syscall spawn
npm ERR! file sh
複製程式碼

針對這一問題,將 package.json 檔案中的 cross-env 換成 ./node_mdoules/.bin/cross-env 即可。

 "test:nowatch": "./node_modules/.bin/cross-env CI=true npm run test"
複製程式碼

九、小結

至此,就完成了團隊元件庫的整個搭建過程。

其他: