Think in Component

Bit是组件驱动架构,基于组件的古代利用开发。在Bit的世界里,所有皆组件。

组件能够组合成其余组件,最终组成一个利用APP,即APP也是组件的一种。

这为咱们开发提供一个新的思路:咱们构建能够整合成不同利用的组件,而不是构建蕴含组件的利用。

Bit帮咱们构建模块化、巩固的、可测试、可复用的代码。

Bit Cloud是组件的云托管服务。它为开发人员和团队提供端到端的解决方案,用于托管、组织、检索、应用、更新和合作解决组件。

Bit劣势

  • 以组件架构的思维帮忙咱们构建模块化、巩固的、可测试、可复用的代码。
  • 从现有代码构造中拆散组件,无需更改构造,或保护新的我的项目。
  • 可更改依赖组件,并创立本人的版本独立治理,无需担心净化其它环境。

初始化Bit工作区

装置BVM & Bit

BVM是Bit版本管理工具,雷同NVM

// node版本12.22.0以上npm i -g @teambit/bvm

执行bvm -h测验是否装置胜利,若揭示bvm命令不可用,须要设置环境变量:

# MacOs Bashecho 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc && source ~/.bashrc# zshecho 'export PATH=$HOME/bin:$PATH' >> ~/.zshrc && source ~/.zshrc# windowssetx path "%path%;%LocalAppData%\.bvm"

装置最新版bit:

bvm install

执行bit -h测验是否装置胜利,若揭示bit命令不可用,须要按上述流程设置一下环境变量。

bit new命令初始化工作区

实用于新建我的项目
$ bit new  <env> <project>$ cd <project>$ bit install

bit init命令初始化工作区

实用于已有我的项目
  1. 先初始化环境
$ cd <project>$ bit init --harmony
  1. 手动配置开发环境

以react环境为例,批改workspace.jsonc文件:

"teambit.workspace/variants": {  "*": {    "teambit.react/react": { }  }}
  1. 装置必要的peer依赖
$ bit install react --type peer$ bit install react-dom --type peer

初始化Git

须要将workspace.jsonc和.bitmap 上传到Git。

创立组件

应用内置组件创立

以react为例:

  1. 以内置模版创立组件bit create <built-in-template> <component>
$ bit templates # 查看所有的内置模版$ bit create react-component ui/button     # TypeScript$ bit create react-component-js ui/button  # JavaScript

留神:其中,<component>能够是个门路,前置门路为命名空间,上述示例等同于bit create react-component button --namespace ui。

  1. 增加测试用例
$ bit install @testing-library/react
  1. 编译并起服务
$ bit compile$ bit start

自定义组件

  1. 已有组件构造与代码
  2. 通过bit add <relative-path> --namespace <namespace>增加组件

查看组件信息

能够查看组件编译环境、蕴含文件、依赖等所有信息。
$ bit show <component-id>

输入信息示例:

  ┌───────────────┬────────────────────────────────────────────────────────────────────┐  │ id            │ my-scope/ui/button                                                 │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ scope         │ my-scope                                                           │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ name          │ ui/button                                                          │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ env           │ teambit.react/react                                                │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ package name  │ @my-scope/ui.button                                                │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ main file     │ index.ts                                                           │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ files         │ button.composition.tsx                                             │  │               │ button.docs.mdx                                                    │  │               │ button.tsx                                                         │  │               │ button.spec.tsx                                                    │  │               │ index.ts                                                           │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ dev files     │ button.docs.mdx (teambit.docs/docs)                                │  │               │ button.spec.tsx (teambit.defender/tester)                          │  │               │ button.composition.tsx (teambit.compositions/compositions)         │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ extensions    │ teambit.react/react                                                │  │               │ teambit.component/dev-files                                        │  │               │ teambit.compositions/compositions                                  │  │               │ teambit.pkg/pkg                                                    │  │               │ teambit.docs/docs                                                  │  │               │ teambit.envs/envs                                                  │  │               │ teambit.dependencies/dependency-resolver                           │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ dependencies  │ core-js@3.8.3- (package)                                           │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ dev           │ @testing-library/react@11.2.6- (package)                           │  │ dependencies  │ @babel/runtime@7.12.18-------- (package)                           │  │               │ @types/react-router-dom@5.1.7- (package)                           │  │               │ @types/jest@26.0.20----------- (package)                           │  │               │ @types/react@16.9.43---------- (package)                           │  │               │ @types/node@12.20.4----------- (package)                           │  ├───────────────┼────────────────────────────────────────────────────────────────────┤  │ peer          │ react@16.13.1----- (package)                                       │  │ dependencies  │ react-dom@16.13.1- (package)                                       │  └───────────────┴────────────────────────────────────────────────────────────────────┘

