Bit Shared Code

Posted by itsmeArry on Thu, 18 Nov 2021 18:27:19 +0100

Think in Component

Bit is a component-driven architecture for modern application development based on components. In Bit's world, everything is a component.

Components can be grouped into other components, which ultimately form an application APP, which is also a component.

This gives us a new idea for development: we build components that can be integrated into different applications instead of building applications that contain components.

Bit helps us build modular, robust, testable, reusable code.

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

Bit Advantage

  • Help us build modular, robust, testable, reusable code with the idea of component architecture.
  • Separate components from existing code structures without changing the structure or maintaining new projects.
  • You can change dependent components and create your own version to be managed independently without worrying about polluting other environments.

Initialize Bit Workspace

Install BVM & Bit

BVM Is a Bit version management tool, the same as NVM

// node version 12.22.0 and above
npm i -g @teambit/bvm

Perform bvm-h to verify that the installation was successful and set the environment variable if the BVM command is reminded that it is not available:

# 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

Perform a bit-h check to see if the installation was successful, and if the reminder bit command is unavailable, set the environment variable as described above.

bit new command initializes workspace

Suitable for new projects

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

bit init command initializes workspace

Apply to existing projects

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

Take the react environment as an example, modify the 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 upload workspace.jsonc and.bitmap to Git.

Create Components

Create with built-in components

Take react for example:

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

Note: where <component>can be a path and the preceding path is a namespace, the above example is equivalent to bit create react-component button --namespace ui.

  1. Add Test Cases
$ 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 the information about the component compilation environment, including files, dependencies, and so on.

$ bit show <component-id>

Example 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  │ 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)                                       │
  └───────────────┴────────────────────────────────────────────────────────────────────┘

View component status

$ bit status

View all versions of a component

$ bit log <component-id>

View a list of all local components

$ bit list

Start the test server

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

$ bit compile
$ bit start

Using Components

Bit does not allow relative path imports when importing another component as a dependency. Because this couples project-specific directory structures, use package names instead.

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

Bit creates a module for each component in the workspace that is linked in node_modules directory with its build output and auto-generated package.json.

To regenerate module links for components, run the bit link command.

Install components as NPM packages

The install command installs components, which are used as NPM packages.

As a Vendor component

Bit Workspace takes a component and manages it as if it were a custom component

Install components with the import command, as shown in the following example:

$ bit import <component-id>

Update import components to the latest version

$ bit import

Turn Vendor components into 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

A Bit server that hosts components and their versions.

characteristic

Set up Scope s on remote servers to share components, such as Bit.dev or self-hosted Bit servers.

Storing components on a 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.

Note: Remote Scope caches component dependencies, such as those of other Scopes. This has the advantage of ensuring that the current component is executable even if the dependent component is not available.

Use

After Bit Server creates the Remote Scope, you need to change the workspace.jsonc file:

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

Any changes in the workspace.jsonc file require the local development server to be restarted.

$ bit start

Workspace Scope

Local storage of workspace components.

characteristic

The developer's workspace keeps working copies of the components and their history in the local Scope. This allows us to browse the history, compare versions, and review past revisions of components.

Workspace Scope s may also contain components from different Remote Scope s.

Shared Components

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

Note: When the sharing upload process ends, the.bitmap file will be updated to reflect the 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 workflows, while npm packages focus on compiled output.

  • Generating NPM packages is only part of the Bit Component build process, which Bit calls version artifacts.

Configuration

Each component must be configured with an environment in which Bit "knows" how to build, test, link, and document components.

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

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

View Configuration

  • bit env - Prints a simple table containing all components in the workspace and their environments
  • Bit show <component> - Print all information about the component, including the environment
  • bit start - Visualize the component tree through a browser to see the component's environment

Remove Components

Remove Local Build

$ bit remove <component-id>

Impact:

  • An untracked component relies on deleting components - no effect

    • Because Bit has not isolated untracked components, its dependencies will not be detected
  • A tracked component relies on deleting the component - warning, use --force to force deletion
  • Imported remote components rely on deleting components - no impact

    • Because remote components are isolated and immutable
    • Locally introduced remote components and changes create another version

Remove remote components

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

Describe the impact with one example:

  • button component in remote uiScope
  • The card component relies on the button component, which is also in the uiScope
  • The login component relies on the button component in adminScope

Impact of deleting button components:

  • Because the card component is in the same Scope as the button component, there is a warning to delete the button component.

    • Appendable - force deletion
    • After deletion, the card component lacks dependencies and needs to be refactored to keep it working properly
  • login component has no effect

    • Bit maintains dependencies in Scope
  • Installation errors when other projects depend on login components

    • Source button component, missing

Compile Components

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

Bit's compiler is an environment service.

The choice of a compiler (Babel, TypeScript, and so on) and its configuration are determined by the various environments in which it serves.

Compilers never run directly, but only through the Compiler service.

A single workspace may run different compilers for different components, each depending on its environment.

$ bit compile <component-id> # Compile specific components
$ bit compile # Compile Workspace All Components

Component Dependency Diagram

