Bit shared code

Time:2022-5-5

Think in Component

Bit is a component driven architecture for modern application development based on components. In the world of bit, everything is a component.

Components can be combined into other components to finally form an application app, that is, app is also a kind of component.

This provides a new idea for our development: we build components that can be integrated into different applications, rather than building applications containing components.

Bit helps us build modular, stable, testable and reusable code.

Bit cloud is a cloud hosting service for components. It provides end-to-end solutions for developers and teams to host, organize, retrieve, use, update, and collaborate on processing components.

Bit shared code

Bit advantage

  • The idea of component architecture helps us build modular, stable, testable and reusable code.
  • Separate components from existing code structures without changing the structure or maintaining new projects.
  • You can change dependent components and create your own version for independent management without worrying about polluting other environments.

Initialize bit workspace

Install BVM & bit

BVMIt is a bit version management tool, similar to NVM

//Node version above 12.22.0
npm i -g @teambit/bvm

Run BVM – h to check whether the installation is successful. If you remind BVM that the command is unavailable, you need to set the environment variable:

# MacOs Bash
echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc && source ~/.bashrc

# zsh
echo 'export PATH=$HOME/bin:$PATH' >> ~/.zshrc && source ~/.zshrc

# windows
setx path "%path%;%LocalAppData%\.bvm"

Install the latest version of bit:

bvm install

Execute bit – h to check whether the installation is successful. If the reminder bit command is unavailable, you need to set the environment variables according to the above process.

The bit new command initializes the workspace

Applicable to new projects

$ bit new  <env> <project>
$ cd <project>
$ bit install

The bit init command initializes the workspace

Applicable to existing projects

  1. Initialize environment first
$ cd <project>
$ bit init --harmony
  1. Manually configure the development environment

Take react environment as an example, modify workspace Jsonc file:

"teambit.workspace/variants": {
  "*": {
    "teambit.react/react": { }
  }
}
  1. Install the necessary peer dependencies
$ bit install react --type peer
$ bit install react-dom --type peer

Initialize Git

You need to add workspace Jsonc and Upload bitmap to GIT.

Create component

Create using built-in components

Take react as an example:

  1. Create component with built-in template bit create < build in template > < component >
$bit templates # view all built-in templates
$ bit create react-component ui/button     # TypeScript
$ bit create react-component-js ui/button  # JavaScript

be careful:Among them, < component > can be a path, and the front path is a namespace. The above example is equivalent to bit create react component button — namespace UI.

  1. Add test case
$ bit install @testing-library/react
  1. Compile and start service
$ bit compile
$ bit start

Custom components

  1. Existing component structure and code
  2. Add components through bit add < relative path > — namespace < namespace >

View component information

You can view all information about the component compilation environment, including files, dependencies, and so on.

$ bit show <component-id>

Example of output information:

  ┌───────────────┬────────────────────────────────────────────────────────────────────┐
  │ 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  │ [email protected] (package)                                           │
  ├───────────────┼────────────────────────────────────────────────────────────────────┤
  │ dev           │ @testing-library/[email protected] (package)                           │
  │ dependencies  │ @babel/[email protected] (package)                           │
  │               │ @types/[email protected] (package)                           │
  │               │ @types/[email protected] (package)                           │
  │               │ @types/[email protected] (package)                           │
  │               │ @types/[email protected] (package)                           │
  ├───────────────┼────────────────────────────────────────────────────────────────────┤
  │ peer          │ [email protected] (package)                                       │
  │ dependencies  │ [email protected] (package)                                       │
  └───────────────┴────────────────────────────────────────────────────────────────────┘

View component status

$ bit status

View all versions of components

$ bit log <component-id>

View a list of all local components

$ bit list

Start the test server

Run different workspace tasks through worker, such as tests, linkers, and any workspace tasks defined by components.

$ bit compile
$ bit start

Using components

Bit does not support importing another component as a dependencyAllow relative Import paths。 Because this will couple the project specific directory structure, use the package name instead.

To import components as dependencies, you must use module links.

Bit creates a module for each component in the workspace, and these modules are linked in the node_ Modules directory and contains its build output and automatically generated package json。

To regenerate the module link for the component, run the bit link command.

Install components as NPM packages

The install command installs components in the form of NPM package.

As vendor component

The bit workspace gets the component and manages it as if it were a custom component

Install components through the Import command, for example:

$ bit import <component-id>

Update the imported components to the latest version

$ bit import

Convert vendor components to NPM package dependencies

$ bit eject <component-id>

Scope

Scope is the virtual storage of components.

Bit uses scope to save versions of bit components and access them as needed.

Remote Scope

The bit server that hosts the component and its version.

characteristic

Set up scope on the remote server toShared components,Such as bit Dev or self managed bit server.

Storing components on remote scope allows them to be reused in other projects.

  • Use the Import command to get components from remote scope.
  • Use the export command to push components to remote scope.

be careful:Remote scope caches component dependencies, such as components from other scopes. The advantage of this is to ensure that the current component is executable even if the dependent component is not available.

use