查看组件状态

$ bit status

查看组件所有版本

$ bit log <component-id>

查看本地所有组件列表

$ bit list

启动测试服务器

通过 worker 运行不同的工作区工作,例如测试、linter 和由组件定义的任何工作区工作。
$ bit compile$ bit start

应用组件

在导入另一个组件作为依赖时,Bit不容许应用相对路径导入。因为这会耦合我的项目特定的目录构造,请应用包名代替。

要将组件作为依赖项导入,必须应用模块链接。

Bit 为工作区中的每个组件创立一个模块,这些模块链接在 node_modules 目录中,并蕴含它的构建输入和主动生成的 package.json。

要为组件从新生成模块链接,请运行该bit link命令。

将组件装置为NPM包

install命令装置组件,以NPM包的模式应用。

作为Vendor组件

Bit工作区获取组件并治理该组件,就如同它是自定义组件一样

通过import命令装置组件,示例如下:

$ bit import <component-id>

更新import的组件到最新版本

$ bit import

将Vendor组件转为NPM包依赖

$ bit eject <component-id>

Scope

Scope是组件的虚拟存储。

Bit 应用Scope保留Bit组件的版本并依据须要拜访它们。

Remote Scope

托管组件及其版本的Bit服务器。

特色

在近程服务器上设置Scope以共享组件,如Bit.dev或自托管 Bit 服务器。

将组件存储在Remote Scope上,能够使它们在其余我的项目中重复使用。

  • 应用import命令从Remote Scope获取组件。
  • 应用export命令将组件推送到Remote Scope。

留神:Remote Scope会缓存组件依赖,例如其余Scope的组件。这样做的益处是,即便依赖组件不可用,还能确保以后组件可执行。

应用

在Bit Server创立Remote Scope后,须要更改workspace.jsonc文件:

{  "teambit.workspace/workspace": {    "defaultScope": "<bit-username>.<remote-scope-name>"  }}

workspace.jsonc文件中的任何更改都须要重新启动本地开发服务器。

$ bit start

Workspace Scope

工作区组件的本地存储。

特色

开发人员的工作区都在本地 Scope 中保留了组件及其历史记录的工作正本。这容许咱们浏览历史记录、比拟版本和查看组件的过来订正。

Workspace Scope也可能蕴含来自各异Remote Scope的组件。

共享组件

  1. 为已批改的组件更新版本号
$ bit tag --all --message "first version"
  1. 共享组件
$ bit export

留神:当共享上传流程完结,.bitmap文件将更新以反映该新状态。

装置组件

注册Scope源

$ npm config set '@YourUserName:registry' https://node.bit.dev

装置依赖

$ npm install @orgName/componentScopeName.componentID

Bit Component vs. NPM包

Bit 专一于基于组件的工作流,npm 包关注编译后的输入。
  • 生成NPM包只是Bit Component构建流程的局部,Bit称之为版本工件。

Configuration

每个组件都必须配置一个环境,好让Bit 就“晓得”如何构建、测试、lint 和document组件。

teambit.workspace/variants提供一个对立的形式,能够为每个组件设置不同的配置项,而无需批改每个组件文件下的 package.json 。

{  "teambit.workspace/variants": {    "design/theme": {      "defaultScope": "acme.theme",    },    "cart": {      "defaultScope": "acme.cart",      "teambit.react/react": {}    }  }}

查看配置

  • bit env - 打印一个简略的表格,其中蕴含工作区中的所有组件及其环境
  • bit show <component> - 打印组件的所有信息,包含环境
  • bit start- 通过浏览器可视化浏览组件树以查看组件的环境

移除组件

移除本地组建

$ bit remove <component-id>

产生的影响:

  • 一个未追踪的组件依赖 删除组件 —— 没有影响

    • 因为Bit还没有隔离未追踪的组件,不会检测其依赖
  • 一个已追踪的组件依赖 删除组件 —— 会正告,应用--force强制删除
  • 引入的近程组件依赖 删除组件 —— 没有影响

    • 因为近程组件是曾经隔离且不可更改的
    • 本地引入近程组件且更改会创立另一个版本

移除近程组件

$ bit remove <username.your-scope/ui/button> --remote

以一个例子形容产生的影响:

  • button组件在近程uiScope中
  • card组件依赖button组件,也在uiScope中
  • login组件依赖button组件,在adminScope中