A key feature of Bit is the ability to automatically create dependency diagrams from the source code of components.

Javascript can use require or import declarations to depend on two types of dependencies:

  • As node_ Packages installed by modules
  • Files and directories inside the project, or referenced in an ornament (for example, in Angular)

node_modules Dependency

The process for Bit parsing packages (that is, node_modules):

  • You can check the dependencies Bit resolves for each package by bit show <component-id>
$ 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      │
└───────────────────┴─────────────────────────────────────────────────────────────────────┘

If Bit cannot resolve all package dependencies, it prompts missing package dependencies. We need to verify that all packages do exist in package.json.

File Dependency

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

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

Note: Bit uses static code analysis and therefore only supports static import, not require.

Bit Resolve File Dependent Processes

When Bit encounters a file that needs to be tracked, it tries to check that the file has been tracked in another component, in which case Bit makes another component a dependency of that component.

If the file is not tracked, Bit warns untracked file dependencies when checking component status.

Isolation issues

To solve the isolation problem, you can:

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

Which of the above approaches 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 an internal file of the tracked file, you can add it as a file of the component.

Files added to existing components

Run bit add to point to the Id of the component to which you want to add the file:

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

Run bit status to check for success:

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

Tracking files as new components

New components can be added with bit add s

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

The result of execution is a new component.

Private Deployment v15

Hardware conditions

  • Linux/Mac System
  • Memory 4G+

Preconditions

  • Docker
  • Git
# Uninstall old docker
$ yum remove docker  docker-common docker-selinux docker-engine
# Install 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
# chkconfig mysqld on
$ 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 # Function
$ docker run -dit -p <port>:3000 bitcli/bit-server:latest
  • Dockerfile-bit:

    • Install bvm and then use bvm to install the docker file for bit.
    • This docker is often useful for running Bit commands like tag and export on a CI machine
  • Dockerfile-bit-server:

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

    • for internal use only

Related Issues

Mac computer ssh link: Permission denied

$ sudo ssh root@<ip>

WarNING warned when ssh links: REMOTE HOST IDENTIFICATION HAS CHANGE

$ sudo ssh-keygen -R <ip>

bvm install cannot install Bit

Temporarily change terminal agent

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

Be careful:

  • Require VPN
  • Ensure browser access to external network
  • Turn on VPN, the terminal cannot be proxied even globally

Permanent Modification Agent

# Modify ~/.bashrc Settings Permanent Management Script
function proxy_on() {
    export http_proxy=http://127.0.0.1:1087
    export https_proxy=$http_proxy
    echo -e "Terminal agent is turned on."
}

function proxy_off(){
    unset http_proxy https_proxy
    echo -e "The terminal agent has been shut down."
}

Note: After modification, take effect immediately through source ~/.bashrc.

By proxy_on Start Agent, 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

Listen for file changes to identify.

If the file does not change, it cannot be identified.

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

Note: Independent components form a dependency network through independent "remote scope" and remote component hosting.

This dependency network enables changes to propagate a component's changes to all its dependent components. That is, changes to a component trigger 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 were initially 0.0.1.

If component A is changed by 0.0.1, it will be A0.0.1-> 0.0.2 and B0.0.1-> 0.0.2 through bit tag--all.

If you continue to change component B, the version of A will not change through bit tag --all, B0.0.2-> 0.0.3.

Bit Deployment

Deployment requires a new identity, otherwise it cannot be deployed.

$ bit export

Extend Bit

We extend Bit by creating Aspect and API s that access Bit.

Extend Workspace UI

Take the new Tab as an example:

Initialize Bit Environment

$ bit init

New.bit/,.bitmap, workspace.jsonc files (folders) are created automatically.

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

Here, the hello-world.main.runtime.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);

Note: hello-world.main.runtime is responsible for extending workspace CLI and workspace Server.

To create a new menu on the Component Details page, we need to refer to the hello-world.main.runtime.ts file to create a new hello-world.ui.runtime.tsx file:

// 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);

Note: ComponentAspect is introduced here, which is the core Aspect of Bit and is responsible for building all the components and operations of the page. With ComponentAspect as a dependency, we can get it in the provider and use the API it provides.

// Update hello-world.ui.runtime.tsx
// Register registerNavigation 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 by relying on the registerNavigation provided by ComponentAspect, and manually switching navigation renders Hello.

// Update hello-world.ui.runtime.tsx
// Register registerRoute routing
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 a route by relying on the registerRoute provided by ComponentAspect, which takes on the registered navigation described above and renders the hello world simply.

Register Custom Aspect

To configure a resolution environment for Aspect before it is executed, it translates the Aspect into browser, nodejs-recognized code.

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

Installation Dependency

$ bit install

bit start works without installing dependencies, but no additional UI is visible.

Effect Display

Run bit start to see the effect~

Note: To update the display, delete.Bit/, node_modules, public/, execute bit install and bit start again.

View Aspect Information

View information halfway 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-name]
  • Install template-related dependencies through bit install
  • View custom extension status through bit status
  • If there is a dependency missing error, 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.

Topics: Front-end npm