Introducing Lit Component Development Environment

be
benjyg1 year ago

Lit support was first introduced to Bit in early 2022. Since then, numerous teams have used it to streamline the development process for their Bit Components. Over the past year, we gathered feedback from the community to improve processes, tooling and any defaults.

As part of a larger review for Bit's developer experience, we decided to upgrade the Lit env and provide it with improved capabilities and developer experience:

  • ESM support by default
  • Ability to wrap compositions with any styles or providers
  • Tooling configuration is clear, concise and to the point
  • Remove as many abstractions as possible
  • Better component template control and configuration

And much, much more…

We are confident that this will empower the expanding Bit + Lit community with greater control over their development process and enable them to enhance their workflow customization capabilities.

Create a Custom Lit Env with Bit

Below I will try to give you a sneak peek at the Lit env. For further reference, please visit the Lit Documentation Portal.

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

Run the following command:

$bit
Copiedcopy

The new workspace created contains a template for a custom Lit env for your Bit Components.

For existing workspaces, just add the following to the workspace.jsonc as a top-level field to add the Lit templates to your workspace:

"teambit.generator/generator": {
  "envs": [ "teambit.web-components/lit" ]
}
CopiedCopy

Creating Your Lit Development env

Create a lit env from the template:

$bit
Copiedcopy

The development experience starts with how you extend the defaults Bit provides for you, which means that when you don't "tap in" to modify a tool, you just use Bit's best practices for Lit development.

The default Lit env inherits from our base Lit env, with regular class inheritance.

export class MyLitEnv extends LitEnv {
}
CopiedCopy

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

tester(): EnvHandler<Tester> {
    return JestTester.from(...);
  }
  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-lit-env/config
├── eslintrc.js
├── jest.config.ts
├── prettier.config.ts
└── tsconfig.json
CopiedCopy

See the Lit documentation linked above for instructions on customising the config for each tool in the env.

Providers for Component Preview

A significant improvement for any Lit developer looking to build shared components is the introduction of the “preview” API.

This allows you to create a custom rendering env for all your components' examples and docs. This essentially mimics consumption contexts, such as adding global styles or css variables to component previews.

This way, you can simulate any component example you build with custom styles and providers applied by default.

preview(): EnvHandler<Preview> {
    return ReactPreview.from({
      docsTemplate: require.resolve('./preview/docs'),
      mounter: require.resolve('./preview/mounter'),
      hostDependencies,
      transformers: [litWebpackTransformation],
    });
  }
CopiedCopy

Using the Preview API you can control your own mounter function which renders component previews, and the docsTemplate which renders the component documentation.

For example, the Preview feature in Bit loads a mounter for your component previews. You can add your own providers - either wrappers or just general DOM elements (e.g. script tags) - to that mounter, which will then be rendered along with the preview.

For example, adding a blue border around all component previews:

const providerDiv = document.createElement('div');
providerDiv.setAttribute('style', "border-color:blue; border-width:5px; border-style: solid;");
export const MyHtmlProvider: HtmlProvider = {location: "body", content: providerDiv};

export default createMounter([MyHtmlProvider]);
CopiedCopy

Tip: By default, providers will be wrapped around your component previews. Add noWrap: true to the provider object to render it as a standalone element on the page.

While this example might not be amazingly useful, it demonstrates the idea - more useful options are setting a div with encapsulated styles for the composition, or adding global styles via a standalone script tag.

From this mounter you have full control over what will mount your component and provide any runtime requirements.

Migrating from Previous Implementation

If you are already using a previous Lit env for Bit, you can create a new env in your project as above and configure your components to use the newly created env. Once migration is completed and stable, we recommend deprecating your previous custom Lit env (if you had one).