After creating remote scope in bit server, you need to change workspace Jsonc file:

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

workspace. Any changes in the jsonc file require restarting the local development server.

$ bit start

Workspace Scope

Local storage of workspace components.

characteristic

The developer’s workspace holds working copies of components and their history in the local scope. This allows us to browse history, compare versions, and check past revisions of components.

Workspace scope may also contain components from different remote scopes.

Shared components

  1. Update the version number for the modified component
$ bit tag --all --message "first version"
  1. Shared components
$ bit export

be careful:When the sharing upload process ends The bitmap file will be updated to reflect this new state.

Install components

Register scope source

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

Installation dependency

$ npm install @orgName/componentScopeName.componentID

Bit component vs. NPM package

Bit focuses on component-based workflow, and NPM package focuses on compiled output.

  • Generating NPM package is only part of the build process of bit component, which is called version artifact by bit.

Configuration

Each component must be configured with an environment so that bit can “know” how to build, test, lint and document components.

teambit. Workspace / variants provides a unified way to set different configuration items for each component without modifying the package under each component file json 。

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

View configuration

  • Bit env – prints a simple table that contains all the components in the workspace and their environments
  • Bit show < component > – print all the information of the component, including the environment
  • Bit start – visual browsing through the browserComponent treeTo view the environment of the component

Remove components

Remove local build

$ bit remove <component-id>

Impact:

  • An untraceable component depends on deleting the component – no impact

    • Because bit has not isolated untraceable components, its dependencies will not be detected
  • A tracked component depends on deleting the component — it will be warned, and use — force to force deletion
  • The introduced remote component relies on deleting components – no impact

    • Because remote components are isolated and cannot be changed
    • The remote component is introduced locally and the change creates another version

Remove remote components

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

Describe the impact with an example:

  • Button component in remote uiscope
  • The card component depends on the button component, which is also in uiscope
  • The login component depends on the button component, which is in adminscope

Impact after deleting button component:

  • Because the card component is in the same scope as the button component, there will be a warning when deleting the button component.

    • Appendable — force forced deletion
    • After deletion, the card component lacks dependencies and needs to be reconstructed to ensure its normal operation
  • The login component has no effect

    • Bit will maintain dependencies in scope
  • When other projects depend on the login component, the installation will report an error

    • Traceability button component, missing

Compile component

Most modern frameworks require a compilation or translation project to convert source code into executable code that can run in multiple browsers or nodejs.

The bit compiler is an environment service.

The choice of compiler (Babel, typescript, etc.) and its configuration are determined by the various environments it serves.

The compiler will never run directly, but only through the compiler service.

A single workspace may run different compilers for different components, each according to its own environment.

$bit compile < component ID > # compile specific components
$bit compile # compiles all components in the workspace

Component dependency diagram

A key feature of bit is that it can automatically create dependency diagrams according to the source code of components.

JavaScript can declare two types of dependencies using require or import:

  • As node_ Modules installed packages
  • Files and directories within the project, or referenced in the decorator (for example, in angular)

node_ Modules dependency

Process of bit parsing package (i.e. node_modules):

Bit shared code

  • You can use bit show < component ID > to check the packages resolved by bit for each package:
$ bit show hello/world
┌───────────────────┬─────────────────────────────────────────────────────────────────────┐
│        ID         │                            hello/world                              │
├───────────────────┼─────────────────────────────────────────────────────────────────────┤
│     Language      │                             javascript                              │
├───────────────────┼─────────────────────────────────────────────────────────────────────┤
│     Main File     │                      src/hello-world/index.js                       │
├───────────────────┼─────────────────────────────────────────────────────────────────────┤
│     Packages      │                           [email protected]^2.1.0                           │
├───────────────────┼─────────────────────────────────────────────────────────────────────┤
│       Files       │       src/hello-world/hello-world.js, src/hello-world/index.js      │
└───────────────────┴─────────────────────────────────────────────────────────────────────┘

If bit cannot resolve all package dependencies, it will prompt missing package dependencies. We need to verify the package Whether all packages do exist in JSON.

File dependency

Components can rely on other files, such as import/ utils. js。

In order to isolate these components that depend on other files, we also need to track other files that the component depends on. This is because if we want to use this component in another project, the component must have its dependency files.

be careful:Bit uses static code analysis, so it only supports static import and does not support require.

Bit parsing file dependent process

Bit shared code

When bit encounters a file that needs to be tracked, it will try to check whether the file has been tracked in another component. In this case, bit will make another component a dependency of the component.

If the file is not tracked, bit will issue an untracked File Dependencies warning when checking the component status.

Isolation problem

To solve the isolation problem, you can:

  • Add untracked file dependencies to existing components
  • Trace files as new components

Which of the above methods is based on the context of the file. If the file is used by multiple other components, it makes sense to put it in a separate component.

However, if this file is only the internal file of the tracked file, it can be added as the file of the component.

Add files to existing components

Run bit add to point toAdd file componentsID of:

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

Run bit status to check whether it is successful:

$ bit status
new components
    > component/hello-world... ok

Files are tracked as new components