删除button组件后的影响:

  • 因为card组件与button组件在同一个Scope中,因而删除button组件会有个正告。

    • 可追加---force强制删除
    • 删除后,card组件短少依赖,为保障其失常工作须要重构
  • login组件没有影响

    • Bit会在Scope中保护依赖
  • 其余我的项目依赖login组件时,装置会报错

    • 溯源button组件,缺失

编译组件

大多数古代框架都须要一个编译或转译我的项目来将源代码转换为能够在多个浏览器或 Nodejs 中运行的可执行代码。

而Bit 的编译器是一个环境服务。

编译器的抉择(Babel、TypeScript 等)及其配置由其服务的各种环境决定。

编译器永远不会间接运行,而只能通过 Compiler 服务运行。

单个工作区可能会针对不同的组件运行不同的编译器,每个编译器都依据本人的环境。

$ bit compile <component-id> # 编译特定组件$ bit compile # 编译工作区全副组件

组件依赖关系图

Bit 的一个要害个性是可能依据组件的源代码主动创立依赖关系图。

Javascript 能够应用 require 或 import 申明依赖两种类型的依赖项:

  • 作为 node_modules 装置的软件包
  • 我的项目外部的文件和目录,或在装璜器中援用(例如在 Angular 中)

node_modules依赖

Bit解析包(即node_modules)的流程:

  • 能够通过bit show <component-id>来查看 Bit 为每个包解析的依赖项(Packages):
$ bit show hello/world┌───────────────────┬─────────────────────────────────────────────────────────────────────┐│        ID         │                            hello/world                              │├───────────────────┼─────────────────────────────────────────────────────────────────────┤│     Language      │                             javascript                              │├───────────────────┼─────────────────────────────────────────────────────────────────────┤│     Main File     │                      src/hello-world/index.js                       │├───────────────────┼─────────────────────────────────────────────────────────────────────┤│     Packages      │                           left-pad@^2.1.0                           │├───────────────────┼─────────────────────────────────────────────────────────────────────┤│       Files       │       src/hello-world/hello-world.js, src/hello-world/index.js      │└───────────────────┴─────────────────────────────────────────────────────────────────────┘

如果 Bit 无奈解析所有包的依赖项,它会提醒missing package dependencies。咱们须要验证 package.json 中是否的确存在所有包。

文件依赖

组件能够依赖于其余文件,例如import ./utils.js。

为了隔离这些依赖其它文件的组件,咱们还须要跟踪该组件依赖的其它文件。这是因为如果咱们想在另一个我的项目中应用这个组件,该组件必须要有它的依赖文件。

留神:Bit 应用动态代码剖析,因而仅反对动态导入import,不反对require。

Bit解析文件依赖的流程

当 Bit 遇到须要跟踪的文件时,它会尝试查看该文件是否曾经在另一个组件中进行了跟踪,在这种状况下,Bit 将使另一个组件成为该组件的依赖项。

如果文件未被跟踪,Bit 将untracked file dependencies在查看组件状态时收回正告。

隔离问题

要解决隔离问题,您能够:

  • 将未跟踪的文件依赖项增加到现有组件
  • 将文件作为新组件进行跟踪

采取以上何种办法基于文件的上下文。如果该文件被多个其余组件应用,则将其放入一个独自的组件中是有意义的。

然而,如果此文件仅仅是被跟踪文件的外部文件,则能够将其增加为组件的文件。

文件增加到现有组件

运行bit add指向要增加文件的组件的 Id:

// 示例$ bit add src/utils/noop.js --id hello/world

运行bit status ,查看是否胜利:

$ bit statusnew components    > component/hello-world... ok

文件作为新组件进行跟踪

能够bit add增加新组件

// 示例$ bit add src/utils/noop.js --namespace utils

执行后果是一个新组件。

私有化部署v15

硬件条件

  • Linux/Mac零碎
  • 内存4G+

前置条件

  • Docker
  • Git
# 卸载旧版docker$ yum remove docker  docker-common docker-selinux docker-engine# 装置docker依赖$ yum install -y yum-utils device-mapper-persistent-data lvm2# 设置docker源$ yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo$ yum install docker-ce# 启动docker$ systemctl start docker# 退出开机启动$ systemctl enable docker
# 装置Git$ yum install git

部署流程

