Introducing Angular Component Development Environment

oc
ocombe2 years ago

Angular support was first introduced to Bit in 2021. Since then, many teams have used it to help streamline the development process for their Bit Components. Over the years, we have gathered feedback from the community to improve processes, tooling and any defaults.

During this time, we identified the fundamental things that we needed to improve for the Angular env:

  • Adding support for Standalone Components.
  • Configuring the preview to easily wrap compositions with any styles or providers (such as themes).
  • Simplifying tooling configuration to be more clear, concise and to the point.
  • Removing as many abstractions as possible.
  • Adding a simple way to create component templates and starters.
  • Being able to set/change default dependencies for all components.

And much, much more...

The foundations of this new env architecture are similar on all of the currently supported frameworks.

This means if you use another framework such as React or Vue, then it will be easier than before to make the switch.

We hope that this will allow our growing community better control over their development process and enhance the ability to customize workflows.

Create a Custom Angular Env with Bit

Below is a sneak peek at the changes to the Angular env. For more information, please visit the Angular Documentation Portal.

In this post we will create a new Bit Workspace, but you can also do this in an existing one.

Run the following command:

$bit
Copiedcopy

The new workspace created contains a custom Angular env pre-configured for your Bit Components.
The development process starts with extending the defaults Bit provides you:

export class MyAngularEnv extends AngularV15Env {
}
CopiedCopy

For each subsequent development operation, you can control the specific implementation using a dedicated function. For example:

override tester(): EnvHandler<Tester> {
    return JestTester.from();
  }
 override linter(): EnvHandler<Linter> {
    return ESLintLinter.from();
  }
CopiedCopy

As you can see, there is a dedicated directory containing all the configuration files used by default. You can directly modify any of the files to affect your components.

my-scope/envs/my-angular-env/config
├── eslintrc.js
├── jest.config.ts
├── prettier.config.ts
└── tsconfig.json
CopiedCopy

Providers for Component Preview

A significant improvement for any Angular developer looking to build shared components is the introduction of the preview API. This allows you to create a custom runtime env for all your components.

The “Preview” method lets you change the Angular options (similar to those from an angular.json config file) and the webpack configuration:

/**
   * Generates the component previews during development and build
   */
  override preview(): EnvHandler<Preview> {
    const ngEnvOptions = this.getNgEnvOptions();
    /**
     * To customize the dev server or bundler behavior, you can change webpack transformers, angular
     * options and webpack options in the getDevServer and getBundler methods.
     */
    const devServerProvider: DevServerProvider = (devServerContext: DevServerContext) => this.getDevServer(devServerContext, ngEnvOptions);
    const bundlerProvider: BundlerProvider = (bundlerContext: BundlerContext) => this.getBundler(bundlerContext, ngEnvOptions);
    return AngularPreview.from({
      devServerProvider,
      bundlerProvider,
      ngEnvOptions,
      hostDependencies,
      mounterPath: require.resolve('./preview/mounter'),
    });
  }
CopiedCopy

Using the Preview API you can control your own mounter function (see the mounter file in the “Previews” folder). This allows you to wrap your Previews with any context or styles.

Since components will be used in various apps and services, it might be important to have some part of the application's context available for a component. The Preview and Mounter features are a way to have a default composition env during development, so that you can focus on building a more loosely coupled component, and see how this looks and feels in a consuming runtime env.

The way this works is by changing the mounter function to add a wrapper for your components, which lets you have full control over the entry point of the preview:

import { createMounter } from '@teambit/angular-mounter';
import { Component, ViewEncapsulation } from '@angular/core';
import { ThemeModule } from '@my-scope/my-theme.provider';

@Component({
  selector: 'bit-wrapper',
  standalone: true,
  imports: [ThemeModule],
  encapsulation: ViewEncapsulation.None,
  template: `
    <my-theme>
      <ng-content></ng-content>
    </my-theme>
  `,
}) export class WrapperComponent {
}

export default createMounter(WrapperComponent);
CopiedCopy

Migrating from the Previous Implementation

If you are already using a previous Angular implementation for Bit, you can create a new env in your project and configure your components to use the newly created one. Once the migration is completed, we recommend deprecating the previous env so that you can move forward with a clean and fresh Component Development env.