You can add new components with bit add

//Examples
$ bit add src/utils/noop.js --namespace utils

The result of execution is a new component.

Privatization deployment V15

Bit shared code

Hardware conditions

  • Linux / MAC system
  • Memory 4G+

Preconditions

  • Docker
  • Git
#Uninstall old docker
$ yum remove docker  docker-common docker-selinux docker-engine
#Installing docker dependencies
$ yum install -y yum-utils device-mapper-persistent-data lvm2
#Set docker source
$ yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ yum install docker-ce
#Start docker
$ systemctl start docker
#Join startup
$ systemctl enable docker
#Install Git
$ yum install git

Deployment process

$ 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 # run
$ docker run -dit -p <port>:3000 bitcli/bit-server:latest
  • Dockerfile-bit:

    • Install BVM, and then use BVM to install the docker file of bit.
    • This docker is usually useful for running bit commands such as tag and export on CI machines
  • Dockerfile-bit-server:

    • A docker file based on dockerfile bit (using from)
    • The docker file creates a blank scope and initializes the bit server through bit start on it
  • Dockerfile-symphony:

    • For internal use only

Related issues

Mac SSH link: permission denied

$ sudo ssh [email protected]<ip>

SSH link times warning: remote host identification has change

$ sudo ssh-keygen -R <ip>

BVM install cannot install bit

Temporary change of terminal agent

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

be careful:

  • VPN required
  • Ensure that the browser can access the Internet
  • When VPN is enabled, the terminal cannot be proxy even if it is global

Permanent modification agent

#Modify ~ / Bashrc set persistent management script
function proxy_on() {
    export http_proxy=http://127.0.0.1:1087
    export https_proxy=$http_proxy
    Echo - e "terminal agent turned on."
}

function proxy_off(){
    unset http_proxy https_proxy
    Echo - e "terminal agent is closed."
}

be careful:After modification, use source ~ / Bashrc takes effect immediately.

Through proxy_ On start proxy_ Off closes the agent.

release

Register remote scope

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

workspace.jsonc

Configure 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

Only by listening to file changes can we identify.

If there is no change in the file, it cannot be identified.

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

be careful:Independent components form a dependency network through independent “remote scope” and remote component hosting.

This dependency network enables changes to be propagated from one component to all its dependent components. In other words, the change of a component triggers the Ci of the component and the Ci of the component that depends on it in a cascading manner.

give an example:

Component B depends on component A, both of which have an initial version of 0.0.1.

If component A is changed from 0.0.1, A0 will be changed through bit tag — all 0.1 —> 0.0.2,B0. 0.1 —> 0.0.2。

If you continue to change component B, click bit tag — all, B0 Version a – > 0.0.2 unchanged.

Bit deployment

The premise of deployment is to have a new identity. Otherwise, it cannot be deployed.

$ bit export

Bit shared code

Extended bit

We extend bit by creating aspect and API accessing bit.

Expand workspace UI

Take the new tab as an example:

Initialize bit environment

$ bit init

It will be created automatically bit/、. bitmap、workspace. Jsonc file (folder).

Modify 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"
  },
  ...
}

New aspect

$ bit create aspect aspects/hello-world

Generate directory structure:

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

Among them, hello world main. runtime. The TS code is as follows:

// hello-world.main.runtime.ts
import { 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);

be careful:hello-world. main. Runtime is responsible for extending workspace CLI and workspace server.

In order to create a new menu in the component details page, we need to refer to Hello world main. runtime. TS file creates a new Hello world ui. runtime.tsxFile:

// hello-world.ui.runtime.tsx
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]) {
    return new HelloWorldUI();
  }
}

HelloWorldAspect.addRuntime(HelloWorldUI);

be careful:Componentaspect is introduced here. It is the core aspect of bit and is responsible for building all components and operations of the page. Taking componentaspect as a dependency, we can get it in the provider and use the API it provides.

//Update Hello world.com ui. runtime. tsx
//Register navigation
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);

Here, we register navigation through registernavigation provided by componentaspect dependency. Manually switching navigation will render hello.

//Update Hello world.com ui. runtime. tsx
//Register registerroute route
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);

Here, we register the route through the registerroute provided by componentaspect dependency. The route will undertake the navigation of the above registration and simply render Hello world.

Register custom aspect

Before executing an aspect, it needs to be configured with a parsing environment, which will eventually translate the aspect into code recognized by the browser and nodejs.

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

Installation dependency

$ bit install

Without installing dependencies, bit start works normally, but you can’t see the added UI.

Effect display

Run bit start to check the effect ~

Bit shared code

be careful:To update the presentation, delete it bit/、node_ Modules, public /, and execute bit install and bit start again.

View aspect information

You can view the information through bit show me / aspects / Hello world

Create extensions from built-in templates

  • View built-in templates through bit templates
  • Through ` bit create < template > < custom name > [– scope scope name]
  • Install template related dependencies through bit install
  • View custom extension status through bit status
  • If there is an error in missing dependency, add the missing dependency to:
  "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 supplements installation dependencies.

  • Pass the bit start — dev test.