$ git clone https://github.com/teambit/bit.git$ cd bit/scripts/docker-teambit-bit$ docker build -f ./Dockerfile-bit -t bitcli/bit:latest .$ docker build -f ./Dockerfile-bit-server -t bitcli/bit-server:latest .$ docker run -dit bitcli/bit:latest /bin/bash # 运行$ docker run -dit -p <port>:3000 bitcli/bit-server:latest
  • Dockerfile-bit:

    • 装置 bvm 而后应用 bvm 装置 bit 的 docker 文件。
    • 这个 docker 通常对在 CI 机器上运行像 tag 和 export 这样的Bit命令很有用
  • Dockerfile-bit-server:

    • 一个基于Dockerfile-bit(应用 from)的docker 文件
    • 该docker文件创建一个空白Scope,并在其上通过bit start初始化Bit服务器
  • Dockerfile-symphony:

    • 仅供外部应用

相干问题

Mac电脑ssh链接: Permission denied

$ sudo ssh root@<ip>

ssh链接时报正告WARNING: REMOTE HOST IDENTIFICATION HAS CHANGE

$ sudo ssh-keygen -R <ip>

bvm install装置不了Bit

长期更改terminal代理

$ export http_proxy=http://127.0.0.1:1087$ export https_proxy=$http_proxy

留神:

  • 须要有VPN
  • 保障浏览器能够拜访外网
  • 开启VPN,即便全局,终端也是无奈被代理

永恒批改代理

# 批改~/.bashrc设置永恒治理脚本function proxy_on() {    export http_proxy=http://127.0.0.1:1087    export https_proxy=$http_proxy    echo -e "终端代理已开启。"}function proxy_off(){    unset http_proxy https_proxy    echo -e "终端代理已敞开。"}

留神:批改后,通过source ~/.bashrc立刻失效。

通过proxy_on启动代理,proxy_off敞开代理。

公布

注册近程Scope

# 客户端$ cd <my-project>$ bit init$ bit remote add http://<host>:<port>

workspace.jsonc

配置teambit.workspace/workspace

  "teambit.workspace/workspace": {    /**     * the name of the component workspace. used for development purposes.     **/    "name": "my-workspace-name",    /**     * set the icon to be shown on the Bit server.     **/    "icon": "https://static.bit.dev/bit-logo.svg",    /**     * default directory to place a component during `bit import` and `bit create`.     * the following placeholders are available:     * name - component name includes namespace, e.g. 'ui/button'.     * scopeId - full scope-id includes the owner, e.g. 'teambit.compilation'.     * scope - scope name only, e.g. 'compilation'.     * owner - owner name in bit.dev, e.g. 'teambit'.     **/    "defaultDirectory": "{scope}/{name}",    /**     * default scope for all components in workspace.     **/    "defaultScope": "remote-scope"  },

打Tag

监听文件变动,能力标识。

若文件无变动,无奈进行标识。

$ bit tag --all  --message "first version"

留神: 独立的组件通过独立的“近程范畴”、近程组件托管造成依赖关系网络。

这种依赖关系网络使更改可能让一个组件的扭转流传到它的所有依赖组件。也就是说,一个组件的更改以级联的形式触发了组件的CI及依赖它的组件的CI。

举例:

组件B依赖组件A,二者初始版本皆为0.0.1。

若组件A由0.0.1进行更改,通过bit tag --all会A0.0.1 —> 0.0.2,B0.0.1 —> 0.0.2。

若持续更改组件B,通过bit tag --all,B0.0.2 —> 0.0.3,A的版本不变。

Bit部署

部署的前提是有新的标识,否则,无奈部署。

$ bit export

扩大Bit

咱们通过创立Aspect和接入Bit的API来扩大Bit。

扩大Workspace UI

以新增Tab为例:

初始化Bit环境

$ bit init

会主动新建.bit/、.bitmap、workspace.jsonc文件(夹)。

批改DefaultScope

{  ...  "teambit.workspace/workspace": {    /**     * the name of the component workspace. used for development purposes.     **/    "name": "my-workspace-name",    /**     * set the icon to be shown on the Bit server.     **/    "icon": "https://static.bit.dev/bit-logo.svg",    /**     * default directory to place a component during `bit import` and `bit create`.     * the following placeholders are available:     * name - component name includes namespace, e.g. 'ui/button'.     * scopeId - full scope-id includes the owner, e.g. 'teambit.compilation'.     * scope - scope name only, e.g. 'compilation'.     * owner - owner name in bit.dev, e.g. 'teambit'.     **/    "defaultDirectory": "{scope}/{name}",    /**     * default scope for all components in workspace.     **/    "defaultScope": "me"  },  ...}

新建Aspect

$ bit create aspect aspects/hello-world

生成目录构造:

.└──me  └── aspects    └── hello-world      ├── hello-world.aspect.ts      ├── hello-world.main.runtime.ts      └── index.ts

其中,hello-world.main.runtime.ts代码如下:

// hello-world.main.runtime.tsimport { MainRuntime } from '@teambit/cli';import { HelloWorldAspect } from './hello-world.aspect';export class HelloWorldMain {  static slots = [];  static dependencies = [];  static runtime = MainRuntime;  static async provider() {    return new HelloWorldMain();  }}HelloWorldAspect.addRuntime(HelloWorldMain);

留神:hello-world.main.runtime是负责扩大workspace CLI和 workspace Server的。

为了在组件详情页创立一个新的菜单,咱们须要参考hello-world.main.runtime.ts文件新建hello-world.ui.runtime.tsx文件:

// hello-world.ui.runtime.tsximport React, { useContext } from 'react';import { UIRuntime } from '@teambit/ui';import { ComponentUI, ComponentAspect } from '@teambit/component';import { HelloWorldAspect } from './hello-world.aspect';export class HelloWorldUI extends React.Component<any> {  static slots = [];  static dependencies = [ComponentAspect];  static runtime = UIRuntime;  static async provider([component]: [ComponentUI]) {    return new HelloWorldUI();  }}HelloWorldAspect.addRuntime(HelloWorldUI);

留神:这里引入了ComponentAspect,它是Bit外围Aspect,负责组建页面所有的组件和操作。将ComponentAspect作为依赖,咱们能在provider中获取到它并应用它提供的API。

// 更新hello-world.ui.runtime.tsx// 注册registerNavigation导航import React, { useContext } from 'react';import { UIRuntime } from '@teambit/ui';import { ComponentUI, ComponentAspect } from '@teambit/component';import { HelloWorldAspect } from './hello-world.aspect';export class HelloWorldUI extends React.Component<any> {  static slots = [];  static dependencies = [ComponentAspect];  static runtime = UIRuntime;  static async provider([component]: [ComponentUI]) {     component.registerNavigation({         href: '~hello',         children: 'Hello'     });    return new HelloWorldUI();  }}HelloWorldAspect.addRuntime(HelloWorldUI);

这里,咱们通过ComponentAspect依赖提供的registerNavigation注册了导航,手动切换导航会渲染Hello。

// 更新hello-world.ui.runtime.tsx// 注册registerRoute路由import React, { useContext } from 'react';import { UIRuntime } from '@teambit/ui';import { ComponentUI, ComponentAspect } from '@teambit/component';import { HelloWorldAspect } from './hello-world.aspect';export class HelloWorldUI extends React.Component<any> {  static slots = [];  static dependencies = [ComponentAspect];  static runtime = UIRuntime;  static async provider([component]: [ComponentUI]) {     component.registerRoute({             children: () => <div>hello world</div>,             path: '~hello'         });     component.registerNavigation({         href: '~hello',         children: 'Hello'     });    return new HelloWorldUI();  }}HelloWorldAspect.addRuntime(HelloWorldUI);

这里,咱们通过ComponentAspect依赖提供的registerRoute注册了路由,该路由会承接上述注册的导航,简略的渲染了hello world。

注册自定义Aspect

在执行Aspect之前,要为其配置解析环境,该环境会将Aspect最终转译为浏览器、nodejs可辨认的代码。

{  ...  "teambit.workspace/variants": {    "{me/aspects/*}": {      "teambit.harmony/aspect":{}    }  },  "me/aspects/hello-world": {}  ...}

装置依赖

$ bit install

不装置依赖,bit start也是失常运行的,只是看不到减少的UI。

成果展现

运行bit start查看成果~

留神:若要更新展现,则要删除.bit/、node_modules、public/,再次执行bit install和bit start。

查看Aspect信息

中途可通过bit show me/aspects/hello-world查看信息

通过内置模板创立扩大

  • 通过bit templates查看内置模板
  • 通过`bit create <template> <custom-name> [--scope scope-name]
  • 通过bit install装置模板相干依赖
  • 通过bit status查看自定义扩大状态
  • 若有依赖缺失报错,将缺失依赖增加到:
  "teambit.dependencies/dependency-resolver": {    /**     * choose the package manager for Bit to use. you can choose between 'yarn', 'pnpm'     */    "packageManager": "teambit.dependencies/pnpm",    "policy": {      "dependencies": {},      "peerDependencies": {        "react": "~17.0.2",        "@testing-library/react": "~12.1.2"      }    }  },

bit install补充装置依赖。

  • 通过bit start --dev测试。