<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matt Angelosanto</title>
    <description>The latest articles on DEV Community by Matt Angelosanto (@mangelosanto).</description>
    <link>https://dev.to/mangelosanto</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F643722%2Fce6ad6d9-9867-44c8-a490-a61bedb41ae0.png</url>
      <title>DEV Community: Matt Angelosanto</title>
      <link>https://dev.to/mangelosanto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mangelosanto"/>
    <language>en</language>
    <item>
      <title>Using semantic-release to automate releases and changelogs</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Thu, 25 Jan 2024 21:22:38 +0000</pubDate>
      <link>https://dev.to/logrocket/using-semantic-release-to-automate-releases-and-changelogs-1dg</link>
      <guid>https://dev.to/logrocket/using-semantic-release-to-automate-releases-and-changelogs-1dg</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/sebastianweber/" rel="noopener noreferrer"&gt;Sebastian Weber&lt;br&gt;
&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The focus of this article is to demonstrate how to automate releases and release notes with &lt;a href="https://semantic-release.gitbook.io/semantic-release/" rel="noopener noreferrer"&gt;semantic-release&lt;/a&gt; in &lt;a href="https://docs.gitlab.com/" rel="noopener noreferrer"&gt;GitLab&lt;/a&gt;. semantic-release is a Node CLI application, but it can be used to publish any type of package. This article will explore how to publish npm packages in a private GitLab registry.&lt;/p&gt;
&lt;h2&gt;
  
  
  An introduction to semantic-release
&lt;/h2&gt;

&lt;p&gt;It is not a trivial task to decide when and how to increase version numbers and sync them with release notes. The goal of semantic-release is to take over this job based on established software engineering patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;Semantic Versioning&lt;/a&gt;: An established convention for version numbers following the pattern MAJOR.MINOR.PATCH&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt;: A spec to establish human- and machine-readable commit messages. In our case, semantic-release is analyzing commit messages following this convention&lt;/li&gt;
&lt;li&gt;  Publish releases on &lt;a href="https://semantic-release.gitbook.io/semantic-release/recipes/release-workflow/distribution-channels" rel="noopener noreferrer"&gt;distribution channels&lt;/a&gt; with &lt;a href="https://docs.npmjs.com/adding-dist-tags-to-packages" rel="noopener noreferrer"&gt;distribution tags&lt;/a&gt; (dist-tags)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;semantic-release parses the commit messages and extracts certain information, such as the release type and scope. Based on this, the Git history, and the used and configured semantic-release plugins, a new version is calculated, a release is created — which might be published to some registry — and release notes are updated. &lt;/p&gt;

&lt;p&gt;In the next section, we’ll set up semantic-release with GitLab. After that, I’ll provide a detailed use case of various commit messages on different branches leading to different versions and release notes.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to work with the companion project
&lt;/h2&gt;

&lt;p&gt;This article is based on a Node project that represents a simplified addition and subtraction CLI tool. Although the actual application code is not important, I decided to use a somewhat realistic example so the commit messages, release types, changelogs, and version changes are understandable. &lt;/p&gt;

&lt;p&gt;You can follow along with this &lt;a href="https://gitlab.com/doppelmutzi/companion-project-semantic-release" rel="noopener noreferrer"&gt;GitLab project&lt;/a&gt; in parallel while reading the article.&lt;/p&gt;
&lt;h2&gt;
  
  
  Configuring a semantic-release workflow
&lt;/h2&gt;

&lt;p&gt;The goal of this article is to execute the semantic-release bot in a pipeline step whenever a new commit is pushed to a branch, which is configured in semantic-release's &lt;code&gt;release.config.cjs&lt;/code&gt; config file. &lt;/p&gt;

&lt;p&gt;In this simplified project, the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .gitlab-ci.yml&lt;/span&gt;

&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:latest&lt;/span&gt;
&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;lint&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
&lt;span class="na"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lint&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm run lint&lt;/span&gt;
&lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;next&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "@doppelmutzi:registry=https://${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/" &amp;gt; .npmrc&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${NPM_TOKEN}" &amp;gt;&amp;gt; .npmrc&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm i -g semantic-release @semantic-release/gitlab @semantic-release/changelog @semantic-release/git @semantic-release/npm @semantic-release/commit-analyzer conventional-changelog-conventionalcommits&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx semantic-release --debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that config in place, the &lt;code&gt;release&lt;/code&gt; pipeline step runs for the &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;next&lt;/code&gt; branches if the &lt;code&gt;lint&lt;/code&gt; step is successful. Let's look at the &lt;code&gt;release&lt;/code&gt; job in more detail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;next&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm i -g semantic-release @semantic-release/gitlab @semantic-release/changelog @semantic-release/git @semantic-release/npm @semantic-release/commit-analyzer @semantic-release/release-notes-generator conventional-changelog-conventionalcommits&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx semantic-release --debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two variants to install semantic-release: &lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/installation#local-installation" rel="noopener noreferrer"&gt;local or global installation.&lt;/a&gt; We’ll opt for installing all npm packages globally with the global flag &lt;code&gt;-g&lt;/code&gt;. &lt;code&gt;semantic-release&lt;/code&gt; constitutes the actual tool, whereas the packages with scope &lt;code&gt;@semantic-release&lt;/code&gt; are optional plugins. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/conventional-changelog/conventional-changelog" rel="noopener noreferrer"&gt;conventional-changelog-conventionalcommits&lt;/a&gt; is a package used for creating conventional commits and has a bit more configuration possibilities with changelogs in contrast to the default Angular commit scheme. &lt;/p&gt;

&lt;p&gt;Here is a brief overview of the plugins used in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/semantic-release/gitlab" rel="noopener noreferrer"&gt;&lt;code&gt;@semantic-release/gitlab&lt;/code&gt;&lt;/a&gt; to publish GitLab releases&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/semantic-release/changelog" rel="noopener noreferrer"&gt;&lt;code&gt;@semantic-release/changelog&lt;/code&gt;&lt;/a&gt; to create or update changelog files&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/semantic-release/git" rel="noopener noreferrer"&gt;&lt;code&gt;@semantic-release/git&lt;/code&gt;&lt;/a&gt; to commit changes to the Git repository, e.g., an updated &lt;code&gt;package.json&lt;/code&gt; version or updates to changelog files&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/semantic-release/npm" rel="noopener noreferrer"&gt;&lt;code&gt;@semantic-release/npm&lt;/code&gt;&lt;/a&gt; to publish npm packages in a public or private registry&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/semantic-release/commit-analyzer" rel="noopener noreferrer"&gt;&lt;code&gt;@semantic-release/commit-analyzer&lt;/code&gt;&lt;/a&gt; to analyze commit messages with respect to conventional commit conventions&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/semantic-release/release-notes-generator" rel="noopener noreferrer"&gt;&lt;code&gt;@semantic-release/release-notes-generator&lt;/code&gt;&lt;/a&gt; to generate content for the changelog file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another approach to set up semantic-release for GitLab is to just install the package &lt;a href="https://github.com/semantic-release/gitlab-config" rel="noopener noreferrer"&gt;semantic-release/gitlab-config&lt;/a&gt;, which represents a shareable config that comes with the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;@semantic-release/commit-analyzer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@semantic-release/release-notes-generator&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@semantic-release/npm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@semantic-release/gitlab&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It isn’t required to install all the plugins because some are shipped with the semantic-release package. &lt;/p&gt;

&lt;p&gt;The plugins &lt;code&gt;@semantic-release/gitlab&lt;/code&gt;, &lt;code&gt;@semantic-release/npm&lt;/code&gt;, and &lt;code&gt;@semantic-release/git&lt;/code&gt; require authentication to push commits, create GitLab releases, and publish to GitLab's private registry. Therefore, we need to create a project access token (PAT)( &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Access Tokens&lt;/strong&gt;) with the following scopes: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fproject-access-token-required-allow-semantic-release-create-releases.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fproject-access-token-required-allow-semantic-release-create-releases.png" alt="A Project Access Token Is Required TO Allow Semantic-Release To Create Releases"&gt;&lt;/a&gt; Next, copy the token and create an environment variable (&lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;CI/CD&lt;/strong&gt; &amp;gt; &lt;strong&gt;Expand&lt;/strong&gt; &amp;gt; &lt;strong&gt;Add variable&lt;/strong&gt;): &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ftoken-stored-gitlabtoken-env-variable.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ftoken-stored-gitlabtoken-env-variable.png" alt="The Token Needs To Be Stored In The GITLAB_TOKEN Environment Variable"&gt;&lt;/a&gt; According to the &lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/ci-configuration#authentication" rel="noopener noreferrer"&gt;semantic-release documentation&lt;/a&gt;, you need a variable name of &lt;code&gt;GITLAB_TOKEN&lt;/code&gt; or &lt;code&gt;GL_TOKEN&lt;/code&gt; to authenticate semantic-release for GitLab. &lt;/p&gt;

&lt;p&gt;We need one more token to enable semantic-release to publish into GitLab's private npm registry. Create a deploy token (&lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Repository&lt;/strong&gt; &amp;gt; &lt;strong&gt;Deploy token&lt;/strong&gt;s &amp;gt; &lt;strong&gt;Expand&lt;/strong&gt; &amp;gt; &lt;strong&gt;Add token&lt;/strong&gt;) with the following scopes: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fdeploy-token-required-push-gitlab-package-registry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fdeploy-token-required-push-gitlab-package-registry.png" alt="A Deploy Token Is Required To Push Into GitLab’s Package Registry"&gt;&lt;/a&gt; Copy the created deploy token and create another environment variable as described above. This time, the name needs to be &lt;code&gt;NPM_TOKEN&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Now, let's look at the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# required authentication https://semantic-release.gitbook.io/semantic-release/usage/ci-configuration#authentication-for-plugins&lt;/span&gt;
&lt;span class="c1"&gt;# NPM_TOKEN and GL_TOKEN provided as Gitlab environment variable&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;next&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "@doppelmutzi:registry=https://${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/" &amp;gt; .npmrc&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${NPM_TOKEN}" &amp;gt;&amp;gt; .npmrc&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm i -g semantic-release @semantic-release/gitlab @semantic-release/changelog @semantic-release/git @semantic-release/npm @semantic-release/commit-analyzer conventional-changelog-conventionalcommits&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx semantic-release --debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two &lt;code&gt;echo&lt;/code&gt; commands in the &lt;code&gt;script&lt;/code&gt; section of the &lt;code&gt;release&lt;/code&gt; step are important to dynamically create the contents for a &lt;code&gt;.npmrc&lt;/code&gt; file. With this file, &lt;code&gt;@semantic-release/npm&lt;/code&gt; can publish releases into the GitLab registry. &lt;/p&gt;

&lt;p&gt;The code above makes use of the previously created environment variable &lt;code&gt;NPM_TOKEN&lt;/code&gt; to store the authentication token in &lt;code&gt;.npmrc&lt;/code&gt;. It is considered best practice to use environment variables instead of exposing credentials in plain text. &lt;/p&gt;

&lt;p&gt;If you want to learn more about &lt;a href="https://blog.logrocket.com/advanced-package-manager-features-npm-yarn-pnpm/#accessing-private-registries" rel="noopener noreferrer"&gt;publishing packages to private registries with different package managers&lt;/a&gt;, you can consult this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tweaking the semantic-release plugins
&lt;/h2&gt;

&lt;p&gt;In the previous section, we configured the GitLab pipeline and made sure that the semantic-release script was able to make changes in the GitLab project. This section highlights how to provide a &lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/configuration" rel="noopener noreferrer"&gt;semantic&lt;/a&gt;&lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/configuration" rel="noopener noreferrer"&gt;-&lt;/a&gt;&lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/configuration" rel="noopener noreferrer"&gt;release configuration&lt;/a&gt; to tweak the provided semantic-release plugins and their interplay. &lt;/p&gt;

&lt;p&gt;In this project, we opt for a JavaScript config file (&lt;code&gt;release.config.cjs&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @type {import('semantic-release').GlobalConfig}
 */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/commit-analyzer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;angular&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;releaseRules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;breaking&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;major&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;feat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;minor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;patch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;README&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;patch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;patch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;parserOpts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;noteKeywords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BREAKING CHANGE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BREAKING CHANGES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BREAKING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/release-notes-generator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/*  
            use conventionalcommits instead of conventional-changelog-angular (default)
            to introduce new sections in changelog
        */&lt;/span&gt;
        &lt;span class="na"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;conventionalcommits&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;presetConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;feat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Features&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bug Fixes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Miscellaneous Chores&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Miscellaneous Chores&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;parserOpts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;noteKeywords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BREAKING CHANGE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BREAKING CHANGES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BREAKING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/changelog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;changelogFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CHANGELOG.md&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/git&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;package.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CHANGELOG.md&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/gitlab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this config down. The &lt;code&gt;branches&lt;/code&gt; array defines which branches the tool should be active for. semantic-release works with some conventions — the &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt; branches have special meanings. Later, we'll see that the &lt;code&gt;main&lt;/code&gt; branch releases are published on the &lt;code&gt;latest&lt;/code&gt; distribution channel and the &lt;code&gt;next&lt;/code&gt; branch on the &lt;code&gt;next&lt;/code&gt; distribution channel. Therefore, it uses &lt;a href="https://docs.npmjs.com/adding-dist-tags-to-packages" rel="noopener noreferrer"&gt;npm distribution tags&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;plugins&lt;/code&gt; array, every plugin needs to be listed with an optional configuration in case we want to differ from the shipped default. The order of the plugins is important. &lt;/p&gt;

&lt;p&gt;With the plugin &lt;code&gt;@semantic-release/commit-analyzer&lt;/code&gt;, we define which conventional commit convention to use. We’ll use the default Angular convention, but there are more options, such as ESLint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;[&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@semantic-release/commit-analyzer"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="pi"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;preset&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;angular"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;releaseRules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
      &lt;span class="pi"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;breaking&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;major"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="pi"&gt;},&lt;/span&gt;
      &lt;span class="pi"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feat"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;minor"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="pi"&gt;},&lt;/span&gt;
      &lt;span class="pi"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fix"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;patch"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="pi"&gt;},&lt;/span&gt;
      &lt;span class="pi"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docs"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;README"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;patch"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="pi"&gt;},&lt;/span&gt;
      &lt;span class="pi"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chore"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;patch"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;],&lt;/span&gt;
    &lt;span class="nv"&gt;parserOpts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;noteKeywords&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BREAKING&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CHANGE"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BREAKING&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CHANGES"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BREAKING"&lt;/span&gt;&lt;span class="pi"&gt;],&lt;/span&gt;
    &lt;span class="pi"&gt;},&lt;/span&gt;
  &lt;span class="pi"&gt;},&lt;/span&gt;
&lt;span class="pi"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can skip &lt;code&gt;releaseRules&lt;/code&gt; if we are satisfied with the &lt;a href="https://github.com/semantic-release/commit-analyzer/blob/master/lib/default-release-rules.js" rel="noopener noreferrer"&gt;default release rules&lt;/a&gt;. In this example, we want to extend the list of release types to use &lt;code&gt;chore&lt;/code&gt; and &lt;code&gt;docs&lt;/code&gt; with scope &lt;code&gt;README&lt;/code&gt; for patch releases. In addition, we want to create major releases for breaking changes. &lt;/p&gt;

&lt;p&gt;We can specify &lt;code&gt;parseOpts&lt;/code&gt; to create breaking changes whenever one of the listed variants is part of the body of the commit message. We'll look at what that means in the next section. &lt;/p&gt;

&lt;p&gt;With the plugin &lt;code&gt;@semantic-release/release-notes-generator&lt;/code&gt;, we have the chance to tweak the changelog contents. This example shows how to create three sections: &lt;strong&gt;Features, Bug Fixes&lt;/strong&gt;, and &lt;strong&gt;Miscellaneous&lt;/strong&gt;. The &lt;code&gt;hidden&lt;/code&gt; property controls whether certain release types are listed in the changelog or not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/release-notes-generator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/*  
        use conventionalcommits instead of conventional-changelog-angular (default)
        to introduce new sections in changelog
    */&lt;/span&gt;
    &lt;span class="na"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;conventionalcommits&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;presetConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;feat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Features&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bug Fixes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Miscellaneous Chores&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Miscellaneous Chores&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;parserOpts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;noteKeywords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BREAKING CHANGE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BREAKING CHANGES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BREAKING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we are satisfied with the default configurations of &lt;code&gt;@semantic-release/npm&lt;/code&gt; and &lt;code&gt;@semantic-release/gitlab&lt;/code&gt;, we just need to list them in the &lt;code&gt;plugins&lt;/code&gt; array. &lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;@semantic-release/changelog&lt;/code&gt; config, changelogs are stored in the &lt;code&gt;CHANGELOG.md&lt;/code&gt; file. The &lt;code&gt;@semantic-release/git&lt;/code&gt; config tells the plugin to pick up &lt;code&gt;CHANGELOG.md&lt;/code&gt; and &lt;code&gt;package.json&lt;/code&gt; and commit changes as we see in the next section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/changelog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;changelogFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CHANGELOG.md&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/git&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;package.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CHANGELOG.md&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing the workflow with a dry run
&lt;/h2&gt;

&lt;p&gt;Let’s shift the focus to the last line of &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;, which executes the semantic-release script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx semantic-release --debug --dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a good approach to add the &lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/configuration#dryrun" rel="noopener noreferrer"&gt;&lt;code&gt;--dry-run&lt;/code&gt;&lt;/a&gt; flag while working on the project setup. This flag doesn’t create any releases, but potential version changes or setup issues can be seen in the pipeline's output, especially with the verbose &lt;code&gt;--debug&lt;/code&gt; flag. &lt;/p&gt;

&lt;p&gt;Let's create a conventional commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat: initial CLI tool with addition functionality"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tutorial works with the &lt;a href="https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines" rel="noopener noreferrer"&gt;Angular commit conventions&lt;/a&gt;. Each commit message consists of a header, body, and footer. The most important part is the header that includes the release type (here, &lt;code&gt;feat&lt;/code&gt; for feature), an optional scope, and a subject:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&amp;lt;scope&amp;gt;&lt;span class="o"&gt;)&lt;/span&gt;: &amp;lt;subject&amp;gt;
&amp;lt;BLANK LINE&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;BLANK LINE&amp;gt;
&amp;lt;footer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later we will see an example of using a scope (&lt;code&gt;docs(RELEASE)&lt;/code&gt;) and the footer (for breaking changes). &lt;/p&gt;

&lt;p&gt;After we pushed the commit to remote, the log of the &lt;code&gt;release&lt;/code&gt; step didn't reveal any problems. It just states which release version would have been created without the &lt;code&gt;dry-run&lt;/code&gt; flag: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fdry-run-mode.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fdry-run-mode.png" alt="No Tag, Changelog, Or Npm Package Will Be Created In --Dry-Run Mode"&gt;&lt;/a&gt; We are now ready to work with our semantic-release workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  semantic-release in action
&lt;/h2&gt;

&lt;p&gt;The previous sections highlight how to set up a GitLab project to make use of semantic-release. The following section will describe how different releases on different distribution channels can be created with this setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  First release
&lt;/h3&gt;

&lt;p&gt;After a dry run didn't reveal any problems, we can make another local commit to enable semantic-release by removing the &lt;code&gt;--dry-run&lt;/code&gt; flag in &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"chore: enable semantic release by removing --dry-run option"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This constitutes our very first "working" commit that triggers a release. &lt;/p&gt;

&lt;p&gt;After pushing this commit to remote, the pipeline is triggered. Because we made a commit to the &lt;code&gt;main&lt;/code&gt; branch, which is referenced in &lt;code&gt;release.config.cjs&lt;/code&gt; as a trackable branch, a pipeline is triggered with a &lt;code&gt;release&lt;/code&gt; step. &lt;/p&gt;

&lt;p&gt;After the pipeline has succeeded, the commit graph reveals that the technical user &lt;code&gt;semantic-release-bot&lt;/code&gt; has created another commit: &lt;code&gt;chore(release): 1.0.0 [skip ci]&lt;/code&gt;. The part in the brackets is GitLab's mechanism to prevent another pipeline run: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fcommit-type-core-triggers-first-release.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fcommit-type-core-triggers-first-release.png" alt="A Commit With Type Core Triggers The First Release"&gt;&lt;/a&gt; This first release (v1.0.0) includes two conventional commits (&lt;strong&gt;feat&lt;/strong&gt; and &lt;strong&gt;chore&lt;/strong&gt;) that lead to two entries in the created changelog file (&lt;code&gt;CHANGELOG.md&lt;/code&gt;) by the plugin &lt;code&gt;@semantic-release/release-notes-generator&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In addition, the version number of &lt;code&gt;package.json&lt;/code&gt; was updated by the plugin &lt;code&gt;@semantic-release/npm&lt;/code&gt;: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Finitial-release-new-git-tag-project-home-screen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Finitial-release-new-git-tag-project-home-screen.png" alt="The Initial Release With A New Git Tag Can Be Seen On The Project's Home Screen"&gt;&lt;/a&gt; When you click on &lt;strong&gt;1 Release&lt;/strong&gt;, you see how these conventional commits were transferred to release notes by the &lt;code&gt;@semantic-release/release-notes-generator&lt;/code&gt; plugin: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ffirst-release-notes-release-notes-generator.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ffirst-release-notes-release-notes-generator.png" alt="First Release Notes Created By Semantic-Release's Release-Notes-Generator"&gt;&lt;/a&gt; The technical commit &lt;code&gt;chore(release): 1.0.0 [skip ci]&lt;/code&gt; reveals what was changed by &lt;code&gt;@semantic-release/git&lt;/code&gt; in conjunction with &lt;code&gt;@semantic-release/npm&lt;/code&gt; : &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Frelease-related-changes-chorerelease-commit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Frelease-related-changes-chorerelease-commit.png" alt="The Release-Related Changes By The Chore(Release) Commit Of Semantic-Release-Bot"&gt;&lt;/a&gt; Because we want to publish an npm package in GitLab's registry, a technical commit with an updated &lt;code&gt;package.json&lt;/code&gt; represents the desired behavior. &lt;/p&gt;

&lt;p&gt;If you have a project where you don't publish an npm package, you can also &lt;a href="https://semantic-release.gitbook.io/semantic-release/support/faq#why-is-the-package.jsons-version-not-updated-in-my-repository" rel="noopener noreferrer"&gt;prevent publishing to an npm registry&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;As we see in the next image, the &lt;code&gt;@semantic-release/npm&lt;/code&gt; plugin published v1.0.0 with the &lt;code&gt;latest&lt;/code&gt; dist-tag: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ffirst-published-package-latest-label.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ffirst-published-package-latest-label.png" alt="The First Published Package Gets The Latest Label"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing the published package
&lt;/h3&gt;

&lt;p&gt;Let's take a short excursion to use the released package. We need to provide an npm registry config to get access to GitLab's package registry. One approach is to store a &lt;code&gt;.npmrc&lt;/code&gt; file in your home folder like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.npmrc&lt;/span&gt;
@doppelmutzi:registry&lt;span class="o"&gt;=&lt;/span&gt;https://gitlab.com/api/v4/projects/&amp;lt;project-id&amp;gt;/packages/npm/
//gitlab.com/api/v4/projects/&amp;lt;project-id&amp;gt;/packages/npm/:_authToken&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;NPM_TOKEN&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;NPM_TOKEN&lt;/code&gt; is the value of the deploy token we stored in GitLab's environment variable. The project ID can be retrieved from the project's home screen: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fproject-id-home-screen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fproject-id-home-screen.png" alt="Find Out The Project ID From Project's Home Screen"&gt;&lt;/a&gt; Then, the following Shell command is all it needs to execute the executable &lt;code&gt;doppelmutzi-addition&lt;/code&gt; of the latest version of the package &lt;code&gt;@doppelmutzi/semantic-release-git-workflow&lt;/code&gt; stored in the private registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx @doppelmutzi/semantic-release-git-workflow@latest doppelmutzi-addition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating more releases
&lt;/h3&gt;

&lt;p&gt;Next, we’ll update the &lt;code&gt;README.md&lt;/code&gt; with some information on how to use the CLI tool and create the following commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"docs(README): how to use the CLI tool"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It uses the type &lt;code&gt;docs&lt;/code&gt; with the single &lt;code&gt;scope&lt;/code&gt; we configured to trigger a patch release. Here is the important part of the configuration of &lt;code&gt;@semantic-release/commit-analyzer&lt;/code&gt; in &lt;code&gt;release.config.cjs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/commit-analyzer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;angular&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;releaseRules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;README&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;patch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Due to this setup, the previous commit triggers a release with version 1.0.1: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Frelease-v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Frelease-v1.png" alt="Release Version 1.0.1"&gt;&lt;/a&gt; The Git history should look like this: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fgit-history-after-release-version-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fgit-history-after-release-version-1.png" alt="Git History After Release Version1.0.1"&gt;&lt;/a&gt; In the package registry, there is a new package with version 1.0.1, which has the &lt;code&gt;latest&lt;/code&gt; dist-tag. Executing the previous &lt;code&gt;npx&lt;/code&gt; Shell command will now execute this package version: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fpackage-v1-latest-dist-tag-published.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fpackage-v1-latest-dist-tag-published.png" alt="Package V1.0.1 With Latest Dist-Tag Was Published"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with the &lt;code&gt;@next&lt;/code&gt; distribution tag
&lt;/h3&gt;

&lt;p&gt;Let's work on a new feature that allows us to perform subtractions. We want to test this with a smaller group of users so we’ll develop this in the &lt;code&gt;next&lt;/code&gt; branch. &lt;/p&gt;

&lt;p&gt;With the following commit, a package with version 1.1.0 and a &lt;code&gt;@next&lt;/code&gt; distribution tag is published:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat: allow subtraction"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fpackages-developed-next-branch-next-dist-tag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fpackages-developed-next-branch-next-dist-tag.png" alt="Packages Developed On The Next Branch Get The Next Dist-Tag"&gt;&lt;/a&gt; This works because the &lt;code&gt;next&lt;/code&gt; branch is configured as a trackable branch in &lt;code&gt;release.config.cjs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this is what the Git history looks like: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fcommit-type-feat-version-1-next-branch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fcommit-type-feat-version-1-next-branch.png" alt="A Commit With Type Feat Leads To 1.1.0 On The Next Branch"&gt;&lt;/a&gt; Users can use this package like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx @doppelmutzi/semantic-release-git-workflow@next doppelmutzi-calculator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While users are testing the new feature on the &lt;code&gt;next&lt;/code&gt; branch, we’ll find a general problem with the calculator. The command cannot handle empty spaces and multiple operands. We can fix this on the &lt;code&gt;main&lt;/code&gt; branch and create a commit with type &lt;code&gt;fix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix: command accepts whitespaces and unlimited numbers can be added"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This leads to version 1.0.2 with a &lt;code&gt;latest&lt;/code&gt; tag: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fcommit-type-fix-main-branch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fcommit-type-fix-main-branch.png" alt="A Commit With Type Fix On The Main Branch Leads To 1.0.2"&gt;&lt;/a&gt; The Git history reveals two branches with v1.0.2 on &lt;code&gt;main&lt;/code&gt; and v1.1.0 on &lt;code&gt;next&lt;/code&gt;: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnew-release-latest-dist-tag-available.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnew-release-latest-dist-tag-available.png" alt="A New Release With The Latest Dist-Tag Is Available"&gt;&lt;/a&gt; Let's port this bugfix to the &lt;code&gt;next&lt;/code&gt; branch by merging the &lt;code&gt;main&lt;/code&gt; branch into the &lt;code&gt;next&lt;/code&gt; branch. After resolving the merge conflicts, we get the version 1.1.1 with the &lt;code&gt;next&lt;/code&gt; distribution tag: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnew-version-available-next-dist-tag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnew-version-available-next-dist-tag.png" alt="Version 1.1.1 Is Available On @Next Dist-Tag"&gt;&lt;/a&gt; A Git tag v1.1.1 is created on the &lt;code&gt;next&lt;/code&gt; branch after merging the main branch into it: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fgit-tag-created-next-branch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fgit-tag-created-next-branch.png" alt="A Git Tag Version 1.1.1 Is Created On Next Branch After Merging The Main Branch Into It"&gt;&lt;/a&gt; We are satisfied with our &lt;code&gt;next&lt;/code&gt; version and want to port it back to &lt;code&gt;latest&lt;/code&gt;. Therefore, we’ll merge the &lt;code&gt;next&lt;/code&gt; branch into &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling breaking changes
&lt;/h3&gt;

&lt;p&gt;During development, it became clear that our application requires a newer Node version as a minimum requirement. This is a breaking change as the application no longer works with Node &amp;lt;18.19.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"chore: upgrade engines field &lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt; BREAKING CHANGE: the CLI tool only works with Node 18.19.0 or greater"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the Angular conventions, it's important for this type of commit that &lt;code&gt;BREAKING CHANGE&lt;/code&gt; be in the body of the commit, so the two line breaks are crucial. This commit leads to a major version bump (2.0.0): &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fbreaking-changes-lead-major-version-bumps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fbreaking-changes-lead-major-version-bumps.png" alt="Breaking Changes Lead To Major Version Bumps"&gt;&lt;/a&gt; The newest version on the &lt;code&gt;latest&lt;/code&gt; distribution tag is now 2.0.0: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnewest-version-latest-dist-tag-now-version-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnewest-version-latest-dist-tag-now-version-2.png" alt="The Newest Version On Latest Dist-Tag Is Now 2.0.0"&gt;&lt;/a&gt; This is how the Git history looks after the breaking change: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fgit-history-after-major-version-bump.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fgit-history-after-major-version-bump.png" alt="Git History After Major Version Bump"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with merge requests
&lt;/h2&gt;

&lt;p&gt;Let's use another approach to develop a new release. We want to develop a complex feature containing many commits, so we’ll provide a CLI option to our script. &lt;/p&gt;

&lt;p&gt;We’ll branch off a new branch from &lt;code&gt;main&lt;/code&gt; named &lt;code&gt;feature/cli-option&lt;/code&gt;. The advantage of this approach is that we can build the feature with multiple commits that do not have to use the conventional commit convention. &lt;/p&gt;

&lt;p&gt;After we're done developing, we’ll create a merge request with the &lt;code&gt;squash commits&lt;/code&gt; and &lt;code&gt;edit commit message&lt;/code&gt; options to provide custom messages. In the squash commit message, we again have the chance to use the Angular convention to make sure that we create one commit of type &lt;code&gt;feat&lt;/code&gt;: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fsquash-commit-uses-conventional-commit-convention.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fsquash-commit-uses-conventional-commit-convention.png" alt="The Squash Commit Uses The Conventional Commit Convention"&gt;&lt;/a&gt; After merging the merge request, a new release v2.1.0 is created with the &lt;code&gt;latest&lt;/code&gt; distribution tag: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fmerged-mr-leads-version-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fmerged-mr-leads-version-2.png" alt="The Merged MR Leads To A Version 2.1.0"&gt;&lt;/a&gt; The final Git history also shows that the final commit leads to a Git tag of v2.1.0: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ffinal-commit-leads-version-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ffinal-commit-leads-version-2.png" alt="The Final Commit Leads To Version 2.1.0"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The focus of this article is to demonstrate how to achieve a semantic-release workflow with GitLab to automate releases and changelog generation. Of course, semantic-release can be used with other popular &lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/ci-configuration" rel="noopener noreferrer"&gt;CI services&lt;/a&gt;, such as GitHub Actions. Most of the shown configurations will be the same — the only difference is to set up authentication for the respective service. &lt;/p&gt;

&lt;p&gt;The semantic-release workflow is very flexible, e.g., you can choose a &lt;a href="https://github.com/semantic-release/release-notes-generator#options" rel="noopener noreferrer"&gt;conventional commit convention&lt;/a&gt; other than Angular, such as Atom or ESLint. &lt;/p&gt;

&lt;p&gt;If you want to have a more rigorous workflow that allows only conventional commits, you can think about using Git pre-commit hooks with &lt;a href="https://commitlint.js.org/#/" rel="noopener noreferrer"&gt;commitlint&lt;/a&gt;. A &lt;a href="https://theodorusclarence.com/shorts/husky-commitlint-prettier" rel="noopener noreferrer"&gt;setup with lint-staged, husky, and commitlint&lt;/a&gt; would also minimize the chance that developers push inadequate commit messages to remote, which would lead to undesirable results.&lt;/p&gt;




&lt;h2&gt;
  
  
  200’s only  Monitor failed and slow network requests in production
&lt;/h2&gt;

&lt;p&gt;Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, &lt;a href="https://lp.logrocket.com/blg/node-signup" rel="noopener noreferrer"&gt;try LogRocket&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/node-signup" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhvtumu4p97lxlreb8mkd.png" alt="LogRocket Signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/node-signup" rel="noopener noreferrer"&gt;LogRocket&lt;/a&gt; is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.&lt;/p&gt;

&lt;p&gt;LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. &lt;a href="https://lp.logrocket.com/blg/node-signup" rel="noopener noreferrer"&gt;Start monitoring for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>D3.js adoption guide: Overview, examples, and alternatives</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Thu, 25 Jan 2024 16:09:21 +0000</pubDate>
      <link>https://dev.to/logrocket/d3js-adoption-guide-overview-examples-and-alternatives-4dj2</link>
      <guid>https://dev.to/logrocket/d3js-adoption-guide-overview-examples-and-alternatives-4dj2</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/ezesunday/" rel="noopener noreferrer"&gt;Eze Sunday&lt;br&gt;
&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;D3.js is a JavaScript library that allows you to create tailored data visualizations. While most tutorial examples use charts to illustrate its usage, D3.js is a lot more powerful than a traditional charting library. It allows you to create highly custom, flexible data visualizations in many different formats. &lt;/p&gt;

&lt;p&gt;In this guide, our goal is to give you all the information you need to convince your team to use D3.js or determine whether an alternative might better suit your needs. If you are considering D3.js for your project, let’s get into the details so you can make your final decision.&lt;/p&gt;


&lt;h2&gt;
  
  
  Background and history of D3.js
&lt;/h2&gt;

&lt;p&gt;D3.js originated from Protovis, a declarative JavaScript graphical data visualization library that was created by Mike Bostock and Jeff Heer of the Stanford Visualization Group, with significant help from Vadim Ogievetsky. &lt;/p&gt;

&lt;p&gt;Protovis was first released in April 2009 and was &lt;a href="http://vis.stanford.edu/files/2011-D3-InfoVis.pdf" rel="noopener noreferrer"&gt;discontinued after its final v3.3.1&lt;/a&gt; on June 28, 2011. D3.js was invented by the same team and built on many of the concepts of Protovis, making a big leap forward from Protovis with improved support for animation, interactions, and flexibility.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why use D3.js?
&lt;/h2&gt;

&lt;p&gt;There are several data visualization libraries in the JavaScript ecosystem. However, D3.js has been at the forefront for several years. Not only this, but D3.js is also the underlying library behind many other available data visualization libraries. &lt;/p&gt;

&lt;p&gt;Some of the reasons why I typically prefer D3.js over other data visualization libraries include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Flexibility:&lt;/strong&gt; D3.js makes it possible to create high-level tailored visualizations for your specific needs. This type of flexibility is one you can’t really get from other libraries. It gives you the power to create whatever visualization you desire&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Scalability&lt;/strong&gt;: D3.js is designed to be scalable. In the past, browser limitations caused performance to become an issue for projects with massive data in the billions. But today, that is no longer an issue — we can leverage server-side rendering to transfer data-intensive visualizations to the server. This should make D3.js suitable for large datasets and complex visualization at scale&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Customizability&lt;/strong&gt;: Every aspect of the data visualizations you create with D3.js will likely involve writing the code yourself, giving you full control over how it looks and behaves. It’s the type of data visualization library you’ll want to use when you need to create a specific kind of visualization that describes your data in the best way possible, tailored to your own needs&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Active&lt;/strong&gt; &lt;strong&gt;community&lt;/strong&gt;: D3.js has an active developer community with over &lt;a href="https://github.com/d3/d3/stargazers" rel="noopener noreferrer"&gt;107k GitHub stars&lt;/a&gt; and regular updates to their GitHub repository. This is something I always look out for when choosing a library for my project, as a well-maintained project with an active community is likely to provide a high level of support&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Framework agnostic&lt;/strong&gt;: A lot of other data visualization libraries are tailored to a particular JavaScript library or framework. For example, &lt;a href="https://formidable.com/open-source/victory/" rel="noopener noreferrer"&gt;Victory&lt;/a&gt; and &lt;a href="https://airbnb.io/visx/" rel="noopener noreferrer"&gt;Visx&lt;/a&gt; are visualization libraries designed to work with React only. However, D3.js can be implemented for any framework at all&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While I admire D3.js, I think it’s also fair to mention that it’s not a perfect library. It also has some cons, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Steep learning curve&lt;/strong&gt;: Since you get to build every part of the visualisation from the ground up, you need a reasonable grasp of the fundamentals of D3, SVG, HTML, and CSS. Otherwise, it might take much longer to get what you need done&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Not ideal for basic chart visualization&lt;/strong&gt;: If you only need to create simple charts for basic data exploration, D3.js might be overkill. Other libraries offer simpler solutions for these cases&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Lack of prebuilt templates&lt;/strong&gt;: Unlike a lot of other visualization libraries, D3.js does not have prebuilt templates, like charts that allow you to just feed them some data. Keep in mind that there is &lt;a href="https://github.com/wbkd/awesome-d3" rel="noopener noreferrer"&gt;a long list of charting libraries and tools&lt;/a&gt; that leverage D3.js to enable you to build visualizations a lot faster without worrying about the low-level D3.js details&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  &lt;em&gt;Further reading:&lt;/em&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/data-visualization-angular-d3-js/" rel="noopener noreferrer"&gt;Data visualization in Angular using D3.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/data-visualization-d3-js-node-js/" rel="noopener noreferrer"&gt;Data visualization with D3.js and Node.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/data-visualization-vue-js-d3/" rel="noopener noreferrer"&gt;Data visualization with Vue.js and D3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/data-visualization-svelte-d3/" rel="noopener noreferrer"&gt;Data visualization with Svelte and D3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/using-d3-js-v6-with-react/" rel="noopener noreferrer"&gt;Using D3.js v6 with React&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  How D3.js works
&lt;/h2&gt;

&lt;p&gt;Now that we’ve gone over the background, benefits, and drawbacks of D3.js, let’s explore how it works. &lt;/p&gt;

&lt;p&gt;D3.js takes both the data to be visualized and the graphics you want to use for the visualization and binds them to the DOM in a flexible way, allowing you to manipulate, add, or update your data easily. This makes it possible for you to build very complex visualizations customized to your needs. &lt;/p&gt;

&lt;p&gt;For example, the code below will render a simple bar chart in the browser. You can easily copy and paste it into your code editor to test it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"simple-chart"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.jsdelivr.net/npm/d3@7/+esm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Set chart dimensions.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Sample data.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;// Create SVG container.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Create bars for each data point.&lt;/span&gt;
&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;y&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;steelblue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;chartContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;simple-chart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Append SVG to the chart container.&lt;/span&gt;
&lt;span class="nx"&gt;chartContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above will render the following bar chart: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2FSimple-bar-chart-D3-js.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2FSimple-bar-chart-D3-js.png" alt="Demo Of A Simple Bar Chart Created Using D3 Js"&gt;&lt;/a&gt; Let’s break down a few notable parts of the code block above. One thing you’ll notice is that every part of the bar chart is drawn on top of an &lt;code&gt;svg&lt;/code&gt; container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because SVG makes it a lot easier to draw shapes. For example, a &lt;code&gt;rect&lt;/code&gt; is a built-in SVG element that defines a rectangle shape. &lt;/p&gt;

&lt;p&gt;We selected all existing &lt;code&gt;rect&lt;/code&gt; elements — and made sure to create a new &lt;code&gt;rect&lt;/code&gt; for each data element if it didn’t already exist — with the help of the &lt;code&gt;enter()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;svg.selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("x", (d, i) =&amp;gt; i * 60)
    .attr("y", d =&amp;gt; height - d)
    .attr("width", 50)
    .attr("height", d =&amp;gt; d)
    .attr("fill", "steelblue");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we append the SVG we created to the D3 object, as shown in this part of the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"simple-chart"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
let chartContainer = document.getElementById("simple-chart");
// Append SVG to the chart container.
chartContainer.append(svg.node());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just the tip of the iceberg for what you can do with D3.js. To get a better sense of this library’s capabilities, let’s look at some of its standout features.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Further reading:&lt;/em&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/creating-visualizations-d3-typescript/" rel="noopener noreferrer"&gt;Creating visualizations with D3 and TypeScript&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key D3.js features to know
&lt;/h2&gt;

&lt;p&gt;Digging deep into the D3.js documentation is the recommended way to gain in-depth knowledge of the tool. However, if you’re looking to evaluate the functionalities and start practicing immediately, here are some key features to look out for.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visualization tools
&lt;/h3&gt;

&lt;p&gt;D3.js gives you the tools to create any kind of data visualization you can imagine by leveraging your skills in D3.js, JavaScript, HTML, and CSS. &lt;/p&gt;

&lt;p&gt;You can create graphs, charts, scatter plots, and several other types of visuals. It’s also possible to combine D3.js with other graphics libraries like Three.js to build even more amazing graphics. For example, here is an example of a &lt;a href="https://communities.sas.com/t5/image/serverpage/image-id/30598i89143063E3131CDA/image-size/large?v=v2&amp;amp;px=999" rel="noopener noreferrer"&gt;3D globe created with D3.js and Three.js&lt;/a&gt;: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2FDemo-3D-globe-D3-js.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2FDemo-3D-globe-D3-js.gif" alt="Demo Showing A 3D Globe Created Using D3 Js"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Further reading:&lt;/em&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/build-interactive-charts-flask-d3js/" rel="noopener noreferrer"&gt;Build interactive charts with Flask and D3.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/best-heatmap-libraries-react/#d3-js" rel="noopener noreferrer"&gt;Best heatmap libraries for React (with demos) #D3.js: The advanced option&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Selecting elements
&lt;/h3&gt;

&lt;p&gt;D3.js allows you to select HTML elements with the &lt;code&gt;select&lt;/code&gt; and &lt;code&gt;selectAll&lt;/code&gt; methods as shown in our initial example. These methods can be used like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//or&lt;/span&gt;

&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above snippet, &lt;code&gt;d3.select&lt;/code&gt; allows you to select the first matching &lt;code&gt;rect&lt;/code&gt; element. Meanwhile, &lt;code&gt;d3.selectAll&lt;/code&gt; selects all matching &lt;code&gt;rect&lt;/code&gt; elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  DOM manipulation
&lt;/h3&gt;

&lt;p&gt;D3.js allows you to leverage JavaScript and CSS to manipulate the DOM to achieve your desired visualization result. You can directly create, update, and delete elements based on data or your project requirements. &lt;/p&gt;

&lt;p&gt;For example, you could use &lt;code&gt;append&lt;/code&gt; to add new elements, &lt;code&gt;remove&lt;/code&gt; to delete, and &lt;code&gt;attr&lt;/code&gt; to set attributes, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;// Select the body element
var bodySelection = d3.select("body");

// Append a paragraph
bodySelection.append("p")
  .text("This is a new paragraph.");

// Wait for 2 seconds and then remove the paragraph
setTimeout(function() {
  bodySelection.select("p").remove();
}, 2000);

// Append a div with a class and style
bodySelection.append("div")
  .attr("class", "my-div")
  .style("width", "100px")
  .style("height", "100px")
  .style("background-color", "lightblue")
  .text("I'm a div with attributes!");

// Wait for 2 seconds and then change the text content
setTimeout(function() {
  bodySelection.select(".my-div").text("Text updated!");
}, 4000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Data joining
&lt;/h3&gt;

&lt;p&gt;Data joining in D3.js is about connecting your data to the visual elements you're creating. &lt;/p&gt;

&lt;p&gt;In a previous example, we used &lt;code&gt;selectAll()&lt;/code&gt; to select all the &lt;code&gt;rect&lt;/code&gt; elements — even though they did not yet exist — and then loaded data to the &lt;code&gt;rect&lt;/code&gt;. We then used &lt;code&gt;enter&lt;/code&gt; and &lt;code&gt;append&lt;/code&gt; to join the data to each rectangle. That’s exactly what data joining is. &lt;/p&gt;

&lt;p&gt;In the below example, we’re joining data to selected rectangles directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;svg.selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a lot of other methods like this that you can find in &lt;a href="https://d3js.org/getting-started" rel="noopener noreferrer"&gt;the D3.js documentation&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use cases for D3.js
&lt;/h2&gt;

&lt;p&gt;There are several use cases for D3.js, but let’s highlight three key use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Real-time data visualization&lt;/strong&gt;: Picture a scenario where you want to display real-time updates with dynamic charts and graphs that adjust as new data arrives. That’s a perfect candidate for D3.js, as this library plays nicely with dynamic data and interactivity&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Interactive charts and graphs&lt;/strong&gt;: If you are looking to create tailored, dynamic, and interactive charts for data presentation on websites, D3.js is a great JavaScript library for that sort of thing&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Geospatial data visualization&lt;/strong&gt;: D3.js allows you to show geographical data visually, like interactive maps or choropleth maps. The &lt;a href="https://geojson.io/#map=2/8.37/17.47" rel="noopener noreferrer"&gt;image below&lt;/a&gt; is an example of an interactive map that can be built with D3.js:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2FInteractive-map-D3-js.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2FInteractive-map-D3-js.gif" alt="Demo Of An Interactive Map Created Using D3 Js"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;These are some of the most common use cases for D3.js, but since the library allows you to create completely custom data visualizations, the only limit is your imagination!&lt;/p&gt;




&lt;h2&gt;
  
  
  Styling and animating D3.js
&lt;/h2&gt;

&lt;p&gt;D3.js allows you to use native CSS to style your data visualizations. It provides a styling method that allows you to pass conventional CSS styles to your visualizations as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"map"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/d3@7"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#map&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;circle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;circle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;style&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;style&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stroke&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;style&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stroke-width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we used the providing styling method to change the color of the SVG &lt;code&gt;stroke&lt;/code&gt; to &lt;code&gt;white&lt;/code&gt;, paint each circle’s background with a &lt;code&gt;blue&lt;/code&gt; hue, and add a &lt;code&gt;stroke-width&lt;/code&gt; of &lt;code&gt;2&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;You can also choose to write your styles in the &lt;code&gt;style&lt;/code&gt; tag or in a different CSS file. For example, here is the same code, but with the CSS file separated in the &lt;code&gt;style&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nc"&gt;.svg-elements&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="py"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="py"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="py"&gt;stroke-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;#map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* Adjust the width as needed */&lt;/span&gt;
      &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* Adjust the height as needed */&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"map"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.jsdelivr.net/npm/d3@7/+esm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Create an SVG element&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#map&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Add circles to the SVG&lt;/span&gt;
    &lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;circle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;// example data, replace with your own&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;circle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Apply the class to style the circles&lt;/span&gt;
    &lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;circle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;classed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svg-elements&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will look like so: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ffinal-web-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Ffinal-web-app.png" alt="Final Web App"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Deploying your D3.js project
&lt;/h2&gt;

&lt;p&gt;D3 project deployment is straightforward. Just run your normal library or framework bundler and it will be bundled together! &lt;/p&gt;

&lt;p&gt;You don’t need to do anything special to make D3.js work, since D3.js code is just JavaScript, HTML, and CSS. So, you’ll deploy it together with your existing project without any additional requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  Other factors to weigh when considering D3.js
&lt;/h2&gt;

&lt;p&gt;We’ve learned a lot about D3.js already, but there are a few additional considerations you should keep in mind while deciding whether or not to adopt this library into your project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Performance&lt;/strong&gt;: Even though D3.js was optimized to handle large datasets, the browser might not be able to handle extreme amounts of data. As we mentioned earlier, you might want to offload some of the data processing to the backend and render your visualization in batches with aggregations&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;DX/Ease of use&lt;/strong&gt;: D3.js is straightforward for very simple visualizations, but for more complex needs, you’ll need a better understanding of the D3.js library. If all you need is a simple charting library, you may be better off using libraries that provide templates where you can simply supply the required data to generate your charts. On the other hand, D3.js is an excellent tool for creating highly custom data visualizations, in which case the trouble of learning the fundamentals and practicing using this library tends to pay off in the long run&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Bundle size&lt;/strong&gt;: The &lt;a href="https://www.npmjs.com/package/d3" rel="noopener noreferrer"&gt;D3.js library file size&lt;/a&gt; is about 873kB as of the time of this writing. It’s also tree-shakable, which means it will include only the code required by your application to work effectively in your production bundle, so you won’t end up with an over-bloated build&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Documentation&lt;/strong&gt;: One of the best things about D3.js documentation is that it has lots of examples. For almost every concept, there is a theoretical explanation along with an example to show you exactly how it works, from basic examples to more complex ones&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Supported data sources&lt;/strong&gt;: D3.js supports many data sources, including JSON, CSV, GeoJSON, HTML table data, and JavaScript arrays and objects. This allows you to load your data in almost any format you want to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are special methods that allow you to load your data into D3.js for different data sources. Let’s see some of the methods for popular data sources like CSV, JSON, arrays and objects, tabular HTML data, and GeoJSON. &lt;/p&gt;

&lt;p&gt;CSV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your_data.csv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Process csv data here&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your_data.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Arrays/objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;// Or&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;key2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tabular data in HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;table tr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GeoJSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your_geojson_data.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geoData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geoData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  D3.js vs. similar libraries
&lt;/h2&gt;

&lt;p&gt;There are lots of libraries that allow you to create data visualizations, but none currently beats the flexibility and depth of D3.js. We’ve compared the top charting libraries— including D3 — in previous posts on the LogRocket blog, which you can peruse under “Further reading” below. &lt;/p&gt;

&lt;p&gt;It’s important to acknowledge that D3.js has taken a huge market share in the data visualization space. A lot of other similar options actually use D3.js behind the scenes. Those that don’t use D3.js under the hood also don’t give you the type of flexibility that D3.js provides.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Further reading:&lt;/em&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/top-javascript-data-visualization-libraries-2021/" rel="noopener noreferrer"&gt;Top JavaScript data visualization libraries&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/top-8-react-chart-libraries/" rel="noopener noreferrer"&gt;The top 8 React chart libraries&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/comparing-most-popular-javascript-charting-libraries/" rel="noopener noreferrer"&gt;Comparing the most popular JavaScript charting libraries&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;D3.js is an amazing JavaScript data visualization library designed for highly performant, tailored visualizations. It’s the type of visualization library you want to use when you want to visualize your data in very custom ways or to meet particular project requirements. &lt;/p&gt;

&lt;p&gt;While D3.js is a great choice for many use cases, sometimes, you might just want to create simple charts and graphs. In such cases, you might want to use simpler data visualization options or tools that allow you to leverage D3.js without worrying about the low-level details. &lt;/p&gt;

&lt;p&gt;Make sure you weigh all your project requirements to determine whether D3.js is appropriate for your needs. Feel free to comment below with questions or to share your D3.js projects. Happy visualizing!&lt;/p&gt;




&lt;h2&gt;
  
  
  Get set up with LogRocket's modern error tracking in minutes:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://logrocket.com/signup/" rel="noopener noreferrer"&gt;https://logrocket.com/signup/&lt;/a&gt; to get an app ID.&lt;/li&gt;
&lt;li&gt;Install LogRocket via NPM or script tag. &lt;code&gt;LogRocket.init()&lt;/code&gt; must be called client-side, not server-side.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save&lt;/span&gt; logrocket 

// Code:

import LogRocket from &lt;span class="s1"&gt;'logrocket'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
LogRocket.init&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app/id'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Script Tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.lr-ingest.com/LogRocket.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.(Optional) Install plugins for deeper integrations with your stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Redux middleware&lt;/li&gt;
&lt;li&gt;  ngrx middleware&lt;/li&gt;
&lt;li&gt;  Vuex plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/signup" rel="noopener noreferrer"&gt;Get started now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Exploring Effect, a meta-state RxJS-like framework</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Wed, 24 Jan 2024 16:14:54 +0000</pubDate>
      <link>https://dev.to/logrocket/exploring-effect-a-meta-state-rxjs-like-framework-3b9</link>
      <guid>https://dev.to/logrocket/exploring-effect-a-meta-state-rxjs-like-framework-3b9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/isaacjunior/" rel="noopener noreferrer"&gt;Isaac Okoro&lt;br&gt;
&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While TypeScript does a great job of &lt;a href="https://blog.logrocket.com/using-strongly-typed-vs-statically-typed-code/" rel="noopener noreferrer"&gt;statically typing JavaScript code&lt;/a&gt;, certain drawbacks might arise. These drawbacks can include managing the complex nature of asynchronous code, handling types in asynchronous scenarios, and error handling. The Effect library was created as a way to address these drawbacks. &lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll get to know Effect, how it works, and why you may benefit from using it. We’ll also compare it to &lt;a href="https://blog.logrocket.com/tag/rxjs/" rel="noopener noreferrer"&gt;RxJS, a JavaScript library for reactive programming&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Effect?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.effect.website/" rel="noopener noreferrer"&gt;Effect is a functional library&lt;/a&gt; for building and composing asynchronous, concurrent, and reactive programs in TypeScript. It focuses on providing a robust and type-safe way to manage side effects in your programs. &lt;/p&gt;

&lt;p&gt;A great use case for Effect is building a streaming platform. Ideally, you want to fetch and display recommended content and real-time updates concurrently. &lt;/p&gt;

&lt;p&gt;With Effect's async support, you can initiate these tasks without blocking the main thread. This ensures a smooth streaming experience for users while the app handles various asynchronous operations in the background. &lt;/p&gt;

&lt;p&gt;The reactive nature of Effect allows you to respond dynamically to events, like new content availability or user interactions, making the streaming platform more responsive and interactive. &lt;/p&gt;

&lt;p&gt;Effect helps you structure your code in a way that makes it easier to handle async operations, concurrency, and reactivity while maintaining type safety. It's particularly useful for developers who want to apply functional programming techniques to build reliable and maintainable software in TypeScript.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why use Effect?
&lt;/h2&gt;

&lt;p&gt;The team behind Effect created this library as an ecosystem of tools that enable you to write TypeScript code in a better and more functional way. You can use Effect to build software in a purely functional manner. &lt;/p&gt;

&lt;p&gt;However, Effect’s core function — probably its most unique function — is to provide you with a way to use the type system to track errors and the context of your application. It does this with the help of the &lt;code&gt;Effect&lt;/code&gt; type, which is at the core of the Effect ecosystem. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Effect&lt;/code&gt; type allows you to express the potential dependencies that your code will run on, as well as to track errors explicitly. You can check out an example of the &lt;code&gt;Effect&lt;/code&gt; type in the code block below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Requirements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Requirements&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Effect&lt;/code&gt; type takes in three parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;Requirements&lt;/code&gt;&lt;/strong&gt;: The data to be executed by the effect, which is stored in a &lt;code&gt;Context&lt;/code&gt; collection. You can also pass in &lt;code&gt;never&lt;/code&gt; as the type parameter if the effect has no requirements&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;Error&lt;/code&gt;&lt;/strong&gt;: Any errors that might occur during execution. You can also choose to pass in &lt;code&gt;never&lt;/code&gt; to indicate that the effect will never fail&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;Value&lt;/code&gt;&lt;/strong&gt;: This represents the success value of an effect. You can pass &lt;code&gt;void&lt;/code&gt;, &lt;code&gt;never&lt;/code&gt;, or the exact value type you are expecting here. If you pass in &lt;code&gt;void&lt;/code&gt;, then the success value has no useful information. If you pass in &lt;code&gt;never&lt;/code&gt;, then the effect runs forever&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is an example of an &lt;code&gt;Effect&lt;/code&gt; type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cannot divide by zero&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code block above, we have a division function that subscribes to the &lt;code&gt;Effect&lt;/code&gt; pattern. &lt;/p&gt;

&lt;p&gt;We passed &lt;code&gt;never&lt;/code&gt; in the &lt;code&gt;Requirements&lt;/code&gt; parameter, a type &lt;code&gt;Error&lt;/code&gt; in the &lt;code&gt;Error&lt;/code&gt; parameter, and a type &lt;code&gt;number&lt;/code&gt; in the &lt;code&gt;Value&lt;/code&gt; parameter. This means this &lt;code&gt;Effect&lt;/code&gt; takes in no requirements, might fail with an error of type &lt;code&gt;Error&lt;/code&gt; if the second number is zero, and succeeds with a success value of type &lt;code&gt;number&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;When writing TypeScript, we always assume that a function will either succeed or fail. In the case of a failure, we can throw an exception to handle error conditions. &lt;/p&gt;

&lt;p&gt;However, what then happens when we are writing code, but we forget to use a &lt;code&gt;try...catch&lt;/code&gt; block or throw an exception? Take a look at the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fetch someething from a random API&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parseResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dataSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parseResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example makes a &lt;code&gt;fetch&lt;/code&gt; request to an API, makes sure that the response is in &lt;code&gt;JSON&lt;/code&gt;, and then returns it. The problem with the above code is that each line could crash separately and throw a different error that you may choose to handle differently. &lt;/p&gt;

&lt;p&gt;So, how do we fix the above code using the Effect library? Let’s see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pipe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;effect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tryPromise&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fetch something from a random API&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fetch returned an error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;

    &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tryPromise&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JSON parse cant be trusted also😭&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;dataSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This error is from the data schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above is similar to the example we first discussed. However, this time around, we are taking note of each point where our code might potentially fail and handling each error separately. &lt;/p&gt;

&lt;p&gt;This code shows a real-life example of how to use Effect. If you take a look at the code block without the &lt;code&gt;Effect&lt;/code&gt; type, we see that the function handles three operations: data fetching, JSON parsing, and &lt;code&gt;dataSchema&lt;/code&gt; parsing. &lt;/p&gt;

&lt;p&gt;In the example with Effect, we created the type &lt;code&gt;Effect&amp;lt;never, Error, Data&amp;gt;&lt;/code&gt; in line three. Now, if you have different error handlers for each specific operation, then you can rewrite the &lt;code&gt;Effect&lt;/code&gt; to use those error handlers as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FetchError&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;JSONError&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;DataSchemaError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that done, when the &lt;code&gt;getData&lt;/code&gt; function runs, you have a specific idea of which of the operations failed and why. You also know that if the &lt;code&gt;getData&lt;/code&gt; function passes, it passes with type &lt;code&gt;Data&lt;/code&gt;, which you defined above. &lt;/p&gt;

&lt;p&gt;Admittedly, the above solution is more verbose than, say, using a &lt;code&gt;try...catch&lt;/code&gt; block to wrap the entire function and throw an exception. Even so, Effect ensures that each error is specifically handled, making your code easier to debug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features of Effect
&lt;/h2&gt;

&lt;p&gt;So far, we’ve seen how to use the Effect library to build and compose purely functional programs in TypeScript. Now, let’s look at some of its standout features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Concurrency&lt;/strong&gt;: Effect offers facilities for concurrent programming through the &lt;a href="https://www.effect.website/docs/concurrency/fibers" rel="noopener noreferrer"&gt;use of fibers&lt;/a&gt;, which are lightweight threads of execution that we can schedule independently, enabling efficient and scalable concurrency&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Error handling&lt;/strong&gt;: Effect implements a robust error-handling mechanism using functional constructs. This includes the &lt;a href="https://www.effect.website/docs/data-types/either" rel="noopener noreferrer"&gt;&lt;code&gt;Either&lt;/code&gt; data type&lt;/a&gt; for explicit error handling and the ability to define error channels within effects&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Resource management&lt;/strong&gt;: Effect provides a structured approach to managing resources. The library ensures that resources are acquired and released safely, preventing resource leaks and improving resource management&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Composability&lt;/strong&gt;: Effect emphasizes composability and modularity. Since it’s easy to compose effects, you can also easily build complex programs from smaller, reusable components&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Type safety&lt;/strong&gt;: Effect leverages the TypeScript type system extensively to provide strong type safety. This helps catch many errors at compile-time, reducing the likelihood of runtime issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These features, alongside the actual &lt;code&gt;Effect&lt;/code&gt; type we saw in action earlier, all make Effect a great tool for developers who want to manage side effects in async, concurrent, and reactive TypeScript programs in a robust and type-safe manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros and cons of using Effect
&lt;/h2&gt;

&lt;p&gt;Using Effect in your projects comes with several benefits, along with a couple of drawbacks to keep in mind. &lt;/p&gt;

&lt;p&gt;Some of the pros of Effect include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Structured asynchronous programming&lt;/strong&gt;: Effect introduces a structured approach to handling asynchronous operations. This enables developers to compose and manage asynchronous code in a declarative and functional manner&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Gradual adoption&lt;/strong&gt;: An added benefit of using the Effect library is that it can be gradually adopted into TypeScript projects, allowing developers to choose how and if they want to continue with the library without imposing a radical shift in development practices&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Maintenance and debugging ease&lt;/strong&gt;: Using Effect allows you to maintain and easily debug your code because the predictable nature of Effect code can contribute to easier maintenance and debugging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meanwhile, some of the drawbacks of using Effect include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Learning curve&lt;/strong&gt;: The learning curve for Effect is quite steep, as Effect introduces functional programming concepts to TypeScript, which might pose a challenge for developers who are not familiar with it. However, since you can adopt Effect gradually in your projects, you can take your time to learn how best to apply effects to your TypeScript programs&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Ecosystem maturity&lt;/strong&gt;: While Effect has an active community, the ecosystem might not be as mature or extensive as some other libraries or frameworks. This could impact the availability of documentation, third-party libraries, and resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s important to consider these factors before choosing whether or not to adopt Effect into your TypeScript projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does Effect compare to RxJS?
&lt;/h2&gt;

&lt;p&gt;RxJS is a library for &lt;a href="https://blog.logrocket.com/guide-rxjs-observables/" rel="noopener noreferrer"&gt;reactive programming using Observables&lt;/a&gt;, which is a powerful and versatile way to handle asynchronous and event-based programming. RxJS is featured around a reactive programming paradigm that uses Observables, Observers, and Subjects to handle events.&lt;/p&gt;

&lt;p&gt;So, how does RxJS compare to Effect? Below is a table that compares the features of RxJS and Effect:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Features&lt;/th&gt;

&lt;th&gt;Effect&lt;/th&gt;

&lt;th&gt;RxJS&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;Programming paradigm&lt;/td&gt;

&lt;td&gt;Functional programming&lt;/td&gt;

&lt;td&gt;Reactive programming&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Main features&lt;/td&gt;

&lt;td&gt;Effects and fibers&lt;/td&gt;

&lt;td&gt;Observables&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Error handling&lt;/td&gt;

&lt;td&gt;Yes&lt;/td&gt;

&lt;td&gt;Yes&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Pros&lt;/td&gt;

&lt;td&gt;Type safety: robust error handling, promotes testability&lt;/td&gt;

&lt;td&gt;Composability, state management, and error handling&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Cons&lt;/td&gt;

&lt;td&gt;Steep learning curve, verbose code base&lt;/td&gt;

&lt;td&gt;Requires data immutability, makes writing tests complex&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Community and ecosystem&lt;/td&gt;

&lt;td&gt;Has an active community with a growing ecosystem&lt;/td&gt;

&lt;td&gt;Has an active community with a well-established ecosystem&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Effect and RxJS are both important libraries. Here are some tips to know which option to choose for different situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Choose a library that suits your project needs&lt;/li&gt;
&lt;li&gt;  Choose Effect when strong type safety, composability, and functional programming are key&lt;/li&gt;
&lt;li&gt;  Choose RxJS for asynchronous and event-based projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While these libraries can be used together, this approach is not advised, as it can lead to potential complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Throughout this article, we explored Effect, a powerful library for writing TypeScript. Effect provides a robust set of abstractions and features that contribute to code reliability, maintainability, and predictability. &lt;/p&gt;

&lt;p&gt;We looked at the &lt;code&gt;Effect&lt;/code&gt; type, which is at the core of Effect, as well as the various features of Effect. We also compared this library to RxJS to better understand when and how to strategically use each in your TypeScript projects. &lt;/p&gt;

&lt;p&gt;Have fun using Effect in your next project. You can find out more in the &lt;a href="https://www.effect.website/docs/introduction" rel="noopener noreferrer"&gt;Effect documentation&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://lp.logrocket.com/blg/typescript-signup" rel="noopener noreferrer"&gt;LogRocket&lt;/a&gt;: Full visibility into your web and mobile apps
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/typescript-signup" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgytow1cup40vuqnyvwdl.png" alt="LogRocket Signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/typescript-signup" rel="noopener noreferrer"&gt;LogRocket&lt;/a&gt; is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.&lt;/p&gt;

&lt;p&gt;In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/typescript-signup" rel="noopener noreferrer"&gt;Try it for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Exploring Redux Toolkit 2.0 and the Redux second generation</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Tue, 23 Jan 2024 19:23:55 +0000</pubDate>
      <link>https://dev.to/logrocket/exploring-redux-toolkit-20-and-the-redux-second-generation-59cj</link>
      <guid>https://dev.to/logrocket/exploring-redux-toolkit-20-and-the-redux-second-generation-59cj</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/stephan-miller/"&gt;Stephan Miller&lt;br&gt;
&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;State management in web applications is a hot topic. But while React's Context API, MobX, and a handful of other libraries might be great alternatives to Redux, Redux is still king.&lt;/p&gt;

&lt;p&gt;Redux has earned its stripes. It's predictable, reliable, and has a huge community of users. But even those of us who use it have to be honest: there used to be a lot of boilerplate to deal with, which added complexity and could make tracing variables through your source code a pain. &lt;/p&gt;

&lt;p&gt;But if you're still dealing with this boilerplate, then you need to catch up. Redux Toolkit has been around since 2019 and is now the standard method of creating Redux apps, streamlining your state management, and reducing the amount of boilerplate code you need to write. And if you are already using Redux Toolkit and RTK Query, Redux Toolkit 2.0 was released to production in November 2023, so it's ready to use.&lt;/p&gt;
&lt;h2&gt;
  
  
  Redux Toolkit 2.0 overview and installation
&lt;/h2&gt;

&lt;p&gt;Redux Toolkit 2.0 is the first major version of Redux Toolkit in four years and while it's a big overhaul and there are some breaking changes, &lt;a href="https://redux.js.org/usage/migrations/migrating-rtk-2"&gt;Redux documentation&lt;/a&gt; states that "most of the breaking changes should not have an actual effect on end users" and that "many projects can just update the package version with very few code changes." Here is an overview of the changes:&lt;/p&gt;
&lt;h3&gt;
  
  
  Modernization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Packaging updates:&lt;/strong&gt; The modern ESM build lives in &lt;code&gt;./dist/&lt;/code&gt; with a CJS build included for compatibility&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Deprecations removed:&lt;/strong&gt; Several options that were marked as deprecated in the past have been removed, such as the outdated object syntax in slices and reducers&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Better workflow
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;New &lt;code&gt;combineSlices&lt;/code&gt; method:&lt;/strong&gt; Lazy load slice reducers for improved performance and modularity&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Object vs. callback syntax:&lt;/strong&gt; Both &lt;code&gt;createSlice&lt;/code&gt; and &lt;code&gt;createReducer&lt;/code&gt; now use a cleaner callback syntax instead of the deprecated object approach&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dynamic middleware&lt;/strong&gt;: You can now add middleware on the fly&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Dependency changes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Updated dependencies, like Reselect and Redux Thunk, which you don't have to install separately&lt;/li&gt;
&lt;li&gt;  Requires TypeScript 4.7 or later for optimal compatibility&lt;/li&gt;
&lt;li&gt;  Requires React Redux 9.0 for React apps, which you have to install separately&lt;/li&gt;
&lt;li&gt;  Requires React 18 if you're using React Redux&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Installing Redux Toolkit
&lt;/h2&gt;

&lt;p&gt;Now that we have an idea of the changes and improvements in this new version of Redux Toolkit, let's look at how to migrate a web app to this new version. If you are still using old school, non-Toolkit Redux, I will point you to other posts along the way that will guide you through migrating to the newer way of using Redux. &lt;/p&gt;

&lt;p&gt;The first step is to install the new version, which is v2.0.2 at the time of writing this article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# with npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @reduxjs/toolkit
&lt;span class="c"&gt;# or with yarn&lt;/span&gt;
yarn add @reduxjs/toolkit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will bring Redux core 5.0, Reselect 5.0, and Redux Thunk 3.0 along with it. If you are installing this in a React app, the new version of React Redux requires updating to React 18. &lt;/p&gt;

&lt;p&gt;Once you have upgraded React or if you are already running this version, install React Redux 9.0 with one of these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# with npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;react-redux
&lt;span class="c"&gt;# or with yarn&lt;/span&gt;
yarn add react-redux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Moving to Redux Toolkit 2.0 and Redux core 5.0
&lt;/h2&gt;

&lt;p&gt;If you are still using vanilla Redux, you should check out this &lt;a href="https://blog.logrocket.com/smarter-redux-redux-toolkit/"&gt;article on moving to Redux Toolkit.&lt;/a&gt; This installation won't change that because you can still use vanilla Redux with this version, but who would want to? Redux Toolkit changes the following three files into one file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Actions&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ADD_TODO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ADD_TODO&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ADD_TODO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Reducer&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;todoReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ADD_TODO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Store&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoReducer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the resulting file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSlice&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todoSlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSlice&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addTodo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todoSlice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;todoSlice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Redux ToolKit changes in 2.0
&lt;/h2&gt;

&lt;p&gt;Now let's look at how Redux Toolkit improved in the latest version and what changes have to be made during an upgrade.&lt;/p&gt;

&lt;h3&gt;
  
  
  Minor TypeScript changes
&lt;/h3&gt;

&lt;p&gt;Here are some of the simple changes you have to make because of TypeScript compatibility updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;UnknownAction&lt;/code&gt; replaces &lt;code&gt;AnyAction&lt;/code&gt;:&lt;/strong&gt; Treat any action's fields as &lt;code&gt;unknown&lt;/code&gt; unless explicitly checked. Use type guards like &lt;code&gt;.match()&lt;/code&gt; from Redux Toolkit or the new &lt;code&gt;isAction&lt;/code&gt; utility to verify action types before accessing fields&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;Middleware&lt;/code&gt; action and &lt;code&gt;next&lt;/code&gt; parameters are also &lt;code&gt;unknown&lt;/code&gt;:&lt;/strong&gt; Use type guards to safely interact with actions within the middleware&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;PreloadedState&lt;/code&gt; type is gone:&lt;/strong&gt; It has been replaced by a generic in the &lt;code&gt;Reducer&lt;/code&gt; type&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Callback syntax in &lt;code&gt;createSlice&lt;/code&gt; is now required
&lt;/h3&gt;

&lt;p&gt;This change applies to both &lt;code&gt;createSlice.extraReducers&lt;/code&gt; and &lt;code&gt;createReducer&lt;/code&gt;. Up until this version, you could use either type of syntax. Here is an example of how to make this change. &lt;/p&gt;

&lt;p&gt;This is the code block before making the change. We’re using the object syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mySlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSlice&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ... other reducers&lt;/span&gt;
  &lt;span class="na"&gt;extraReducers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fetchTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fetchTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fulfilled&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fetchTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rejected&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is after the change. We’re using the callback syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mySlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSlice&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ... other reducers&lt;/span&gt;
&lt;span class="na"&gt;extraReducers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;builder&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fulfilled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rejected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Changes to &lt;code&gt;configureStore&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;According to the Redux docs, &lt;code&gt;createStore&lt;/code&gt; is now deprecated and &lt;code&gt;configureStore&lt;/code&gt; should be used instead. However, this has been the case since version 4.2.0, so it is not a new development. They are just reiterating this; &lt;code&gt;createStore&lt;/code&gt; won't be removed because &lt;code&gt;configureStore&lt;/code&gt; uses it internally, but it shouldn't be used directly. &lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;configureStore.middleware&lt;/code&gt; and &lt;code&gt;configureStore.enhancers&lt;/code&gt; must now be callbacks. Here is an example of these changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;configureStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux-logger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;batchedSubscribe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux-batched-subscribe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;configureStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// other configuration options&lt;/span&gt;
  &lt;span class="na"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getDefaultMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getDefaultMiddleware&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="c1"&gt;// NOT THIS: middleware: (getDefaultMiddleware) =&amp;gt; return [myMiddleware],&lt;/span&gt;
  &lt;span class="na"&gt;enhancers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getDefaultEnhancers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getDefaultEnhancers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;batchedSubscribe&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="c1"&gt;// NOT THIS: enhancers: (getDefaultEnhancers) =&amp;gt; return [myEnhancer],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order of &lt;code&gt;middleware&lt;/code&gt; and &lt;code&gt;enhancers&lt;/code&gt; matters. For internal type inference to work, &lt;code&gt;middleware&lt;/code&gt; has to come first. &lt;/p&gt;

&lt;p&gt;You now have to use the &lt;code&gt;Tuple&lt;/code&gt; type to provide an array of custom middleware or enhancers to &lt;code&gt;configureStore&lt;/code&gt;. A plain array often leads to type loss, while &lt;code&gt;Tuple&lt;/code&gt; maintains type safety. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;configureStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Tuple&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux-logger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;configureStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rootReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getDefaultMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getDefaultMiddleware&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;myCustomMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Changes to customizing &lt;code&gt;reactHooksModule&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Previously you could introduce your own custom versions of &lt;code&gt;useSelector&lt;/code&gt;, &lt;code&gt;useDispatch&lt;/code&gt;, and &lt;code&gt;useStore&lt;/code&gt; but there was no way to check that all three were added. This module is now under the key of &lt;code&gt;hooks&lt;/code&gt; and there is a check to determine whether all three exist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// What you could do before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customCreateApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildCreateApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;coreModule&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nf"&gt;reactHooksModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;useDispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createDispatchHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createSelectorHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// How you do it now&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customCreateApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildCreateApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;coreModule&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nf"&gt;reactHooksModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;useDispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createDispatchHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createSelectorHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;useStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createStoreHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New Thunk support in &lt;code&gt;createSlice.reducers&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Redux Toolkit 2.0 introduces the ability to add async thunks within &lt;code&gt;createSlice.reducers&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To do so, first set up a custom version of &lt;code&gt;createSlice&lt;/code&gt; using &lt;code&gt;buildCreateSlice&lt;/code&gt; with access to &lt;code&gt;createAsyncThunk&lt;/code&gt;. Then, use a callback for &lt;code&gt;reducers&lt;/code&gt; to define thunks and other reducers. Finally, employ &lt;code&gt;create.asyncThunk&lt;/code&gt; within the callback. &lt;/p&gt;

&lt;p&gt;Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createSliceWithThunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildCreateSlice&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;creators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;asyncThunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asyncThunkCreator&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todosSlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSliceWithThunks&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// Normal reducers&lt;/span&gt;
    &lt;span class="na"&gt;deleteTodo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt;
    &lt;span class="c1"&gt;// Async thunk&lt;/span&gt;
    &lt;span class="na"&gt;fetchTodo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asyncThunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;thunkApi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`myApi/`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;fulfilled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;rejected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;settled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Access thunks like regular actions using slice.actions.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;deleteTodo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchTodo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todosSlice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Making selectors part of your slice
&lt;/h3&gt;

&lt;p&gt;You can now define selectors directly within &lt;code&gt;createSlice&lt;/code&gt;. Here are some points to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Selectors assume the slice state is mounted at &lt;code&gt;rootState.{sliceName}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Use &lt;code&gt;sliceObject.getSelectors(selectSliceState)&lt;/code&gt; to customize selector generation for alternate state locations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mySlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSlice&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... reducers&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;selectors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;selectTodos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;selectTodoById&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todoId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;todoId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Accessing selectors:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;selectTodos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectTodoById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mySlice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;selectTodos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;selectTodoById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lazy loading and code split slices
&lt;/h3&gt;

&lt;p&gt;Redux Toolkit 2.0 introduces &lt;code&gt;combineSlices&lt;/code&gt; to enable code splitting and lazy loading reducers. It accepts individual slices or an object of slices and automatically merges them using &lt;code&gt;combineReducers&lt;/code&gt;. The reducer function it generates provides the following methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;inject()&lt;/code&gt;&lt;/strong&gt;: Adds slices dynamically, even after the store is created&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;withLazyLoadedSlices()&lt;/code&gt;&lt;/strong&gt;: Generates TypeScript types for slices to be added later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Combine slices and add lazy loaded type&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;combineSlices&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;slice1&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./slice1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;slice2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./slice2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;lazyLoadedSlice&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./lazyLoadedSlice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;combineSlices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slice1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slice2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;withLazyLoadedSlices&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
    &lt;span class="nx"&gt;WithSlice&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;lazyLoadedSlice&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Later, inject new slice lazy loaded slice:&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;lazyLoadedSlice&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./lazyLoadedSlice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;rootReducer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lazyLoadedSlice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dynamically add middleware
&lt;/h3&gt;

&lt;p&gt;It used to take a hack or a separate package to add middleware at runtime, which can be useful for code splitting. Now you can do this with Redux Toolkit 2.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import, create dynamic instance, and configure your store with it.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createDynamicMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;configureStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamicMiddleware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createDynamicMiddleware&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;configureStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;myThings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;myThingsReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getDefaultMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;getDefaultMiddleware&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dynamicMiddleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Add your middleware at runtime&lt;/span&gt;
&lt;span class="nx"&gt;dynamicMiddleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loggerMiddleware&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Add other middleware based on conditions, user input, etc.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someCondition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;dynamicMiddleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;otherMiddleware&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;createDynamicMiddleware&lt;/code&gt; also comes with &lt;a href="https://redux-toolkit.js.org/api/createDynamicMiddleware#react-integration"&gt;React hook integration&lt;/a&gt; (if you have React Redux 9.0 installed).&lt;/p&gt;

&lt;h2&gt;
  
  
  Reselect 5.0: Changes and new features
&lt;/h2&gt;

&lt;p&gt;Reselect now uses a &lt;code&gt;WeakMap&lt;/code&gt;-based memoization function called &lt;code&gt;weakMapMemoize&lt;/code&gt; by default. It offers better performance and memory management compared to the previous &lt;code&gt;defaultMemoize&lt;/code&gt; function. The cache size is effectively infinite, but it now relies exclusively on reference comparison. &lt;/p&gt;

&lt;p&gt;The older &lt;code&gt;defaultMemoize&lt;/code&gt; function is now available as &lt;code&gt;lruMemoize&lt;/code&gt; for those who need a Least Recently Used (LRU) cache. If you want to create custom equality comparisons, you can make &lt;code&gt;createSelector&lt;/code&gt; use &lt;code&gt;lruMemoize&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;You can then pass options to &lt;code&gt;createSelector&lt;/code&gt; for more control over memoization and debugging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;memoize&lt;/code&gt;: Specifies a custom memoization function (e.g., &lt;code&gt;lruMemoize&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;argsMemoize&lt;/code&gt;: Customizes memoization behavior for selector arguments&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;inputStabilityCheck&lt;/code&gt;: Enables a development-time check for input selector stability&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;identityFunctionCheck&lt;/code&gt;: Warns if the result function returns its input directly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example of specifying the older &lt;code&gt;memoize&lt;/code&gt; function instead of the default &lt;code&gt;weakMapMemoize&lt;/code&gt; along with some of these new options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reselect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mySelector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lruMemoize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Use LRU cache, runs the input selectors and compares their current results with the previous ones&lt;/span&gt;
    &lt;span class="na"&gt;memoizeOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;resultEqualityCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Custom equality comparison&lt;/span&gt;
    &lt;span class="nl"&gt;argsMemoize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;defaultMemoize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Use default memoize function, compares the current arguments with the previous ones&lt;/span&gt;
    &lt;span class="na"&gt;argsMemoizeOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isEqual&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Custom equality comparison for argsMemoize&lt;/span&gt;
    &lt;span class="na"&gt;inputStabilityCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Enable input stability check&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Changes to RTK Query 2.0
&lt;/h2&gt;

&lt;p&gt;Now, if you aren't using Redux Toolkit, you definitely aren't using RTK Query. I started using Toolkit around two years ago and just happened to run into RTK Query about six months ago when I was looking for a simplified way of fetching data for the dashboard. I wish I had found it earlier! &lt;/p&gt;

&lt;p&gt;While it doesn't replace React Toolkit, &lt;a href="https://blog.logrocket.com/rtk-query-future-data-fetching-caching-redux/"&gt;RTK Query is great for fetching data&lt;/a&gt;. It will even take out your service files if you currently have them, which means less boilerplate. &lt;/p&gt;

&lt;p&gt;Only a few things were changed in RTK Query 2.0. The development team stated that the focus for 2.0 was improvements to the core Redux Toolkit libraries and now that they’re done with that, they can shift attention to improving the RTK Query library. But some issues were fixed, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Some users reported issues with manually skipping subscriptions and running multiple lazy queries. These bugs were due to RTK Query not tracking cache entries in certain scenarios&lt;/li&gt;
&lt;li&gt;  Running multiple mutations consecutively could cause problems with tag invalidation (updating related data based on changes). RTK Query now lets you choose how tag invalidation happens. By default, it waits briefly to group multiple invalidations, preventing unnecessary processing, but if you prefer the old behavior, you can switch it back in the configuration by setting &lt;code&gt;invalidationBehavior&lt;/code&gt; to &lt;code&gt;immediate&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Not much changed with React Redux 9.0
&lt;/h2&gt;

&lt;p&gt;Redux Toolkit 2 requires React Redux 9 in React-based apps. The changes to React Redux were relatively minor, mainly to make it compatible with the other Redux changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Redux Toolkit 2.0 is here, and it is not yesterday's Redux, but it hasn't been for a while. Redux Toolkit and RTK Query have been around for four years now and reduced a lot of the boilerplate, which was the biggest complaint about Redux. &lt;/p&gt;

&lt;p&gt;But this new version adds even more reasons to give it a try, including streamlined, modern packaging and the removal of outdated and deprecated features. Slices can now be lazy loaded and string-based action types simplify debugging. Finally, upgrading doesn't require many code changes and, according to the docs and my experience, won't affect your users.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get set up with LogRocket's modern error tracking in minutes:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://logrocket.com/signup/"&gt;https://logrocket.com/signup/&lt;/a&gt; to get an app ID.&lt;/li&gt;
&lt;li&gt;Install LogRocket via NPM or script tag. &lt;code&gt;LogRocket.init()&lt;/code&gt; must be called client-side, not server-side.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save&lt;/span&gt; logrocket 

// Code:

import LogRocket from &lt;span class="s1"&gt;'logrocket'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
LogRocket.init&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app/id'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Script Tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.lr-ingest.com/LogRocket.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.(Optional) Install plugins for deeper integrations with your stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Redux middleware&lt;/li&gt;
&lt;li&gt;  ngrx middleware&lt;/li&gt;
&lt;li&gt;  Vuex plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/signup"&gt;Get started now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>redux</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Exploring Next.js no-code platforms for rapid development</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Tue, 23 Jan 2024 15:18:01 +0000</pubDate>
      <link>https://dev.to/logrocket/exploring-nextjs-no-code-platforms-for-rapid-development-3f94</link>
      <guid>https://dev.to/logrocket/exploring-nextjs-no-code-platforms-for-rapid-development-3f94</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/oyinkansolaawosan/"&gt;Oyinkansola Awosan&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developing fast, dependable, and user-friendly web applications requires staying up-to-date with the constantly changing web development landscape. The combination of Next.js and no-code platforms has revolutionized the web development process, enabling frontend developers to create complex applications without deep coding knowledge. &lt;/p&gt;

&lt;p&gt;This article explores the advantages, drawbacks, and best practices associated with using Next.js no-code platforms to speed up frontend development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of no-code platforms for frontend development
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Accessibility and inclusivity&lt;/strong&gt;: No-code platforms provide individuals with the opportunity to engage in frontend development, regardless of their technical background. These platforms are generally easy to use and have intuitive interfaces, freeing designers, entrepreneurs, and non-developers from the limitations of complex code and enabling them to construct user interfaces&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Rapid prototyping&lt;/strong&gt;: Prototyping often happens faster with no-code platforms since developers don't have to dig into complex code intricacies to transform concepts into observable prototypes and mockups quickly. This speeds up the development process, promotes teamwork, and enables stakeholders to see the finished product early&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cost effectiveness&lt;/strong&gt;: Development expenses may be significantly reduced using no-code platforms, particularly for initiatives with tight budgets. By reducing complex code requirements, companies may better manage their resources&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Flexibility and&amp;lt; customization&lt;/strong&gt;: Although no-code platforms are sometimes considered simple, many technologies offer some degree of customization and flexibility. Developers can customize user interfaces, include unique features, and create great user experiences without sacrificing the advantages of a no-code methodology&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s review some popular no-code platforms for Next.js. We’ll look at Plasmic, Retool, Stackbit, and Notion.&lt;/p&gt;




&lt;h2&gt;
  
  
  Plasmic
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hz1DxK3F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/plasmic-no-code-platform-next-js.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hz1DxK3F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/plasmic-no-code-platform-next-js.png" alt="Plasmic No-Code Platform Next.js" width="800" height="355"&gt;&lt;/a&gt; &lt;a href="https://www.plasmic.app/nextjs"&gt;Plasmic&lt;/a&gt; is a visual page builder and headless CMS tool that functions perfectly with contemporary web development frameworks like Next.js. This platform offers a creative way for developers and designers to close the gap between code and visual design. Plasmic’s integration with Next.js improves the entire web development process, making it easier for designers and developers to work collaboratively and productively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plasmic integration with Next.js
&lt;/h3&gt;

&lt;p&gt;The first step to integrating Plasmic with Next.js is to install it locally or globally using npm or Yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @plasmicapp/loader-nextjs
yarn add @plasmicapp/loader-nextjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To initialize Plasmic, create a &lt;code&gt;plasmic-init.ts&lt;/code&gt; module that defines the project's ID and public API token globally, which can be obtained from the Plasmic Studio. The specifics will depend on the demands of your project. For thorough instructions, including code samples and thorough descriptions, see the &lt;a href="https://docs.plasmic.app/learn/nextjs-quickstart/"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;p&gt;There are two primary benefits associated with using Plasmic with Next.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Seamless integration&lt;/strong&gt;: Plasmic is tailored for and provides a seamless interface with Next.js. Developers using Plasmic's visual tools through this connection get access to Next.js capabilities, like file-based routing, server-side rendering (SSR), and static site creation&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Enhanced designer-developer collaboration&lt;/strong&gt;: Thanks to Plasmic, designers do not need to write code to develop or alter UI components graphically. There’s less back and forth between developers and designers because modifications can be performed in the Plasmic editor and instantly reflected in the coding&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;p&gt;Here are some disadvantages to keep in mind if you’re considering using Plasmic with Next.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Learning curve&lt;/strong&gt;: Adopting Plasmic may require a steep learning curve for teams that are not used to visual design tools or are firmly entrenched in traditional coding processes&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Overdependence potential&lt;/strong&gt;: Developers who desire a thorough grasp of every part of the codebase may find that relying too much on a visual builder can cause a gap in their comprehension of the underlying code&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Limited control for advanced customization&lt;/strong&gt;: Plasma my limit developers who are seeking the ability to create highly customized and intricate designs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Retool
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1xKUWca---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/retool-no-code-platform-next-js.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1xKUWca---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/retool-no-code-platform-next-js.png" alt="Retool No-Code Platform Next.js" width="800" height="364"&gt;&lt;/a&gt; &lt;a href="https://retool.com/"&gt;Retool&lt;/a&gt; is a low-code platform intended to facilitate the rapid development of internal tools by developers. It simplifies the development of bespoke apps for internal corporate activities by providing a wide choice of pre-built components and integrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retool integration with Next.js
&lt;/h3&gt;

&lt;p&gt;Retool integration with Next.js applications requires a few steps, from the initial setup of the Next.js app to the integration of Retool with Next.js: &lt;/p&gt;

&lt;p&gt;Step 1: Set up Next.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app@latest my-nextjs-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-next-js-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2: Create a Retool account &lt;br&gt;
Create a basic account on the Retool platform if you do not already have one, and familiarize yourself with how tools are used within the Retool environment. &lt;/p&gt;

&lt;p&gt;Step 3: Connect Retool to Next.js &lt;br&gt;
If you’re using the &lt;a href="https://docs.retool.com/queries/guides/api-requests#:~:text=Query%20a%20REST%20API%E2%80%8B,options%20in%20the%20available%20fields."&gt;REST API Query for Retool&lt;/a&gt;, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Use an existing app or build a new one in your Retool dashboard&lt;/li&gt;
&lt;li&gt;  Establish a connection with your Next.js API route, using Retool's REST API Query&lt;/li&gt;
&lt;li&gt;  If you're working locally, set the URL to your Next.js API endpoint, such as &lt;code&gt;http://localhost:3000/api/retool&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To manage CORS, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Retool will send queries to your Next.js API, so make sure your Next.js app is set up to support Cross-Origin Resource Sharing (CORS)&lt;/li&gt;
&lt;li&gt;  You may manually set up CORS in your API routes or use the nextjs-cors package&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;p&gt;Using Retool with Next.js offers several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Quick development&lt;/strong&gt;: Retool's user-friendly interface with drag-and-drop components allows more rapid application development than writing code from scratch; it reduces the work and time required for frontend development&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Pre-built components&lt;/strong&gt;: Retool provides many readily available, easily customizable, and application-integrable components, such as forms, tables, buttons, and charts&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Integrations&lt;/strong&gt;: Retool offers a wide range of connectors with third-party services, databases, and APIs, enabling smooth data exchanges and interactions in the program&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;p&gt;Here are some disadvantages associated with using Retool with Next.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Learning curve&lt;/strong&gt;: Retool streamlines development, but there is still a learning curve to grasp its features and potential&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Limitations&lt;/strong&gt;: The combination of Retool and Next.js has limited use in consumer-facing applications&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cost&lt;/strong&gt;: Retool can be costly, especially for small enterprises or startups, depending on the extent of utilization&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Stackbit
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zY4rD7fS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/stackbit-no-code-platform-next-js.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zY4rD7fS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/stackbit-no-code-platform-next-js.png" alt="Stackbit No-Code Platform Next.js" width="800" height="401"&gt;&lt;/a&gt; &lt;a href="https://www.stackbit.com/"&gt;Stackbit&lt;/a&gt; is a cutting-edge technology created to improve and expedite the creation process of Jamstack websites. The core of Stackbit's functionality is the Jamstack design, which emphasizes client-side JavaScript, utility APIs, and predefined markup. Stackbit is unique in the web development space for several reasons, and its ability to interact with frameworks such as Next.js increases its usefulness even more.&lt;/p&gt;
&lt;h3&gt;
  
  
  Integrating Stackbit with Next.js
&lt;/h3&gt;

&lt;p&gt;To integrate Stackbit with Next.js, start by initializing a new Next.js project, like ao:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init next-app your-nextjs-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, configure the &lt;code&gt;stackbit.yaml&lt;/code&gt; file in your project root to create content models and their corresponding fields. This is a necessary step for Stackbit to comprehend the organization and content of your project. &lt;/p&gt;

&lt;p&gt;Here’s an example configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ContentModels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;BlogPost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;data&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content/data/blog-post.md'&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;title&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Title&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use Stackbit to fetch and display data. You can use the page's data-fetching methods, such as &lt;code&gt;getServerSideProps&lt;/code&gt; or &lt;code&gt;getStaticProps&lt;/code&gt;, to fetch content controlled by Stackbit and then display it in your Next.js pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;p&gt;There are several benefits to using Stackbit with Next.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Headless CMS with a visual editor&lt;/strong&gt;: Stackbit combines a headless CMS with a visual editor, providing a user-friendly solution for content management&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Supports multiple data sources&lt;/strong&gt;: The platform supports multiple data sources, facilitating flexibility in integrating various content types&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Speed and performance&lt;/strong&gt;: Using the Jamstack methodology, Stackbit websites have superior loading speeds and an enhanced user experience by default. Jamstack websites are fast by default, due to pre-rendering and location-based servers. Stackbit claims its websites load 2x faster than traditional websites&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;p&gt;Here are a couple of potential disadvantages to using Stackbit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Limited customization for complex projects&lt;/strong&gt;: Stackbit works great for simple web projects, but may need help to handle more complicated or unique applications&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dependency on&amp;lt; third-party services&lt;/strong&gt;: Stackbit integrates many platforms and services, so any modifications or interruptions to those services may affect projects using Stackbit&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Notion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z2Qu9Znh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/notion-no-code-platform-next-js.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z2Qu9Znh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/notion-no-code-platform-next-js.png" alt="Notion No-Code Platform Next.js" width="800" height="411"&gt;&lt;/a&gt; &lt;a href="https://www.notion.so"&gt;Notion&lt;/a&gt; is an all-in-one workspace program that is well-liked for its flexible methods for handling databases, taking notes, managing tasks, and working in groups. This application lets users generate and arrange work in whichever best fits their needs by combining the features of a spreadsheet, document editor, and customized content management system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Notion with Next.js
&lt;/h2&gt;

&lt;p&gt;The first step to integrating Notion with Next.js is to set up your Notion workspace. This requires creating a Notion database and obtaining the right Notion API credentials to fetch data. &lt;/p&gt;

&lt;p&gt;Next, run the following command in your terminal to install the required packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @notionhq/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use the Notion SDK in your Next.js application to retrieve data from your database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;p&gt;There are several benefits associated with using &lt;a href="https://blog.logrocket.com/using-notion-next-js-isr-sync-content/"&gt;Notion with Next.js&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Collaboration platform with no-code capabilities&lt;/strong&gt;: Notion is a versatile collaboration platform with no-code capabilities that allows for collaborative content creation&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Database functionalities for content organization&lt;/strong&gt;: The platform offers database functionalities, enabling the structured organization of content for various purposes&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Versatile for project management needs&lt;/strong&gt;: Notion is versatile and can be adapted for various project management needs, enhancing collaboration among team members&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;p&gt;Here are some disadvantages associated with using Notion with Next.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Limited for complex web applications&lt;/strong&gt;: While powerful, Notion may have limitations for developers working on highly complex web applications&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Lack of suitability for large-scale projects&lt;/strong&gt;: For large-scale projects, developers may need to carefully assess whether Notion meets their scalability requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next.js no-code platform comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;&lt;/td&gt;

&lt;td&gt;Plasmic&lt;/td&gt;

&lt;td&gt;Retool&lt;/td&gt;

&lt;td&gt;Stackbit&lt;/td&gt;

&lt;td&gt;Notion&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Open source&lt;/td&gt;

&lt;td&gt;No&lt;/td&gt;

&lt;td&gt;No&lt;/td&gt;

&lt;td&gt;Some components/themes are open source&lt;/td&gt;

&lt;td&gt;No&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Customization&lt;/td&gt;

&lt;td&gt;High customization through visual UI.&lt;/td&gt;

&lt;td&gt;Retool is very customizable as it allows embedding of custom code&lt;/td&gt;

&lt;td&gt;Customizable themes; allows custom code&lt;/td&gt;

&lt;td&gt;Limited customization compared to the other platforms&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Speed&lt;/td&gt;

&lt;td&gt;Generally fast with a visual development approach&lt;/td&gt;

&lt;td&gt;Pre-built components and tools are available to make it fast&lt;/td&gt;

&lt;td&gt;Efficient jamstack deployment, optimized for speed so generally very fast&lt;/td&gt;

&lt;td&gt;Fast but optimized more as a collaborative and note-taking tool&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Community support&lt;/td&gt;

&lt;td&gt;Community is not very large, but it is growing and users can ask questions via its forum or on Slack&lt;/td&gt;

&lt;td&gt;Active community, well-documented, and strong developer support via Discord and their support forum&lt;/td&gt;

&lt;td&gt;Growing community; good documentation&lt;/td&gt;

&lt;td&gt;Boasts a large user base, an active community, and an extensive documentation&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The use of no-code platforms with Next.js has the potential to revolutionize frontend development, particularly for &lt;a href="https://blog.logrocket.com/structure-scalable-next-js-project-architecture/"&gt;Next.js applications&lt;/a&gt;. These platforms drastically cut down on development time and complexity by allowing for the quick, visual production and administration of online content without requiring specialized code. &lt;/p&gt;

&lt;p&gt;Both developers and non-developers can create and manage complex web applications more effectively with the help of these technologies. This combination of standard development frameworks with no-code capabilities is a big step toward improving the accessibility and agility of online development.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://lp.logrocket.com/blg/nextjs-signup"&gt;LogRocket&lt;/a&gt;: Full visibility into production Next.js apps
&lt;/h2&gt;

&lt;p&gt;Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, &lt;a href="https://lp.logrocket.com/blg/nextjs-signup"&gt;try LogRocket&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/nextjs-signup"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ajjeExJ2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png" alt="LogRocket Signup" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/nextjs-signup"&gt;LogRocket&lt;/a&gt; is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.&lt;/p&gt;

&lt;p&gt;The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.&lt;/p&gt;

&lt;p&gt;Modernize how you debug your Next.js apps — &lt;a href="https://lp.logrocket.com/blg/nextjs-signup"&gt;start monitoring for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Bootstrap adoption guide: Overview, examples, and alternatives</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Thu, 18 Jan 2024 15:22:30 +0000</pubDate>
      <link>https://dev.to/logrocket/bootstrap-adoption-guide-overview-examples-and-alternatives-5h2k</link>
      <guid>https://dev.to/logrocket/bootstrap-adoption-guide-overview-examples-and-alternatives-5h2k</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/asaoluelijah/" rel="noopener noreferrer"&gt;Elijah Asaolu&lt;br&gt;
&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bootstrap is a CSS framework that has revolutionized the ease and efficiency of web development. It primarily provides a collection of pre-styled components and layouts that can easily integrate into any web project. This collection includes everything from navbars and buttons to forms and modals, all pre-styled for instant use. &lt;/p&gt;

&lt;p&gt;In this guide, we’ll explore the origins of Bootstrap and how it has evolved over the years. We'll also go into key Bootstrap features, its use cases, why you should choose Bootstrap, and briefly explain how Bootstrap compares with other top CSS frameworks.&lt;/p&gt;


&lt;h2&gt;
  
  
  Introduction to Bootstrap
&lt;/h2&gt;

&lt;p&gt;The origins of Bootstrap can be traced back to 2011 when its creators, Mark Otto and Jacob Thornton, were working at Twitter. Since the previous styling libraries they used caused design discrepancies and were difficult to maintain, they opted to create their own. &lt;/p&gt;

&lt;p&gt;Initially, the team designed Bootstrap as an internal tool to improve design consistency and further unify the platform's frontend standards. Recognizing the project's potential outside of Twitter's internal use, the team opted to open source it, making it public later that year. &lt;/p&gt;

&lt;p&gt;Since then, Bootstrap has changed considerably — most notably, in its relationship with JavaScript libraries. &lt;/p&gt;

&lt;p&gt;Originally, Bootstrap relied heavily on jQuery to implement dynamic components such as dropdowns and modals. However, Bootstrap v5 made a significant shift by abandoning jQuery in favor of vanilla JavaScript — an intentional attempt to adopt new JavaScript standards and improve performance.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;em&gt;Further reading:&lt;/em&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/the-history-and-legacy-of-jquery/" rel="noopener noreferrer"&gt;The history and legacy of jQuery&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/using-bootstrap-components-with-custom-javascript/" rel="noopener noreferrer"&gt;Using Bootstrap components with custom JavaScript&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  How Bootstrap works
&lt;/h3&gt;

&lt;p&gt;Behind the scenes, the Bootstrap team and other contributors have compiled a file containing numerous CSS style definitions linked to specific class names. This file, which is called &lt;code&gt;bootstrap.css&lt;/code&gt;, allows you to rapidly apply these styles to your project by referencing the appropriate class names. &lt;/p&gt;

&lt;p&gt;Additionally, utilizing these styles in your project is pretty straightforward. First, you link Bootstrap's CSS and JavaScript files in your markup, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Bootstrap Example&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Bootstrap CSS --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello, Bootstrap!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Bootstrap JavaScript --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the files linked, you can start using Bootstrap in your HTML by adding Bootstrap's class names to your markup elements. For example, to create a primary-colored button, you would use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Primary Button&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over time, developers have enhanced Bootstrap's adaptability by integrating it with various JavaScript frameworks. For instance, BootstrapVue exclusively caters to Vue.js, while React-Bootstrap is specifically designed for React.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Further reading:&lt;/em&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/getting-started-bootstrapvue/" rel="noopener noreferrer"&gt;Getting started with BootstrapVue&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/using-bootstrap-react-tutorial-examples/" rel="noopener noreferrer"&gt;Using Bootstrap with React&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/handling-bootstrap-integration-next-js/" rel="noopener noreferrer"&gt;Handling Bootstrap integration with Next.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/trying-out-the-new-bootstrap-5-with-react/" rel="noopener noreferrer"&gt;Trying out the new Bootstrap 5 with React&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why choose Bootstrap?
&lt;/h2&gt;

&lt;p&gt;Bootstrap for web development offers numerous benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Performance and bundle size:&lt;/strong&gt; Bootstrap is optimized for performance. It provides a lean and efficient CSS and JavaScript bundle, ensuring it doesn't bloat your website with unnecessary code&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Ease of use:&lt;/strong&gt; One of Bootstrap’s standout features is its ease of use. The framework's intuitive classes and consistent design principles allow developers to quickly create layouts and components without extensive CSS or JavaScript knowledge&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Responsive design:&lt;/strong&gt; The framework is built with a mobile-first approach, ensuring websites are responsive and visually appealing on all devices, from phones to desktops&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Documentation, community, and ecosystem:&lt;/strong&gt; Another major strength of Bootstrap is its comprehensive documentation and strong community support. The well-organized documentation makes it easy to find information and learn how to use the framework&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Seamless integrations:&lt;/strong&gt; Bootstrap’s compatibility with various JavaScript frameworks further enhances its versatility. Tools like BootstrapVue and React-Bootstrap, or ReactStrap, allow developers to integrate Bootstrap's styling and components within Vue.js and React projects, respectively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These benefits make Bootstrap a great choice for almost any project. However, Bootstrap has occasionally faced criticism for its distinctive, recognizable style, which some may consider its most significant drawback — possibly even its only major one. Let’s discuss this next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do all Bootstrap websites look similar?
&lt;/h3&gt;

&lt;p&gt;The similarity in appearance across Bootstrap websites, particularly in elements like buttons and navbars, has led to the narrative that all Bootstrap websites look alike. This criticism holds some truth, especially in earlier versions where customization options were more limited and developers used similar design templates. &lt;/p&gt;

&lt;p&gt;However, recent versions of Bootstrap have significantly addressed these concerns. The framework now offers enhanced extensibility and customization options. Developers can easily personalize components to fit their unique design needs without being confined to the default styles. &lt;/p&gt;

&lt;p&gt;While Bootstrap's enforced style was once a point of debate, the framework's evolution has made it more adaptable and versatile, enabling developers to override default styles and create unique, visually distinct web designs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Bootstrap features to know
&lt;/h2&gt;

&lt;p&gt;Bootstrap is packed with many components and features. Let's quickly explore some of its most common elements in an everyday application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grid system
&lt;/h3&gt;

&lt;p&gt;Bootstrap's grid system is a powerful and flexible tool that forms the foundation of most layouts within the framework. Central to this system are the concepts of containers, rows, and columns: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg1-Bootstrap-grid-system-containers-rows-columns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg1-Bootstrap-grid-system-containers-rows-columns.png" alt="Demo Of Bootstrap Grid System Labeled To Show How Containers, Rows, And Columns Work Together"&gt;&lt;/a&gt; Containers are Bootstrap's most basic layout element and are required when using the grid system. They contain, pad, and align your content within a device or viewport. &lt;/p&gt;

&lt;p&gt;Inside a container, you can create rows using the &lt;code&gt;.row&lt;/code&gt; class. Each row is considered a single horizontal group for your columns. Significantly, each row is divided into 12 equal columns, providing a consistent and flexible way to layout content. &lt;/p&gt;

&lt;p&gt;Columns are created with classes like &lt;code&gt;.col-md-*&lt;/code&gt;, where &lt;code&gt;*&lt;/code&gt; can be any number from 1–12. This number indicates how many of the 12 available columns in the grid system the column should span. For example, using &lt;code&gt;.col-md-4&lt;/code&gt; means the column will span four out of the 12 available columns. &lt;/p&gt;

&lt;p&gt;Here's a basic example of a row with four columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&amp;gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Column 1&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Column 2&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Column 3&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Column 4&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, we've added &lt;code&gt;col-md-3&lt;/code&gt; to each column, allocating one-quarter of the horizontal space per column in a medium-sized viewport: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg2-Bootstrap-four-columns-dividing-one-quarter-horizontal-space-per-column.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg2-Bootstrap-four-columns-dividing-one-quarter-horizontal-space-per-column.jpg" alt="Example Of Four Bootstrap Columns Created By Dividing One Quarter Of The Available Horizontal Space Per Column"&gt;&lt;/a&gt; Bootstrap's grid system is responsive by default, meaning these column sizes will be automatically adjusted based on the viewport's size. Additionally, you can use Bootstrap Flex utility classes to change the direction and alignment of these grid systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Background and text colors
&lt;/h3&gt;

&lt;p&gt;Bootstrap offers a range of utility classes designed to rapidly customize background and text colors within HTML elements. To change the background color of an element, you can use the &lt;code&gt;.bg-[color]&lt;/code&gt; class. Additionally, to alter a text color, the &lt;code&gt;.text-[color]&lt;/code&gt; class is available. &lt;/p&gt;

&lt;p&gt;Here, [&lt;code&gt;color&lt;/code&gt;] represents a color from Bootstrap's predefined color schemes — such as &lt;code&gt;primary&lt;/code&gt;, &lt;code&gt;secondary&lt;/code&gt;, and &lt;code&gt;success&lt;/code&gt; — and not traditional color names like red or orange: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg3-Bootstrap-predefined-color-schemes.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg3-Bootstrap-predefined-color-schemes.jpg" alt="Bootstrap Predefined Color Schemes Showing Text Color And Highlight"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In addition to individual text and background classes, Bootstrap introduces a combined class, &lt;code&gt;.text-bg-[color]&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This combined class merges the functionalities of &lt;code&gt;.text-[color]&lt;/code&gt; and &lt;code&gt;.bg-[color]&lt;/code&gt;, providing a convenient way to set both text and background colors simultaneously. It smartly adjusts the text color for optimal contrast against the specified background color: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg4-Bootstrap-combined-class-set-text-background-colors-simultaneously-smart-adjustment-optimal-contrast.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg4-Bootstrap-combined-class-set-text-background-colors-simultaneously-smart-adjustment-optimal-contrast.jpg" alt="Bootstrap Combined Class To Set Text And Background Colors Simultaneously With Smart Adjustment For Optimal Contrast Between Colors"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Furthermore, in recent Bootstrap versions, you can adjust an element's opacity via the &lt;code&gt;.text-opacity-[percentage]&lt;/code&gt; class. This allows you to set the opacity to 25 percent, 50 percent, or 75 percent of its original value: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg5-Bootstrap-text-opacity-options.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg5-Bootstrap-text-opacity-options.jpg" alt="Bootstrap Text Opacity Options Demonstrated With Label For Each Option Ordered In Descending Order From Default At The Top To 25 Percent Opacity At The Bottom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tables
&lt;/h3&gt;

&lt;p&gt;Styling HTML tables for both responsiveness and visual appeal can be challenging. Fortunately, Bootstrap simplifies this task with a variety of utility classes. You can start by adding the &lt;code&gt;.table&lt;/code&gt; class to your HTML &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; tag to instantly transform a basic table into a more professionally styled one, as shown below: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg6-Bootstrap-table-with-without-table-class.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg6-Bootstrap-table-with-without-table-class.jpg" alt="Html Table Styled With And Without Bootstrap Table Class"&gt;&lt;/a&gt; Further customization is possible with color-specific classes. For example, you can apply a color theme to an entire table or specific table cells using &lt;code&gt;.table-[color]&lt;/code&gt; classes, such as &lt;code&gt;.table-dark&lt;/code&gt;, for a dark color theme: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg7-Table-dark-class-styling.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg7-Table-dark-class-styling.jpg" alt="Bootstrap Table Styled With Table-Dark Class"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Bootstrap's table class list is extensive, allowing for various styling options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Striped tables:&lt;/strong&gt; Add &lt;code&gt;.table-striped&lt;/code&gt; to create a zebra-stripe effect on table rows&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Bordered or borderless tables:&lt;/strong&gt; Use &lt;code&gt;.table-bordered&lt;/code&gt; for borders around all parts of the table and cells and &lt;code&gt;.table-borderless&lt;/code&gt; for a borderless design&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Responsive tables:&lt;/strong&gt; The &lt;code&gt;.table-responsive&lt;/code&gt; class ensures your table remains responsive and scrolls horizontally on smaller devices, accommodating numerous columns without breaking the layout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the help of this set of Bootstrap table classes, you can quickly create tables that are both aesthetically pleasing and functional.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Further reading:&lt;/em&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/table-component-from-scratch-vue-3-bootstrap/" rel="noopener noreferrer"&gt;Build a table component from scratch in Vue 3 with Bootstrap&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Alerts
&lt;/h3&gt;

&lt;p&gt;Alerts are key visual elements that convey important messages to users, ranging from success notifications to warnings or error information. Bootstrap significantly simplifies the creation of these alerts with its utility classes. &lt;/p&gt;

&lt;p&gt;To create a styled alert, you only need to add the &lt;code&gt;.alert&lt;/code&gt; class along with a &lt;code&gt;.alert-[color]&lt;/code&gt; class to a div or any other suitable container element. In the &lt;code&gt;.alert-[color]&lt;/code&gt; class, &lt;code&gt;[color]&lt;/code&gt; reflects the nature and severity of the message. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alert alert-success"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  This is a success alert--check it out!
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alert alert-warning"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  This is a warning alert--check it out!
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alert alert-danger"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  This is a danger alert--check it out!
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above produces the following output: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg8-Demo-Bootstrap-alert-options-success-warning-danger.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg8-Demo-Bootstrap-alert-options-success-warning-danger.jpg" alt="Demo Of Bootstrap Alert Options Including Green Success Alert, Yellow Warning Alert, And Red Danger Alert With Muted Pastel Versions Of Each Color"&gt;&lt;/a&gt; To further enhance the functionality of these alerts, Bootstrap allows them to be dismissible. This feature is particularly useful for messages that do not need to remain on the screen indefinitely. &lt;/p&gt;

&lt;p&gt;You can add a button within the alert that triggers its dismissal and the &lt;code&gt;.alert-dismissible&lt;/code&gt; class on the alert element itself, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alert alert-warning alert-dismissible fade show"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Click &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;X&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; to close this alert!
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt; &lt;span class="na"&gt;data-dismiss=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;×&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above will produce the following output: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg9-Demo-dismissable-alert-Bootstrap.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg9-Demo-dismissable-alert-Bootstrap.gif" alt="Demo Of Dismissable Alert Created With Bootstrap"&gt;&lt;/a&gt; The Bootstrap alert component is a fantastic tool for presenting information in an aesthetically pleasing and intuitive way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Buttons
&lt;/h3&gt;

&lt;p&gt;One of the simplest yet most impactful features of Bootstrap is the styling options for buttons. Bootstrap offers various classes to create visually appealing buttons with minimal effort. To create a styled button, add the &lt;code&gt;.btn&lt;/code&gt; and &lt;code&gt;.btn-[color]&lt;/code&gt; classes to your HTML button elements: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg10-Styled-buttons-Bootstrap.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg10-Styled-buttons-Bootstrap.jpg" alt="Button Style Options In Bootstrap Labeled With Each Button Class"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Bootstrap also includes outline button designs for a more minimalistic look. These are created using the &lt;code&gt;.btn-outline-[color]&lt;/code&gt; class, which renders a button with only the border and text colored. The background only gets filled in on hover or focus: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg11-Bootstrap-outline-button-style.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg11-Bootstrap-outline-button-style.jpg" alt="Bootstrap Outline Button Designs For More Minimalistic Look"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Beyond basic styling, Bootstrap makes it easy to customize button sizes. For example, you can create larger or smaller buttons by adding &lt;code&gt;.btn-lg&lt;/code&gt; or &lt;code&gt;.btn-sm&lt;/code&gt; to your button tag. &lt;a href="https://getbootstrap.com/docs/5.3/components/buttons/" rel="noopener noreferrer"&gt;Bootstrap's button documentation&lt;/a&gt; provides information for more advanced button features and customization options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cards
&lt;/h3&gt;

&lt;p&gt;Bootstrap cards serve as modern, modular containers for displaying content. They offer a sleek and organized way to present a mix of images, text, links, and more. &lt;/p&gt;

&lt;p&gt;To create a Bootstrap card, you typically structure the card into different sections: the card header, body, and an optional footer for actions like buttons or links. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 32rem"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://source.unsplash.com/random/?nature&amp;amp;1"&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-img-top"&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h5&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Your Card Title Here&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro . . .
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Action Button&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above creates a basic card with an image at the top, followed by a title, text, and a button within the card body, as shown below: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg12-Bootstrap-card-component-image-title-text-button.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg12-Bootstrap-card-component-image-title-text-button.jpg" alt="Bootstrap Card Component Showing Image Above Title, Text, And Button"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Additionally, Bootstrap offers a card variant with image overlays, where the text is positioned over the image. This is particularly useful for creating more visually striking cards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card text-bg-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://source.unsplash.com/random/?dark&amp;amp;cover"&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-img"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-img-overlay"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h5&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Your Card Title Here&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
       Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro . . .
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;small&amp;gt;&lt;/span&gt;Last updated 3 mins ago&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above creates a card where the text content overlays the image, providing a more engaging and cohesive visual experience: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg13-Bootstrap-card-component-image-overlapping-text-content.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg13-Bootstrap-card-component-image-overlapping-text-content.png" alt="Bootstrap Card Component With Image Shown Underneath Overlapping Text Content"&gt;&lt;/a&gt; Bootstrap's card component demonstrates its flexibility and efficiency in web design, providing a complex yet easy-to-implement solution for displaying content in a structured and attractive way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Utility classes
&lt;/h3&gt;

&lt;p&gt;Bootstrap is more than just components and design elements. It also includes a comprehensive set of utility classes, providing flexibility in customizing layout and appearance. &lt;/p&gt;

&lt;p&gt;For example, you can use the &lt;code&gt;m-*&lt;/code&gt; classes for setting margins and the &lt;code&gt;p-*&lt;/code&gt; classes for padding. These classes follow a simple naming convention where the asterisk &lt;code&gt;*&lt;/code&gt; represents the size of the margin or padding. For instance, &lt;code&gt;m-3&lt;/code&gt; applies a moderate margin, and &lt;code&gt;p-2&lt;/code&gt; applies a smaller padding. &lt;/p&gt;

&lt;p&gt;Bootstrap also includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Utility classes for adjusting the width &lt;code&gt;w-*&lt;/code&gt; and height &lt;code&gt;h-*&lt;/code&gt; of elements&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;shadow-*&lt;/code&gt; classes, which come in handy for adding box shadows. These range from small (&lt;code&gt;shadow-sm&lt;/code&gt;) to large (&lt;code&gt;shadow-lg&lt;/code&gt;), allowing for varied levels of depth and emphasis on elements&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;position-*&lt;/code&gt; classes to quickly change the CSS position of an element. These include &lt;code&gt;static&lt;/code&gt;, &lt;code&gt;relative&lt;/code&gt;, &lt;code&gt;absolute&lt;/code&gt;, &lt;code&gt;fixed&lt;/code&gt;, and &lt;code&gt;sticky&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bootstrap's utility classes cover various functionalities, from display properties and text alignment to visibility and sizing. For a comprehensive list of all available utility classes and detailed explanations of their usage, the &lt;a href="https://getbootstrap.com/docs/5.3/getting-started/introduction/" rel="noopener noreferrer"&gt;Bootstrap documentation&lt;/a&gt; is a valuable resource.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessibility
&lt;/h3&gt;

&lt;p&gt;​​An often underappreciated yet crucial aspect of Bootstrap is its commitment to accessibility. Its interactive components are designed to work for touch, mouse, and keyboard users. Beyond this, Bootstrap also includes a range of classes specifically designed to make web content more accessible to the visually impaired. &lt;/p&gt;

&lt;p&gt;For example, Bootstrap provides a &lt;code&gt;.visually-hidden&lt;/code&gt; class to hide information intended only for screen readers from the page layout. This feature is particularly useful for visually impaired users for adding additional context or descriptions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-danger"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"visually-hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Danger: &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  This action is not reversible
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As demonstrated in the example above, the text &lt;code&gt;Danger&lt;/code&gt; will not be visible on the browser, but it will be captured by screen reader technologies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bootstrap icons
&lt;/h3&gt;

&lt;p&gt;In addition to its vast array of components and utility classes, Bootstrap also offers a rich library of icons. This library is designed to be generic and easy to incorporate, with elements such as arrows and user icons, as well as more specific symbols such as file types and tools. &lt;/p&gt;

&lt;p&gt;To use Bootstrap icons in your project, you must first include the icon library in your HTML markup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the icon library is linked, you can start referencing the icons in your HTML by using &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tags with the appropriate class names. Each icon has a unique class that starts with bi-, followed by the icon's name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bi bi-rocket-fill"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line of code will display a rocket icon from the Bootstrap icons library. It’s also worth mentioning that Bootstrap icons are SVGs, which means they scale well for all screen sizes and are customizable via CSS. &lt;/p&gt;

&lt;p&gt;Further reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/7-popular-icon-libraries-you-can-use-for-free/#bootstrapicons" rel="noopener noreferrer"&gt;7 popular icon libraries you can use for free — #3 Bootstrap Icons&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to customize Bootstrap
&lt;/h2&gt;

&lt;p&gt;One of the simplest methods for customizing Bootstrap is creating a new CSS file where you can override the default styling. This approach is particularly user-friendly for those who may not be familiar with Sass or are less comfortable with deeper code manipulations. &lt;/p&gt;

&lt;p&gt;To do this, link your custom CSS file after Bootstrap's stylesheet to ensure your custom styles take precedence over Bootstrap's default styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Link to Bootstrap CSS --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"path/to/bootstrap.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Your custom styles --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"path/to/your-stylesheet.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now redefine Bootstrap's classes in your CSS file to match your desired aesthetics. &lt;/p&gt;

&lt;p&gt;Furthermore, you can download &lt;a href="https://getbootstrap.com/docs/5.3/customize/sass/" rel="noopener noreferrer"&gt;Bootstrap's source Sass files&lt;/a&gt; for more in-depth customization and modify the Sass variables to suit your needs. This customization can range from changing the default color scheme to adjusting the global font size, &lt;code&gt;border-radius&lt;/code&gt; values, or even the &lt;code&gt;box-shadow&lt;/code&gt; intensity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="nt"&gt;Customizing&lt;/span&gt; &lt;span class="nt"&gt;primary&lt;/span&gt; &lt;span class="nt"&gt;color&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;primary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#yourCustomColor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="nt"&gt;Customizing&lt;/span&gt; &lt;span class="nt"&gt;border-radius&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;border-radius&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;25&lt;/span&gt;&lt;span class="nt"&gt;rem&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adjusting the variables, simply compile your Sass files to generate a new CSS file that will reflect all your customizations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use cases for Bootstrap
&lt;/h2&gt;

&lt;p&gt;Bootstrap's versatility makes it a go-to framework for a wide range of web development projects, ranging from creating simple landing pages to building complex, interactive dashboards: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg14-Example-project-types-Bootstrap.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg14-Example-project-types-Bootstrap.jpg" alt="Grid Showing Examples Of Project Types That Can Be Created With Bootstrap"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Furthermore, you can seamlessly integrate Bootstrap with JavaScript frameworks like React, Vue, and Capacitor to develop responsive mobile apps, expanding its usage beyond traditional web applications. &lt;/p&gt;

&lt;p&gt;Below is an example of a mobile page I designed with Bootstrap, complemented with custom CSS for additional styling: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg15-Demo-mobile-page-designed-Bootstrap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fimg15-Demo-mobile-page-designed-Bootstrap.png" alt="Demo Of A Mobile Page Designed Using Bootstrap"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;If you're looking for inspiration or want to learn more about the framework's possibilities, you can check out resources like &lt;a href="https://www.awwwards.com/websites/bootstrap/" rel="noopener noreferrer"&gt;Awwward's best Bootstrap websites&lt;/a&gt; and the &lt;a href="https://themes.getbootstrap.com/" rel="noopener noreferrer"&gt;official Bootstrap themes&lt;/a&gt; web page, which has options for free and paid templates.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comparing Bootstrap with Tailwind, MUI, and Bulma
&lt;/h2&gt;

&lt;p&gt;While Bootstrap is an all-around excellent option for styling applications, other popular CSS libraries like Tailwind CSS, Material UI (MUI), and Bulma also offer unique strengths and ideal use cases. &lt;/p&gt;

&lt;p&gt;For example, Bootstrap is known for its quick-start capabilities, offering pre-designed components for rapid development. &lt;/p&gt;

&lt;p&gt;In contrast, Tailwind CSS focuses on utility-first CSS, providing more granular control over styling, while MUI is known for its Material Design components. Similarly, Bulma stands out for its simplicity and usage of Flexbox, providing a modern, minimalist approach that prioritizes responsiveness and ease of use.&lt;/p&gt;

&lt;p&gt;Below is a table comparing key points to help you quickly choose from these frameworks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Factor&lt;/th&gt;

&lt;th&gt;Bootstrap&lt;/th&gt;

&lt;th&gt;Tailwind CSS&lt;/th&gt;

&lt;th&gt;Material UI (MUI)&lt;/th&gt;

&lt;th&gt;Bulma&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;Design philosophy&lt;/td&gt;

&lt;td&gt;Pre-built components and styles; grid system for layout&lt;/td&gt;

&lt;td&gt;Utility-first, low-level utility classes for custom designs&lt;/td&gt;

&lt;td&gt;Pre-built components and styles based on Google’s Material Design&lt;/td&gt;

&lt;td&gt;Flexbox-based, simple, with some pre-built components&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Predefined styles&lt;/td&gt;

&lt;td&gt;Many predefined styles and components&lt;/td&gt;

&lt;td&gt;No predefined styles; utility classes for custom designs&lt;/td&gt;

&lt;td&gt;Predefined styles and components following Material Design&lt;/td&gt;

&lt;td&gt;Basic components and elements; focuses on layout&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Customization&lt;/td&gt;

&lt;td&gt;Global customization using Sass or theme variables&lt;/td&gt;

&lt;td&gt;Utility-first approach for specific style customization&lt;/td&gt;

&lt;td&gt;Global customization using theme variables&lt;/td&gt;

&lt;td&gt;Customizable via Sass variables&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Learning curve&lt;/td&gt;

&lt;td&gt;Relatively low, easy to start&lt;/td&gt;

&lt;td&gt;Steeper, requires learning utility classes&lt;/td&gt;

&lt;td&gt;Moderate, requires understanding of prebuilt components and customization&lt;/td&gt;

&lt;td&gt;Easier due to simplicity and layout focus&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Speed of development&lt;/td&gt;

&lt;td&gt;Quick with prebuilt components&lt;/td&gt;

&lt;td&gt;Quick for custom designs, but requires understanding of utility classes&lt;/td&gt;

&lt;td&gt;Quick with many prebuilt components&lt;/td&gt;

&lt;td&gt;Balanced with ready-to-use components and layout options&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Accessibility&lt;/td&gt;

&lt;td&gt;Good, but varies with implementation&lt;/td&gt;

&lt;td&gt;Manual effort required for accessibility&lt;/td&gt;

&lt;td&gt;Good adherence to accessibility standards&lt;/td&gt;

&lt;td&gt;Good, varies with implementation&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For an in-depth comparison of Bootstrap, Tailwind CSS, and MUI, check out the following LogRocket article: &lt;a href="https://blog.logrocket.com/comparing-bootstrap-vs-tailwind-css-vs-material-ui-mui/" rel="noopener noreferrer"&gt;Comparing Bootstrap vs. Tailwind CSS vs. Material UI (MUI)&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Further reading:&lt;/em&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/comparing-tailwind-css-bootstrap-time-ditch-ui-kits/" rel="noopener noreferrer"&gt;Comparing Tailwind CSS to Bootstrap: Is it time to ditch UI kits?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.logrocket.com/bulma-vs-tailwind-css-better-bootstrap-alternative/" rel="noopener noreferrer"&gt;Bulma vs. Tailwind CSS: Which is the better Bootstrap alternative?&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Throughout this article, we've explored Bootstrap's core features, adaptability in various projects, and customizability. We also compared it to frameworks like Tailwind CSS and Material UI. &lt;/p&gt;

&lt;p&gt;Bootstrap stands out as a user-friendly, versatile framework, perfect for quick development and offering extensive customization for unique design needs. Its ease of use, supportive community, and comprehensive documentation make it reliable for creating responsive, modern applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get set up with LogRocket's modern error tracking in minutes:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://logrocket.com/signup/" rel="noopener noreferrer"&gt;https://logrocket.com/signup/&lt;/a&gt; to get an app ID.&lt;/li&gt;
&lt;li&gt;Install LogRocket via NPM or script tag. &lt;code&gt;LogRocket.init()&lt;/code&gt; must be called client-side, not server-side.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save&lt;/span&gt; logrocket 

// Code:

import LogRocket from &lt;span class="s1"&gt;'logrocket'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
LogRocket.init&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app/id'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Script Tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.lr-ingest.com/LogRocket.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.(Optional) Install plugins for deeper integrations with your stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Redux middleware&lt;/li&gt;
&lt;li&gt;  ngrx middleware&lt;/li&gt;
&lt;li&gt;  Vuex plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/signup" rel="noopener noreferrer"&gt;Get started now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bootstrap</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using Deno with Jupyter Notebook to build a data dashboard</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Wed, 17 Jan 2024 19:09:20 +0000</pubDate>
      <link>https://dev.to/logrocket/using-deno-with-jupyter-notebook-to-build-a-data-dashboard-5aoe</link>
      <guid>https://dev.to/logrocket/using-deno-with-jupyter-notebook-to-build-a-data-dashboard-5aoe</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/agustinustheodorus/" rel="noopener noreferrer"&gt;Agustinus Theodorus&lt;br&gt;
&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this guide, we will explore building a data analysis dashboard using Deno and Jupyter Notebook. Recently, the Deno team announced compatibility with Jupyter Notebook, allowing users to leverage the power and flexibility of Deno for their data analysis workflows by using Deno as a kernel within their Jupyter Notebook.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction to the Deno and Jupyter Notebook integration
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://blog.logrocket.com/what-is-deno/" rel="noopener noreferrer"&gt;Deno is a modern JavaScript runtime&lt;/a&gt; for server-side and client-side applications. Even though you can still run pure JavaScript, Deno provides built-in support for TypeScript. &lt;/p&gt;

&lt;p&gt;Deno uses strict type checking by default, as the TypeScript development team recommends, leading to a more type-safe environment. The main theme behind Deno is to provide a more secure runtime environment and a module system with explicit dependencies. &lt;/p&gt;

&lt;p&gt;Jupyter Notebook is a tool to help you visualize and analyze data interactively and collaboratively. You don’t need to run code from a console, and you can run the code directly within the notebook cells, making it easier to visualize, experiment, and iterate on data analysis tasks. &lt;/p&gt;

&lt;p&gt;This integration opens up new possibilities for data scientists and analysts, giving them access to Deno’s modern JavaScript runtime and its extensive module ecosystem that can import existing npm packages.&lt;/p&gt;
&lt;h3&gt;
  
  
  Jupyter Notebook: A gateway to data science
&lt;/h3&gt;

&lt;p&gt;Jupyter Notebook has become the go-to tool for data scientists to explore and understand data. &lt;/p&gt;

&lt;p&gt;These notebooks provide a convenient way to combine code, execute it, and show visualizations and explanatory text in a single document. This combination makes it easier to use Jupyter Notebook as a collaboration tool among data scientists, allowing for knowledge sharing and reproducibility in data analysis workflows. &lt;/p&gt;

&lt;p&gt;Jupyter Notebook supports multiple languages, including Python, R, Rust, Julia, and Deno. This wide language support makes it easy for data scientists to work with the suitable programming language of their choice, depending on the nature of their data analysis tasks and preferred tools. One of the main goals behind using a notebook is to iterate quickly and use interactive computing effectively for data exploration and analysis. &lt;/p&gt;

&lt;p&gt;Interactive computing allows data scientists to execute code and iterate on it directly without the hassle of using command lines or traditional code execution environments. Compared to executing code via a terminal or debugger, testing code and iterating on data analysis tasks in Jupyter Notebook is exceptionally easier.&lt;/p&gt;
&lt;h3&gt;
  
  
  Exploring data science libraries in Deno
&lt;/h3&gt;

&lt;p&gt;The benefit of using Deno is that you can access modern JavaScript libraries available within the Node and npm ecosystem. There are already a lot of powerful libraries for data science and data visualization in npm, and you can plug and play these libraries in your Deno-powered Jupyter Notebook. &lt;/p&gt;

&lt;p&gt;Here are a few examples of popular data science libraries in Deno that you‘ll interact with in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/d3/d3" rel="noopener noreferrer"&gt;&lt;strong&gt;D3.js&lt;/strong&gt;&lt;/a&gt;: A robust library to visualize your data and create interactive data-driven visualizations.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/observablehq/plot" rel="noopener noreferrer"&gt;&lt;strong&gt;Observable Plot&lt;/strong&gt;&lt;/a&gt;: A library built on top of D3.js used to visualize data and iterate more quickly on different plot chart&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/pola-rs/nodejs-polars" rel="noopener noreferrer"&gt;&lt;strong&gt;Polars&lt;/strong&gt;&lt;/a&gt;: A blazingly fast DataFrame library written in Rust for data manipulation and analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a foundational understanding of Deno and Jupyter Notebook established, let’s delve into how to set up your environment to start building robust data analysis dashboards.&lt;/p&gt;
&lt;h2&gt;
  
  
  Preparing your environment
&lt;/h2&gt;

&lt;p&gt;To prepare your environment, you must install both Deno and Jupyter. Assuming you’re using macOS/Linux, you can install Deno using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://deno.land/x/install/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, ensure you have Python 3.x and pip installed. Jupyter Notebook is written in Python, so you will need pip to install it by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;jupyterlab notebook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test run your local Notebook server by executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jupyter notebook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command above will run a Jupyter Notebook local server: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fjupyter-notebook-local-server.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fjupyter-notebook-local-server.png" alt="Screenshot of Jupyter Notebook Running on Local Server"&gt;&lt;/a&gt; If everything is set up correctly, you should see the Jupyter Notebook interface launching in your browser on &lt;code&gt;http://localhost:8888/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compiling and running TypeScript in Jupyter with Deno
&lt;/h3&gt;

&lt;p&gt;To use Deno in your notebook, you must have the Deno kernel installed. First, you can test run your Deno kernel by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deno jupyter &lt;span class="nt"&gt;--unstable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the kernel is already installed, you should receive a return message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&amp;lt;output&amp;gt;✅ Deno kernel already installed.
&amp;lt;/output&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise, if you haven’t installed the kernel yet, run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deno jupyter &lt;span class="nt"&gt;--unstable&lt;/span&gt; &lt;span class="nt"&gt;--install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will ensure you have installed the most recent Deno kernel for your local Jupyter Notebook.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;N.B.&lt;/strong&gt;, while the Deno kernel is already shipped with the most recent version, it is still marked as unstable. This means that there may be some bugs or issues that could arise while using the Deno kernel in Jupyter Notebook.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you have Deno and Jupyter Notebook configured, you can start building your data analysis dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a data analysis dashboard with Deno and Jupyter Notebook
&lt;/h2&gt;

&lt;p&gt;To help you understand how the new Deno kernel works, it’s better if we do a basic data visualization exercise using Jupyter Notebook and Deno. &lt;/p&gt;

&lt;p&gt;You will build a financial data dashboard that analyzes your income and expenses. This dashboard will provide visualizations and insights into your financial data, helping you understand your expenses over time and make informed financial decisions. It will also allow you to track your net income and identify trends. &lt;/p&gt;

&lt;p&gt;Here is a sample dataset of what the data would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Date,Income,Expenses,NetIncome,BudgetIncome,ActualIncome,BudgetExpenses,ActualExpenses,Salaries,R&amp;amp;D,Marketing,Utilities,Rent,Equipment,Software,Hardware,Consulting,Office Supplies,DiffIncome,DiffExpenses
2022-01-01,281,218,63,284,281,221,218,41,24,45,43,22,35,2,2,2,2,3,3
2022-01-02,328,244,84,323,328,240,244,46,45,34,35,31,37,1,4,8,3,-5,-4
2022-01-03,266,223,43,269,266,222,223,31,49,38,30,22,40,2,6,1,4,3,-1
2022-01-04,287,226,61,279,287,229,226,43,47,31,48,21,26,5,1,3,1,-8,3
2022-01-05,307,214,93,309,307,217,214,48,37,40,23,34,20,1,3,4,4,2,3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dataset for the dashboard is publicly available &lt;a href="https://gist.githubusercontent.com/agustinustheo/195f32a4a6c68c493056c883d959ca35/raw/c7363d8b916ab00a2d1747adb89fca120da29f42/mock_financial_data.csv" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing the right tools for data visualization
&lt;/h3&gt;

&lt;p&gt;In addition to D3.js, Observable Plot, and Polars, mentioned above, you‘ll also use the following packages for this exercise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/samizdatco/skia-canvas" rel="noopener noreferrer"&gt;Skia Canvas&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://deno.land/x/display@v0.1.1/mod.ts" rel="noopener noreferrer"&gt;&lt;code&gt;display&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’ll use Skia Canvas to create a canvas for rendering the data visualizations, &lt;code&gt;display&lt;/code&gt; to render the plot on the canvas, &lt;a href="https://blog.logrocket.com/creating-visualizations-d3-typescript/" rel="noopener noreferrer"&gt;D3 for data visualization&lt;/a&gt;, Observable Plot for creating interactive plots, and Polars to load the data into DataFrames.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the dashboard
&lt;/h3&gt;

&lt;p&gt;You can start by importing the necessary libraries and modules in your Jupyter Notebook to build the financial data dashboard. Begin by importing the &lt;code&gt;nodejs-polars&lt;/code&gt; library and the &lt;code&gt;display&lt;/code&gt; module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pl&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm:nodejs-polars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/x/display@v0.1.1/mod.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you import the required libraries, you can start fetching the sample dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://gist.githubusercontent.com/agustinustheo/195f32a4a6c68c493056c883d959ca35/raw/c7363d8b916ab00a2d1747adb89fca120da29f42/mock_financial_data.csv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readCSV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sep&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integrating D3 with Deno for advanced visualizations
&lt;/h3&gt;

&lt;p&gt;Integrating different types of visualizations, such as line charts, bar charts, and pie charts, to effectively showcase your financial data trends and patterns over time. &lt;/p&gt;

&lt;p&gt;To start visualizing your data, you can use the D3.js library. Import it with the &lt;code&gt;skia_canvas&lt;/code&gt; module to create a canvas to render the chart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm:d3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createCanvas&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/x/skia_canvas/mod.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have imported the necessary libraries, you can build your data visualization using D3. You will build a simple pie chart to track the percentage of expenses. Get the tail end of the data using &lt;code&gt;df.tail(1).toRecords()[0]&lt;/code&gt; and then print the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastDataPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toRecords&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastDataPoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create the sample data by selecting the necessary columns from the DataFrame and converting them into a format suitable for a pie chart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Salaries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;R&amp;amp;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Marketing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Utilities&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Equipment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Software&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hardware&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Consulting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Office Supplies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Sample data&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sampleData1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;sampleData1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lastDataPoint&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can create a canvas and use D3 to render the pie chart. Here’s an example of how you can achieve this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create a pie function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pie&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create an arc generator for the slices&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;innerRadius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;outerRadius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create an arc generator for the labels&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;labelArc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;innerRadius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Adjust to position the labels&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;outerRadius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create the canvas&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCanvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Translate to center the pie chart&lt;/span&gt;
&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Draw the pie chart&lt;/span&gt;
&lt;span class="nf"&gt;pie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sampleData1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Draw the slice&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginPath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;schemeCategory10&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Draw the label&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Label color&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textAlign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textBaseline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;middle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;centroid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;labelArc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;centroid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;centroid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;centroid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Display the canvas&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fexpense-data-pie-chart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fexpense-data-pie-chart.png" alt="Expense Data Rendered as a Pie Chart"&gt;&lt;/a&gt; In the code snippet above, we visualized the percentage distribution of your expenses in a simple pie chart. This is just one example of how you can use D3 to visualize your data in Jupyter Notebook.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Observable Plot for rapid iteration
&lt;/h3&gt;

&lt;p&gt;To further enhance the data visualization capabilities in Jupyter Notebook, consider using Observable Plot. Compared to D3, it has a significantly lower learning curve — you don’t need to write custom functions to render visuals. You can use &lt;code&gt;Plot&lt;/code&gt; and define the type of chart you want to start rendering. &lt;/p&gt;

&lt;p&gt;Start by importing the necessary dependencies, initializing your document canvas, and defining the records you want to show:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Plot&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm:@observablehq/plot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DOMParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SVGElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm:linkedom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DOMParser&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;parseFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;html lang="en"&amp;gt;&amp;lt;/html&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toRecords&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@observablehq/plot&lt;/code&gt; library doesn’t rely on &lt;code&gt;skia_canvas&lt;/code&gt; to render the charts. In the example above, we are using a regular HTML document. &lt;/p&gt;

&lt;p&gt;Now, you will make a line chart for your net income. It will appear as though the net income has no significant trend, but rest assured, it’s expected — the data is randomized:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;convertedArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;NetIncome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NetIncome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;Plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;band&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;marks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;Plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;convertedArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NetIncome&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnet-income-line-chart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnet-income-line-chart.png" alt="Net Income Rendered as a Line Chart"&gt;&lt;/a&gt; Judging by how the line chart looks, &lt;code&gt;@observablehq/plot&lt;/code&gt; gives you a more refined template compared with D3, where you have to do things from scratch. &lt;/p&gt;

&lt;p&gt;Now, let’s continue visualizing the expenses. Remember the pie chart? Let’s make a stacked bar chart showing the expenses over some time with a clear visual of what kind of expenses account for the most spend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sampleData2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentCategory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;sampleData2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentRecord&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
      &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentCategory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentRecord&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currentCategory&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;Plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;band&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;marks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;Plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;barY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sampleData2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;category&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="nx"&gt;Plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ruleY&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fexpenses-over-time-stacked-bar-chart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fexpenses-over-time-stacked-bar-chart.png" alt="Expenses Over Time Rendered as a Stacked Bar Chart"&gt;&lt;/a&gt; In the code snippets above, the &lt;code&gt;@observablehq/plot&lt;/code&gt; library creates two visualizations: a line chart for net income and a stacked bar chart for expenses over time. Both charts are created using the &lt;code&gt;Plot.plot&lt;/code&gt; function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;You‘ve finished creating the financial dashboard using Jupyter Notebook and Deno! &lt;/p&gt;

&lt;p&gt;You have effectively utilized D3 and Observable Plot to create advanced visualizations of your financial data in Jupyter Notebook using Deno. By incorporating D3, you could create a simple and clear visualization of your expenses in the form of a pie chart. &lt;/p&gt;

&lt;p&gt;Additionally, you used Observable Plot to generate a line chart for net income and a stacked bar chart illustrating expenses over time. This library provides a more refined template with minimal effort, making it perfect for rapid iterations and prototyping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional use cases and examples
&lt;/h2&gt;

&lt;p&gt;In addition to our example above, where we created a financial dashboard, this section will cover some other case studies demonstrating how to use Deno with Jupyter Notebook for data analysis and dashboard design.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case #1: Statistical model dashboard
&lt;/h3&gt;

&lt;p&gt;You can make statistical models to predict future trends or analyze data patterns using Jupyter Notebook and Deno. Jupyter Notebook is very popular in machine learning, mainly used in tandem with Python to create interactive notebooks for training models and experiments with different algorithms. &lt;/p&gt;

&lt;p&gt;The only difference here is that Deno uses TypeScript and does not offer the same number of open source data science libraries as Python. While Deno benefits greatly from being cross-compatible with npm, it still isn’t as robust with respect to ML libraries. &lt;/p&gt;

&lt;p&gt;However, you can still utilize libraries such as Polar and &lt;code&gt;scikitjs&lt;/code&gt; in Deno to perform statistical modeling tasks, and its integration with Jupyter Notebook makes it a powerful tool for building a statistical model dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case #2: Data cleaning and transformation
&lt;/h3&gt;

&lt;p&gt;Data cleaning and transformation are common tasks in data analysis, and the combination of Jupyter Notebook and Deno can streamline the process. Jupyter Notebooks provides an interactive environment where you can write and execute code for data cleaning and transformation using Deno. &lt;/p&gt;

&lt;p&gt;Using the aforementioned libraries for processing data, along with Deno’s built-in modules such as &lt;code&gt;fs&lt;/code&gt;, you can easily read, manipulate, and transform data in Jupyter Notebook using Deno. &lt;/p&gt;

&lt;p&gt;Most of the code within this guide is used for data processing. Data engineers benefit from using Jupyter Notebook because it gives them a quick and easy environment to perform data cleaning and transformation, allowing them to iterate faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion, further reading, and resources
&lt;/h2&gt;

&lt;p&gt;Jupyter Notebook is a platform that facilitates interactive, collaborative data visualization and analysis. It is possible to execute code directly within notebook cells, eliminating the requirement for a console, which accelerates task iteration. &lt;/p&gt;

&lt;p&gt;Together with Deno, Jupyter Notebook can simplify data analysis activities like data transformation and cleansing. With this integration, data scientists and analysts now have access to Deno’s modern, secure JavaScript runtime and vast module ecosystem, allowing them to import existing npm packages. &lt;/p&gt;

&lt;p&gt;To learn more about using Jupyter Notebook with Deno for data analysis and building dashboards, you can refer to the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://deno.com/blog/v1.37" rel="noopener noreferrer"&gt;Deno 1.37: Modern JavaScript in Jupyter Notebooks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://docs.deno.com/runtime/manual/tools/jupyter" rel="noopener noreferrer"&gt;Jupyter Kernel for Deno documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some notable packages for data analysis with Jupyter Notebooks and Deno:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/pola-rs/nodejs-polars" rel="noopener noreferrer"&gt;Polars&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/d3/d3" rel="noopener noreferrer"&gt;D3.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/observablehq/plot" rel="noopener noreferrer"&gt;Observable Plot&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/javascriptdata/scikit.js" rel="noopener noreferrer"&gt;scikit.js&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leveraging the potential of Deno in conjunction with Jupyter Notebook will undoubtedly enhance your data analysis practices and open up further opportunities for advanced visualization and modeling quickly and more efficiently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get set up with LogRocket's modern error tracking in minutes:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://logrocket.com/signup/" rel="noopener noreferrer"&gt;https://logrocket.com/signup/&lt;/a&gt; to get an app ID.&lt;/li&gt;
&lt;li&gt;Install LogRocket via NPM or script tag. &lt;code&gt;LogRocket.init()&lt;/code&gt; must be called client-side, not server-side.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save&lt;/span&gt; logrocket 

// Code:

import LogRocket from &lt;span class="s1"&gt;'logrocket'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
LogRocket.init&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app/id'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Script Tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.lr-ingest.com/LogRocket.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.(Optional) Install plugins for deeper integrations with your stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Redux middleware&lt;/li&gt;
&lt;li&gt;  ngrx middleware&lt;/li&gt;
&lt;li&gt;  Vuex plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/signup" rel="noopener noreferrer"&gt;Get started now&lt;/a&gt;&lt;/p&gt;

</description>
      <category>deno</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Analog.js vs. Next.js vs. SolidStart: Comparing modern meta-frameworks</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Wed, 17 Jan 2024 16:01:13 +0000</pubDate>
      <link>https://dev.to/logrocket/analogjs-vs-nextjs-vs-solidstart-comparing-modern-meta-frameworks-29g5</link>
      <guid>https://dev.to/logrocket/analogjs-vs-nextjs-vs-solidstart-comparing-modern-meta-frameworks-29g5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/claraekekenta/" rel="noopener noreferrer"&gt;Clara Ekekenta&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The meta-framework has been gaining lots of traction recently due to its ability to extend base frameworks, giving developers advanced and simplified tools to aid their development process. &lt;/p&gt;

&lt;p&gt;In this tutorial, we'll dive into the three notable meta-frameworks that are all built on existing JavaScript frameworks: Analog.js for Angular, Next.js for React, and SolidStart for SolidJS. We'll look at each of these frameworks, highlighting their similarities and unique features in terms of usability, ease of use, and performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The modern meta-frameworks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Analog.js
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://analogjs.org" rel="noopener noreferrer"&gt;Analog.js&lt;/a&gt; is a new framework built on top of the Angular framework that is known for its robustness in building enterprise-level applications. Analog.js extends the features of Angular.js, offering an enhanced development experience. It streamlines common Angular development tasks, integrates advanced build optimizations, and provides a more intuitive way of building Angular applications. This framework focuses on improving development speed and simplifying complex Angular concepts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://blog.logrocket.com/build-server-rendered-react-app-next-express/#what-next-js" rel="noopener noreferrer"&gt;Next.js is a popular React meta-framework&lt;/a&gt; known for its server-side rendering capabilities and quick build mechanism. It makes it easier for developers to build scalable and highly performant web apps by handling routing, page layout, and server-side rendering in React applications. Next.js also has features that improve the performance and speed of React applications, such as automatic code splitting and static site generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  SolidStart
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://blog.logrocket.com/getting-started-solidstart-solid-js-framework/" rel="noopener noreferrer"&gt;SolidStart is an advanced version of SolidJS&lt;/a&gt;. It improves SolidJS by providing a standardized way to build applications with a better application structure, improved server rendering functionalities, and a suite of development tools that make it easier to develop fast and reactive web apps. It is intended to make the most of SolidJS's features, providing an efficient and streamlined development process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analog.js vs. Next.js vs. SolidStart
&lt;/h2&gt;

&lt;p&gt;Analog.js, Next.js, and SolidStart are all built upon existing JavaScript frameworks to provide additional features for improved developer experience and application performance. These meta-frameworks share common functionalities that make them powerful tools for modern web development. &lt;/p&gt;

&lt;p&gt;All three meta-frameworks support server-side rendering (SSR) for better SEO and faster initial load times, as well as static site generation (SSG) for improved performance. Analog.js, Next.js, and SolidStart offer features like dynamic routing with data fetching capabilities, enabling rich and interactive user experiences. Each of these meta-frameworks also has API routes to allow the implementation of API endpoints, with code splitting capabilities aimed at optimizing load times by only sending the necessary code for each page or component. &lt;/p&gt;

&lt;p&gt;To further understand the similarities and strengths of each meta-framework, let’s compare them in terms of improved usability, ease of use, and performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usability
&lt;/h3&gt;

&lt;p&gt;Frameworks that have good usability make complex tasks simpler and more intuitive. They also have accessible and easy-to-understand concepts, which is particularly important to new developers. &lt;/p&gt;

&lt;p&gt;The usability of Next.js is enhanced through its file-system-based routing and automatic code splitting features. SolidStart improves its usability by providing a straightforward approach to reactive programming, which simplifies state management. Analog.js improves its usability by streamlining complex Angular.js tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ease of use
&lt;/h3&gt;

&lt;p&gt;Ease of use is an important factor for rapid development and adoption. An easy-to-use framework reduces the time spent on boilerplate code and debugging and enables developers to start a new project quickly with minimal configuration, leaving more time for focusing on building the app's features. &lt;/p&gt;

&lt;p&gt;Next.js addresses ease of use by offering a developer-friendly setup with minimal configuration required to start a new project. SolidStart is a minimalistic framework that is easier for new developers to use. Both Next.js and SolidStart promote their ease of use or adoption, but this is one of Analog.js's unique selling points due to the intuitive way it handles the complexities of Angular applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Performance is a framework’s most important feature, enabling developers to build applications that are user friendly and have improved SEO. Frameworks that offer &lt;a href="https://blog.logrocket.com/implementing-ssr-next-js-dynamic-routing-prefetching/" rel="noopener noreferrer"&gt;efficient, server-side rendering&lt;/a&gt; enable webpages to load faster and provide an enhanced user experience. &lt;/p&gt;

&lt;p&gt;Next.js is optimized for performance, offering automatic server-side rendering and static generation features. It uses a feature called Lazy to improve component load times. SolidStart offers a rendering mechanism, especially in updating the DOM, that aids in the development of performant applications. Analog.js is built on top of Angular.js; it offers performance improvements in areas like change detection and component rendering. &lt;/p&gt;

&lt;p&gt;Let’s take a look at Analog.js, Next.js, and SolidStart in action by creating sample projects to demonstrate the uniqueness of each framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a basic project in Analog.js
&lt;/h2&gt;

&lt;p&gt;The Analog.js framework aims for a guided and structured approach, making it easier for beginner developers to create a project. To get started, let’s run the following command to scaffold a new Analog.js application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create analog@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command prompts us to select our preferred configuration for the project without having to manually set it up. Our sample app is a blog project, so our selection will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ Project name: … analog-project
✔ Select a template: › Analog
✔ Select a variant: › blog
✔ Would you like to add Tailwind to your project? … yes

Scaffolding project in /Users/ekekentaodionyenfe/comparison/analog-project...
Initializing git repository:

Done. Now run:

  cd analog-project
  npm install
  npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ve successfully created a simple blog project! All we need to do now is change the directory into the project folder, install the required packages, and run the application with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;analog-project
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fanalog-js-sample-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fanalog-js-sample-app.png" alt="Analog.js Sample App"&gt;&lt;/a&gt; Let’s look at the performance of our Analog.js project: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fanalog-js-app-devtools-performance.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fanalog-js-app-devtools-performance.png" alt="Analog.js App DevTools Performance"&gt;&lt;/a&gt; According to Chrome DevTools, our Analog.js application took &lt;code&gt;3ms&lt;/code&gt; to load and &lt;code&gt;28ms&lt;/code&gt; to render the components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a basic project in Next.js
&lt;/h2&gt;

&lt;p&gt;Now, let’s build a project in Next.js. To get started, we’ll run the command below to create a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to the Analog.js framework, Next.js prompts us to select our preferred configurations for our project. After running the &lt;code&gt;create-next-app&lt;/code&gt; command, our selection looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ What is your project named? … my-app
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
Creating a new Next.js app in /Users/ekekentaodionyenfe/comparison/my-app.

Using npm.

Initializing project with template: app-tw 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Next.js framework leans toward flexibility and customization, enabling developers to build application architecture without being confined to a specific template. This is why we aren’t prompted to select a particular variant or template to work with. &lt;/p&gt;

&lt;p&gt;Now, let’s change directory into the project folder and start the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnext-js-sample-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnext-js-sample-app.png" alt="Next.js Sample App"&gt;&lt;/a&gt; Now, let’s use Chrome DevToolslook at the performance of our Next.js application: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnext-js-app-devtools-performance.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fnext-js-app-devtools-performance.png" alt="Next.js App DevTools Performance"&gt;&lt;/a&gt; Our Next.js application took &lt;code&gt;1ms&lt;/code&gt; for initial load and &lt;code&gt;6ms&lt;/code&gt; to render the components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a basic project in SolidStart
&lt;/h2&gt;

&lt;p&gt;SolidStart takes a guided approach similar to that of the Analog.js framework but gives developers access to more templates to choose from. To see the SolidStart framework in action, let’s build a simple project. &lt;/p&gt;

&lt;p&gt;To get started, we’ll run the below command to create a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init solid@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s the preferred configurations for our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bare
hackernews
with-auth
with-mdx
with-tailwindcss
with-vitest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this tutorial, our selection looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ Where do you want to create the app? … my-app-new
✔ Which template do you want to use? › notes
✔ Server Side Rendering? … yes
✔ Use TypeScript? … yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s change directory into the project folder, install the required dependencies, and run the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-app-new
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--open&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fsolidstart-sample-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fsolidstart-sample-app.png" alt="SolidStart Sample App"&gt;&lt;/a&gt; Let’s look at the performance of our SolidStart app: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fsolidstart-app-devtools-performance.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2024%2F01%2Fsolidstart-app-devtools-performance.png" alt="SolidStart App DevTools Performance"&gt;&lt;/a&gt; According to Chrome DevTools, our SolidStart application took &lt;code&gt;0ms&lt;/code&gt; for initial load and &lt;code&gt;10ms&lt;/code&gt; to render the components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you choose Analog.js, Next.js, or SolidStart?
&lt;/h2&gt;

&lt;p&gt;Analog.js, Next.js, and SolidStart are all excellent options for easily building well-optimized applications. &lt;/p&gt;

&lt;p&gt;If you're already comfortable using React, Next.js is a strong choice. It's widely used and well-supported, making it a good option for developers who want to build fast, SEO-friendly websites. It also provides features like server-side rendering, which helps pages load faster and improves their visibility on search engines. This meta-framework can be used to build both small and complex web applications. &lt;/p&gt;

&lt;p&gt;SolidStart is an exciting option to consider if you're looking to explore new web technologies. It is built on SolidJS, which is known for its simplicity and efficiency. &lt;/p&gt;

&lt;p&gt;If performance is a top priority for your application, SolidStart could be the right choice. However, as of this writing, SolidStart is still relatively new and in beta, so you could encounter bugs or limited resources. &lt;/p&gt;

&lt;p&gt;If you are already using Angular, but are looking for an upgrade, Analog.js could be your best choice to streamline some of Angular's more complex tasks and simplify its use. A potential tradeoff is that Analog.js has a smaller user community and fewer resources compared to more established frameworks like Next.js and the emerging SolidStart. &lt;/p&gt;

&lt;p&gt;Ultimately, your choice should align with the technologies you're comfortable with, the size and nature of your project, and your specific performance and usability needs. Next.js is a safe, well-trodden path ( especially for React developers), SolidStart offers a fresh approach with a focus on performance, and Analog.js might suit you if you're looking to enhance your Angular experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we examined three meta-frameworks: Analog.js, Next.js and SolidStart. We compared their similarities, strengths, and weaknesses in terms of ease of use, performance, and usability. We also created a sample project using each meta-framework to demonstrate how they work and compare their performance. &lt;/p&gt;

&lt;p&gt;To learn more about these frameworks, visit their official documentation pages: &lt;a href="https://analogjs.org/docs" rel="noopener noreferrer"&gt;Analog.js docs&lt;/a&gt;, &lt;a href="https://nextjs.org/docs" rel="noopener noreferrer"&gt;Next.js docs&lt;/a&gt;, and &lt;a href="https://start.solidjs.com/getting-started/what-is-solidstart" rel="noopener noreferrer"&gt;SolidStart docs&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I hope you’ve enjoyed this journey as much as I have. See you in the next one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Are you adding new JS libraries to improve performance or build new features? What if they’re doing the opposite?
&lt;/h2&gt;

&lt;p&gt;There’s no doubt that frontends are getting more complex. As you add new JavaScript libraries and other dependencies to your app, you’ll need more visibility to ensure your users don’t run into unknown issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/javascript-signup" rel="noopener noreferrer"&gt;LogRocket&lt;/a&gt; is a frontend application monitoring solution that lets you replay JavaScript errors as if they happened in your own browser so you can react to bugs more effectively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/javascript-signup" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qyd7ce70lj6nh0b0uv4.png" alt="LogRocket Signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/javascript-signup" rel="noopener noreferrer"&gt;LogRocket&lt;/a&gt; works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app’s performance, reporting metrics like client CPU load, client memory usage, and more.&lt;/p&gt;

&lt;p&gt;Build confidently — &lt;a href="https://lp.logrocket.com/blg/javascript-signup" rel="noopener noreferrer"&gt;start monitoring for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Angular signals vs. observables: How and when to use each</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Tue, 16 Jan 2024 18:53:25 +0000</pubDate>
      <link>https://dev.to/logrocket/angular-signals-vs-observables-how-and-when-to-use-each-14ec</link>
      <guid>https://dev.to/logrocket/angular-signals-vs-observables-how-and-when-to-use-each-14ec</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/lewiscianci/"&gt;Lewis Cianci&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://blog.logrocket.com/exploring-angular-evolution/#introducing-signals"&gt;new signals feature introduced in Angular 16&lt;/a&gt; is an exciting update to how we handle async operations. However, observables already exist in Angular — so why should we care about signals? &lt;/p&gt;

&lt;p&gt;As developers, we kind of have a love/hate relationship with learning new things. It’s great when new updates, features, or software can help us solve problems and code better. On the other hand, with so much software development information already out there, learning yet another new thing can be overwhelming. &lt;/p&gt;

&lt;p&gt;It’s critical to get straight to the point about why something matters so we can avoid missing out on the possible benefits. Let’s do that now by exploring why signals and observables each exist in Angular, along with how and when to use each.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the role of signals and observables in Angular
&lt;/h2&gt;

&lt;p&gt;The first question we have to answer is, what issues do signals and observables set out to solve? And the answer is simple: asynchronous operations. &lt;/p&gt;

&lt;p&gt;Sometimes, when we request data or carry out an operation, the result may change over time. When this happens, we can refer to the source of these events as the emitter. When the emitter updates the value, subscribers can receive the new value. &lt;/p&gt;

&lt;p&gt;To make it easier for us to understand, let’s consider a practical example. Imagine that our application receives real-time data from a WebSocket. In this simple example, it simply receives an incrementing number every second. &lt;/p&gt;

&lt;p&gt;Over time, the WebSocket could emit the following data:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; No data (Connecting to WebSocket)&lt;/li&gt;
&lt;li&gt; Data received (1)&lt;/li&gt;
&lt;li&gt; Data received (2)&lt;/li&gt;
&lt;li&gt; Data received (3)&lt;/li&gt;
&lt;li&gt; Error (due to network disconnection or equivalent)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In all of the above cases, we need to tell our user what’s going on with the connection, what data has been received, and if any errors occurred along the way. This information allows the user to decide whether to try again or not. &lt;/p&gt;

&lt;p&gt;For a long time, the only way to achieve this within Angular was to use an observable or something that implemented an observable. Usually, we could accomplish this with the “async pipe,” where an observable could be called like so and the bound variable within the template would update over time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;observableVariable&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, with signals, using asynchronous data has changed. We should understand the differences between signals and observables, to make the best choice as to what to use within our application.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Angular observables work
&lt;/h3&gt;

&lt;p&gt;The Angular documentation describes observables as a technique developers can use for things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Event handling&lt;/li&gt;
&lt;li&gt;  Asynchronous programming&lt;/li&gt;
&lt;li&gt;  Handling multiple values emitted over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Observables don’t come from within Angular itself; rather, they are &lt;a href="https://blog.logrocket.com/guide-rxjs-observables/"&gt;supplied to Angular by RxJS&lt;/a&gt;. An observable can emit more than once over time, so what do you do if you want to combine multiple emitters? What if you want to consolidate results from more than one source? &lt;/p&gt;

&lt;p&gt;All of this is possible within RxJS, but none of it is necessarily easy. Even the Angular team admits that "RxJS has a steep learning curve and sometimes bewildering behavior.” &lt;/p&gt;

&lt;p&gt;Processing signals occurs through the &lt;code&gt;pipe&lt;/code&gt; operator in RxJS. The idea is that you can put emitted values through the pipe and set up a chained list of operators to massage the values as required. &lt;/p&gt;

&lt;p&gt;This is very powerful, but given the sheer number of operators available, it’s also easy to reach for the wrong operator. Another common pitfall is unnecessarily chaining together too many operators, which can make code hard to read. &lt;/p&gt;

&lt;p&gt;Simply put, observables can be very powerful, but they can also be easy to get wrong. Also, if they’re not cleaned up properly, they can introduce other problems like memory leaks. They are used within both the app’s UI and services to process and manage asynchronous operations. &lt;/p&gt;

&lt;p&gt;Observables emit values over time, but they can also emit errors, or emit that they have completed. &lt;/p&gt;

&lt;p&gt;Long story short — observables are very powerful, and there’s nothing inherently wrong with them. However, given how many operators exist and how complex the operations can be, they can be easy to get wrong or to use incorrectly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where Angular signals enter the picture
&lt;/h3&gt;

&lt;p&gt;Let’s think about a simple value in our code. Imagine we want to have a variable, and we want to set the variable value to &lt;code&gt;0&lt;/code&gt;. That’s as simple as the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;theValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can reference this variable as much or as little as want to. But within the context of reactive applications, there’s a small wrinkle. This value isn’t reactive — we don’t know when it has been set or updated. &lt;/p&gt;

&lt;p&gt;Signals, introduced in Angular 16, set out to resolve this problem. They are a wrapper around a value that can notify interested consumers when the value changes. &lt;/p&gt;

&lt;p&gt;Compared to observables, signals are much simpler to create and use, so they make sense for a wide range of asynchronous operations within Angular. However, they don’t have the same power and flexibility as observables. Considering that RxJS can have “sometimes bewildering behavior”, this isn’t necessarily a bad thing. &lt;/p&gt;

&lt;p&gt;Signals are mainly used within the UI and can have their value changed entirely via &lt;code&gt;set&lt;/code&gt; or have their value updated based on a previous value with &lt;code&gt;update&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Creating a signal is as simple as the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;intSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To change the value, you can rewrite the Signal like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;intSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise, if you need to update the signal based on the existing value, you can do so like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;intSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because signals are reactive, our application’s view will update when they are updated, and other signals that depend on this signal will update as well. That’s where computed signals come into play. &lt;/p&gt;

&lt;p&gt;Instead of using pipes to manage data, signals use computed signals to define signals that update based on the behavior of other signals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;intSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;computedSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;intSignal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, let’s say we wanted to reference &lt;code&gt;intSignal&lt;/code&gt; and &lt;code&gt;computedSignal&lt;/code&gt; from within our template. Whenever we updated &lt;code&gt;intSignal&lt;/code&gt;, we would see that &lt;code&gt;computedSignal&lt;/code&gt; changes in value as well. &lt;/p&gt;

&lt;p&gt;Perhaps predictably, we can’t set the value of a computed signal directly, as it will only ever have the value that the dependent signals give to it. &lt;/p&gt;

&lt;p&gt;Long story short — signals exist as a newer and more efficient way of making a UI responsive and reactive. Connecting multiple signals via &lt;code&gt;computed&lt;/code&gt; is much easier than using an observable to do the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should we use signals or observables — or both?
&lt;/h2&gt;

&lt;p&gt;Whenever something new comes out, it can be tempting to abandon the old thing and run to the new thing. The reverse can also be true, where we never want to change what we’re doing because we’re used to how things used to operate. &lt;/p&gt;

&lt;p&gt;So, in this case, what should we do? Well, the answer is to continue using observables within our services in Angular, but also consider using signals in component logic and templates. &lt;/p&gt;

&lt;p&gt;To show the strengths of both observables and signals, let's make a simple app that reports on the temperatures within the rooms of a house. Normally, these temperatures would not update very frequently, but for this example, we’ll speed it up over a day. &lt;/p&gt;

&lt;p&gt;Our app will look like this at the end: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oZE-2AX_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/Room-temp-viewer-app.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oZE-2AX_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/Room-temp-viewer-app.gif" alt="Preview Of Final Room Temp Viewer Project Showing List Of Rooms With Current Temp And Some Additional Stats" width="800" height="1208"&gt;&lt;/a&gt; To make our demo app, we’ll combine observables, signals, and good old change detection. You can check out the &lt;a href="https://github.com/azimuthdeveloper/angular-signals"&gt;source code for this app on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The room temperature service
&lt;/h2&gt;

&lt;p&gt;The first thing we need for our demo app is a room temperature detection service. Normally, this would be something that we’d get from a third-party service, like an API. But in our case, it’s okay if we just want to create a fake temperature service. &lt;/p&gt;

&lt;p&gt;This service will be responsible for creating a &lt;code&gt;BehaviorSubject&lt;/code&gt; that emits a single new temperature for a room over time. Just like a real temperature detection service, it’s not concerned with tracking historical temperatures or massaging the data. &lt;/p&gt;

&lt;p&gt;Since this is in the service layer and not the UI, it would make sense to use an observable here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RoomTemperatureService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;roomTemperatures$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RoomTemperature&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RoomTemperature&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emitRandomRoomTemperature&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Begin emitting&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;emitRandomRoomTemperature&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Emit a new temperature for a random room&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;roomNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Living Room&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bedroom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Kitchen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;randomRoomIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;roomNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chosenRoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;roomNames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;randomRoomIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newTemperature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roomTemperatures$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chosenRoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newTemperature&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Update random room temperature every second&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we see how to create a &lt;code&gt;BehaviorSubject&lt;/code&gt;, which is a type of observable. We can then call &lt;code&gt;next&lt;/code&gt; to emit a new value on the &lt;code&gt;BehaviorSubject&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Consumers of this service get the information they need — in our case, the room name and detected temperature. However, what if we wanted to aggregate the received data so we could show a historical temperature list? &lt;/p&gt;

&lt;p&gt;Let’s see how we can do that in the individual &lt;code&gt;TemperatureNode&lt;/code&gt; component.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;TemperatureNode&lt;/code&gt; component
&lt;/h2&gt;

&lt;p&gt;First, let’s create a &lt;code&gt;TemperatureNode&lt;/code&gt; that will display the current temperature of each room, historical temperatures, and an average. This component will use standard &lt;code&gt;@Input&lt;/code&gt; components and the &lt;code&gt;ngOnChanges&lt;/code&gt; hook to know when to update the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TemperatureNodeComponent&lt;/span&gt; &lt;span class="kr"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnChanges&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;roomName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;averageTemperature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;totalTemperatureCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SimpleChanges&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;averageTemperature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalTemperatureCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also write up our HTML for this component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: flex; width: 100%; align-content: stretch; flex-direction: row; gap: 12px; border: 2px solid black; border-radius: 5px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 200px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;{{this.roomName}}&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h4&amp;gt;&lt;/span&gt;Statistics&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Average: {{averageTemperature | number:'1.2-2'}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Total amount: {{totalTemperatureCount}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: flex; flex-direction: column; gap: 2px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    @for (temp of temperatures; track temp; let idx = $index){
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
        @if (idx == 0){
          &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;{{temp | number:"1.2-2"}}&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
        }
        @else if (idx &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt; &lt;span class="err"&gt;6){&lt;/span&gt;
          &lt;span class="err"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;temp&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="na"&gt;number:&lt;/span&gt;&lt;span class="err"&gt;"1.2&lt;/span&gt;&lt;span class="na"&gt;-2&lt;/span&gt;&lt;span class="err"&gt;"}}&lt;/span&gt;
        &lt;span class="err"&gt;}&lt;/span&gt;
        &lt;span class="err"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="na"&gt;span&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    }
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the finished sample, this component will look like this: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--60tjWXOk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/Sample-component-checking-room-temp-Kitchen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--60tjWXOk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/Sample-component-checking-room-temp-Kitchen.png" alt="Screenshot Of Sample Component Checking Room Temp In Kitchen With Current Temp Displayed Above Additional Statistics" width="800" height="291"&gt;&lt;/a&gt; Now we need a component to render one of these components for each room that has a temperature result.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;TemperatureView&lt;/code&gt; component
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;TemperatureView&lt;/code&gt; component should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Subscribe to each new emitted object from the temperature service&lt;/li&gt;
&lt;li&gt;  Be responsible for aggregating the results in a way that makes sense&lt;/li&gt;
&lt;li&gt;  Give the user the option to start and stop the flow of messages, reset the results entirely, and set the temperatures to an entirely new value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because our work affects the UI, it would be sensible to choose a signal for this. &lt;/p&gt;

&lt;p&gt;But wait a minute — our service provides temperatures one at a time via an observable, and we want to use a signal within our UI. How do we connect our observable to the signal and perform some basic data massaging? &lt;/p&gt;

&lt;p&gt;Simply put, we can subscribe to our observable as usual and then pipe the data through into our signal via the &lt;code&gt;update&lt;/code&gt; method. Because we are subscribing to an observable here, we’re still responsible for subscribing and unsubscribing to the observable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;startSubscription&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="c1"&gt;// Begin the subscription to the service&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperatureSubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tempService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roomTemperatures$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newTemp&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Update the existing Angular signal contents, in this case, an array.&lt;/span&gt;
    &lt;span class="c1"&gt;// Add new values to existing entries, or add a new entry for the given room&lt;/span&gt;
    &lt;span class="c1"&gt;// This acts as the accumulator&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historicalTemperatures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newTemp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="c1"&gt;// Only if there is a valid temperature reading&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;temperatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;room&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;newTemp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Is there an existing entry for this room?&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="c1"&gt;// Add to existing collection of temperatures for room&lt;/span&gt;
          &lt;span class="nx"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newTemp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Create a new collection for this rooms temperatures&lt;/span&gt;
          &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;room&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newTemp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newTemp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;]}]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// Return the updated variable&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we saw earlier, we can also update the signal with an entirely new value that isn’t based on the existing value via &lt;code&gt;set&lt;/code&gt;. If we wanted to set the temperature data to a new value and disregard what was already in the signal, we could do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setStatic&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="c1"&gt;// First, end the subscription to the service&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endSubscription&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Set the signal data to a new value&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historicalTemperatures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;room&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;10.5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;room&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Guest room&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;13.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;14.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;12.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;12.8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;room&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Living room&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;temperatures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;14.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to use signals vs. observables
&lt;/h2&gt;

&lt;p&gt;Now that we’ve explored how signals and observables can both be used in a project, let’s recap when it’s best to use one or the other.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use observables
&lt;/h3&gt;

&lt;p&gt;In our example, we can see that using an observable requires us to manually subscribe to it, handle the output, and unsubscribe when we are done. &lt;/p&gt;

&lt;p&gt;Subscribing to an observable is like listening to new events that filter down to our consumer. There can be new events, but there could also be an error, or an indication to say that the observable has finished. &lt;/p&gt;

&lt;p&gt;We also manage the stream of events by piping events through a &lt;code&gt;pipe&lt;/code&gt;. These pipes can indeed become extremely complex, but they can be very elegant in managing an asynchronous stream of data over time. &lt;/p&gt;

&lt;p&gt;For this reason, you’ll usually see observables in services within your Angular application.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use signals
&lt;/h3&gt;

&lt;p&gt;Signals, on the other hand, are used within the UI layer of your application. You can update a signal via the &lt;code&gt;set&lt;/code&gt; method, or make a change to an existing value via &lt;code&gt;update&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Since you’re setting or updating the signal each time, there isn’t really a built-in error state, like with an observable. However, you can define your own error state and update a signal accordingly. &lt;/p&gt;

&lt;p&gt;Also, you can use computed signals to compose new signals based on existing signals. Changes will propagate through these computed signals when dependent signals are updated. &lt;/p&gt;

&lt;p&gt;If your template is being updated reactively in your code, it would make sense to use a signal instead of an observable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do we really have to use signals?
&lt;/h2&gt;

&lt;p&gt;Signals are a useful new Angular feature, but do we really have to use them? In short — no. &lt;/p&gt;

&lt;p&gt;If you don’t use signals, you’re simply living the life of an Angular developer before Angular 16 landed. Many excellent applications were written and many reactive webpages were created without signals. &lt;/p&gt;

&lt;p&gt;However, we have to acknowledge the simplicity and power of signals in making templates reactive, and how computed signals can be easily composed from other signals. Using signals to manage these kinds of requirements instead of creating your own subscription tree with your own observable is much simpler. &lt;/p&gt;

&lt;p&gt;No matter what you choose, performance will be about the same in your application, so it ultimately comes down to your preferences and level of comfort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Signals are an exciting new addition to Angular, and they act as a complement — not a replacement — to observables. By understanding where we should use each, we can write high-quality reactive applications that are more performant and easier to develop. &lt;/p&gt;

&lt;p&gt;Feel free to &lt;a href="https://github.com/azimuthdeveloper/angular-signals"&gt;grab the sample app&lt;/a&gt; that was used in this tutorial to see the source code or fork the project for your own needs. If you have any questions, you’re welcome to comment below. &lt;/p&gt;

&lt;p&gt;Happy reactive coding!&lt;/p&gt;




&lt;h2&gt;
  
  
  Experience your Angular apps exactly how a user does
&lt;/h2&gt;

&lt;p&gt;Debugging Angular applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Angular state and actions for all of your users in production, &lt;a href="https://lp.logrocket.com/blg/angular-signup"&gt;try LogRocket&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/angular-signup"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rZLiffbM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://files.readme.io/610d6a7-687474703a2f2f692e696d6775722e636f6d2f696147547837412e706e67.png" alt="LogRocket Signup" width="800" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/angular-signup"&gt;LogRocket&lt;/a&gt; is like a DVR for web and mobile apps, recording literally everything that happens on your site including network requests, JavaScript errors, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.&lt;/p&gt;

&lt;p&gt;The LogRocket NgRx plugin logs Angular state and actions to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.&lt;/p&gt;

&lt;p&gt;Modernize how you debug your Angular apps — &lt;a href="https://lp.logrocket.com/blg/angular-signup"&gt;start monitoring for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using CSS Houdini to extend styling and layout capabilities</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Tue, 16 Jan 2024 15:55:13 +0000</pubDate>
      <link>https://dev.to/logrocket/using-css-houdini-to-extend-styling-and-layout-capabilities-4oae</link>
      <guid>https://dev.to/logrocket/using-css-houdini-to-extend-styling-and-layout-capabilities-4oae</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/emmanuelodioko/"&gt;Emmanuel Odioko&lt;br&gt;
&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CSS Houdini frees developers of the constraints associated with traditional CSS, enabling them to efficiently create unique designs and animations. CSS Houdini can extend CSS styling and even create new features that aren’t part of the standard CSS toolkit, all without the reduction in performance that’s associated with polyfills. &lt;/p&gt;

&lt;p&gt;In this article, we’ll explore CSS Houdini's definition, functionality, and unique contributions to frontend development. We’ll also explore several use cases. It’s important to note that CSS Houdini is still in the experimental phase as of this writing, so it does not have full browser support.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow along with this tutorial, you should have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Basic understanding of HTML, CSS, and JavaScript&lt;/li&gt;
&lt;li&gt;  Familiarity with frontend development concepts (e.g., styling, layout, and animations) is helpful, but not required&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What is CSS Houdini?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Houdini"&gt;CSS Houdini&lt;/a&gt; is a set of APIs that expose parts of CSS engines. You can use these APIs to easily create extensions on top of CSS, building features that don’t currently exist and painting them to the browser. &lt;/p&gt;

&lt;p&gt;Houdini extends CSS via JavaScript so that developers can create something new and implement it in the browser without waiting for a particular feature to be made available in CSS. Its APIs provide developers with direct entry into the CSS Object Model (CSSOM), empowering them to write code that the browser can interpret as CSS and enabling the creation of new CSS features. &lt;/p&gt;

&lt;p&gt;You can think of Houdini as a low-level JavaScript API for the browser API engine, similar to how service workers are low-level APIs for JavaScript cache. &lt;/p&gt;

&lt;p&gt;Some might argue that &lt;a href="https://blog.logrocket.com/two-ways-load-only-css-you-need/#postcss-imports"&gt;PostCSS transforms CSS&lt;/a&gt; and that there are also several JavaScript libraries that extend CSS. However, I would argue that those libraries just write JavaScript that mimics other things we already have with today’s CSS. &lt;/p&gt;

&lt;p&gt;JavaScript enables developers to manipulate existing CSS styles through DOM interaction, but Houdini's APIs aim to allow developers to extend existing CSS capabilities and even create entirely new styles, unconstrained by limitations. &lt;/p&gt;

&lt;p&gt;It’s important to reiterate that, at the time of writing, &lt;a href="https://ishoudinireadyyet.com"&gt;CSS Houdini’s APIs do not have full browser support&lt;/a&gt;, and some are still in the experimental phase.&lt;/p&gt;
&lt;h2&gt;
  
  
  Styling and layout before CSS Houdini
&lt;/h2&gt;

&lt;p&gt;Before the introduction of CSS Houdini, web developers had to make do with using standard CSS to style and layout their webpages. JavaScript, although powerful for handling dynamic behavior, did not have direct access to the rendering engine or the ability to manipulate the CSS parsing process in a granular way. &lt;/p&gt;

&lt;p&gt;Here's a very basic example of how developers handled dynamic styling with JavaScript prior to the introduction of CSS Houdini:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// Dynamic Styling with JavaScript
// Without CSS Houdini
// Change the color of an element using JavaScript

// &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"myElement"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello, World!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;myElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this approach, JavaScript is used to manipulate the inline style of an HTML element. However, this method is limited to basic properties, and extensive dynamic styling and manipulation of the rendering pipeline isn’t feasible. &lt;/p&gt;

&lt;p&gt;Here’s a basic example where JavaScript is used to trigger a CSS-based animation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// Animation without CSS Houdini
// Without CSS Houdini
// Create a simple animation using JavaScript and CSS

// &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"animatedElement"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Animate me!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;animatedElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;animatedElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;animateElement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;animatedElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all 2s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;animatedElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;translateX(200px)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Trigger the animation&lt;/span&gt;
&lt;span class="nf"&gt;animateElement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this approach provides a level of dynamism, developers are constrained by the predefined properties and the timing functions provided by CSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CSS Houdini?
&lt;/h2&gt;

&lt;p&gt;CSS is continually evolving, but the pace of new feature introduction and adoption is often slow, leading to challenges in cross-browser compatibility. CSS features often take significant time to achieve widespread compatibility across different browsers. Some notable examples are: &lt;a href="https://blog.logrocket.com/css-flexbox-vs-css-grid/"&gt;CSS flexbox, CSS grid&lt;/a&gt;, CSS Transitions and Animations, CSS Variables, and Custom Properties. &lt;/p&gt;

&lt;p&gt;As web developers eagerly await widespread support for additional CSS features, they often rely on pieces of code, called &lt;a href="https://blog.logrocket.com/use-polyfills-react-app/"&gt;polyfills&lt;/a&gt;, to fill the gaps in browser support. Polyfills enable the use of modern CSS properties and functionalities in browsers that do not natively support them, but they do come with their own set of minor performance drawbacks. &lt;/p&gt;

&lt;p&gt;As an example, the flexbox property is widely supported in modern browsers, but older versions of Internet Explorer (IE 10 and below) have limited or no support. In such cases, a polyfill can be introduced to mimic the flexbox behavior in those browsers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nt"&gt;Basic&lt;/span&gt; &lt;span class="nt"&gt;polyfill&lt;/span&gt; &lt;span class="nt"&gt;implementation&lt;/span&gt;

&lt;span class="c"&gt;/* Flexbox Polyfill for IE 10 and below */&lt;/span&gt;
&lt;span class="nc"&gt;.flex-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;-ms-flexbox&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;-ms-flex-pack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;justify&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.flex-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;-ms-flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CSS polyfills can be useful for extending the support of modern CSS features to older browsers, but they do have some drawbacks, including reduction in performance, increased page weight, maintenance challenges, browser-specific issues, and more. One notable drawback is the performance impact associated with re-rendering. This can limit the effectiveness of polyfills in certain scenarios. &lt;/p&gt;

&lt;p&gt;The introduction of CSS Houdini was not a declaration of the failure of polyfills, but rather a strategic move toward a more versatile solution. The primary advantage of Houdini lies in its capacity to enhance styling processes, providing a more efficient and standardized approach. A secondary advantage is its ability to seamlessly create styles that transcend different browser environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does browser rendering work?
&lt;/h2&gt;

&lt;p&gt;To fully understand the need for CSS Houdini, we’ll need to consider a brief overview of the browser rendering process: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4vW9obBX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/browser-rendering-flowchart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4vW9obBX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/browser-rendering-flowchart.png" alt="Browser Rendering Flowchart" width="800" height="656"&gt;&lt;/a&gt; Let’s take a closer look at the browser rendering process for HTML parsing, as well as CSS parsing and style computation.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTML parsing
&lt;/h3&gt;

&lt;p&gt;The browser begins by fetching the HTML document from the server. The HTML parser reads and parses the HTML code to create a DOM tree, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- HTML document fetched from the server --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Rendering Pipeline&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Associated CSS stylesheet --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello, world!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- JavaScript can manipulate the DOM after it's parsed --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CSS parsing and styling
&lt;/h3&gt;

&lt;p&gt;Next, the browser fetches and parses the associated CSS stylesheets. The CSS parser generates a CSS Object Model (CSSOM). The DOM and CSSOM are combined to create the render tee, where each node represents a visible element along with its styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* CSS stylesheets defining the appearance of elements */&lt;/span&gt;
&lt;span class="nf"&gt;#content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layout (box model)
&lt;/h3&gt;

&lt;p&gt;The render tree is used to create the box model, defining the position and size of each element on the page. The browser calculates the layout of elements based on their styles, dimensions, and relationships.&lt;/p&gt;

&lt;h3&gt;
  
  
  Painting
&lt;/h3&gt;

&lt;p&gt;The browser starts painting the pixels on the screen according to the layout. Painting involves filling pixels with colors, images, and other visual properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  Composite layers
&lt;/h3&gt;

&lt;p&gt;Modern browsers often use hardware acceleration and create separate layers for certain elements (e.g., animations or transforms). These layers are composited to form the final rendered output, thereby enhancing performance. &lt;/p&gt;

&lt;p&gt;Modern browsers often handle hardware acceleration automatically, but certain CSS properties trigger it. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* CSS triggering hardware acceleration with transforms */&lt;/span&gt;
&lt;span class="nf"&gt;#content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rendering and display
&lt;/h3&gt;

&lt;p&gt;The final rendering and display are handled by the browser once all previous steps are completed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can developers interact with the rendering process?
&lt;/h2&gt;

&lt;p&gt;Developers can manipulate and interact with some of the rendering pipeline at certain stages using JavaScript. Let’s see exactly where developers can intervene.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTML parsing intervention
&lt;/h3&gt;

&lt;p&gt;Developers can dynamically generate or modify HTML content using JavaScript, either before or after the initial HTML parsing by the browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;div id="newElement"&amp;gt;Dynamic Content&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CSS styling intervention
&lt;/h3&gt;

&lt;p&gt;JavaScript can dynamically add, remove, or modify CSS styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layout (box model) intervention
&lt;/h3&gt;

&lt;p&gt;Developers can dynamically change the layout by modifying CSS properties that affect the box model, such as &lt;code&gt;width&lt;/code&gt;, &lt;code&gt;height&lt;/code&gt;, &lt;code&gt;margin&lt;/code&gt;, and &lt;code&gt;padding&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;300px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Painting intervention
&lt;/h3&gt;

&lt;p&gt;Developers have limited control over the painting process, but they can trigger repaints by changing certain styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yellow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rendering and display intervention
&lt;/h3&gt;

&lt;p&gt;JavaScript can continue to manipulate the DOM even after initial rendering, responding to user interactions or events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Element Clicked!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The seamless integration of JavaScript throughout the page load process showcases the immense potential of CSS Houdini which leverages JavaScript within the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are low-level APIs and worklets?
&lt;/h2&gt;

&lt;p&gt;Low-level APIs provide a more direct interface to the browser's internal CSS engine, granting developers granular control over various CSS processes. &lt;/p&gt;

&lt;p&gt;They enable developers to create custom properties, modify existing ones, define custom parsing and rendering rules, and even tap into the layout and paint cycles. These APIs form the foundation upon which higher-level features and tools are constructed, offering a deeper level of customization and control. &lt;/p&gt;

&lt;p&gt;Worklets are &lt;a href="https://blog.logrocket.com/web-workers-react-typescript/"&gt;similar to web workers in concept&lt;/a&gt;, letting developers run JavaScript code in the background, away from the main script. You can think of them as instructions for the browser's backstage crew, tailored for the styling and layout tasks that CSS Houdini focuses on. They essentially work with and enhance the browser's visual engine. &lt;/p&gt;

&lt;p&gt;This background operation makes things happen at the same time, leading to a faster and more efficient performance. It's like having a specialized team working behind the scenes to improve the visual experience on a website. &lt;/p&gt;

&lt;p&gt;Worklets operate independently, not connected to the main thread, and can be triggered at different stages in the rendering process. They're like modular components that seamlessly fit into the browser, making it easier for developers to implement advanced styling and layout features. &lt;/p&gt;

&lt;p&gt;These modular components are effortlessly added and activated using a short line of JavaScript. This easy integration enhances the browser's capabilities, giving developers the power to improve web design and layout. &lt;/p&gt;

&lt;p&gt;Let’s take a closer look at CSS Houdini’s low-level APIs and worklets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Typed Object Model API
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Typed_OM_API"&gt;Typed Object Model (Typed OM) API&lt;/a&gt; is part of CSS Houdini’s efforts to provide a low-level API for dealing with styles and layout in the browser. It allows developers to create and manipulate typed objects representing styles. &lt;/p&gt;

&lt;p&gt;Before the Typed OM API, developers had to manipulate styles by dealing with strings. For example, to change a specific style property, you‘d need to parse the existing string, modify the value, and then set it back as a string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Manipulating styles as strings&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Get the current width as a string&lt;/span&gt;
&lt;span class="nx"&gt;currentWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentWidth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Convert to a number&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentWidth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newWidth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Set the new width as a string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This process was not very efficient and was often prone to errors. Also, manipulating styles as strings didn't provide type safety. Developers had to be cautious about data types and ensure that the correct units and values were used. &lt;/p&gt;

&lt;p&gt;The Typed OM API introduces a more structured and type-safe way to work with styles in JavaScript. There are a few steps to implement it, and the process may vary depending on your specific use case. &lt;/p&gt;

&lt;p&gt;Before using the Typed OM API, perform feature detection to ensure your browser supports it. You can use JavaScript to check the availability of specific Typed OM features or objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CSSStyleValue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Typed OM is supported&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Fallback or inform the user&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, modify your stylesheets to use properties that are compatible with the Typed OM API. For example, instead of directly using strings for styles, consider using the Typed OM-compatible objects. &lt;/p&gt;

&lt;p&gt;Now, identify areas in your JavaScript code where you can replace traditional string-based style manipulations with the Typed OM. Update your code to use the Typed OM API for style-related operations. &lt;/p&gt;

&lt;p&gt;You can use the Typed OM methods to retrieve and update styles in a type-safe manner. For example, use &lt;code&gt;get&lt;/code&gt; to retrieve a style value as a Typed OM object and &lt;code&gt;set&lt;/code&gt; to update a style:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributeStyleMap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentWidth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newWidth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is a simple example showcasing the use of the Typed OM API to change the &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; of an element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;...
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Typed OM Example&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.container&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;brown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s the initial &lt;code&gt;container&lt;/code&gt;: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--by5eXY_R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/initial-container-before-resizing.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--by5eXY_R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/initial-container-before-resizing.png" alt="Initial Container Before Resizing" width="800" height="206"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Select the container using JavaScript&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Log the type of height and width styles&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Type of container.style.height:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Type of container.style.width:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Log the computed styles using Typed OM&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Computed height:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;computedStyleMap&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Computed width:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;computedStyleMap&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Computed width value:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;computedStyleMap&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Set the height and width using Typed OM&lt;/span&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributeStyleMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CSS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;px&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributeStyleMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CSS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;px&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Log the updated computed styles&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Updated height:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;computedStyleMap&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Updated width:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;computedStyleMap&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s the &lt;code&gt;container&lt;/code&gt; with updated &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt;: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fl45WCX1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-resized-object-typed-om-api.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fl45WCX1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-resized-object-typed-om-api.png" alt="CSS Houdini Resized Object Typed OM API" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Properties and Values API
&lt;/h2&gt;

&lt;p&gt;Houdini's &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Properties_and_Values_API"&gt;Properties and Values API&lt;/a&gt; takes CSS variables to a higher level of flexibility and control. Unlike traditional variables, it empowers developers to define data types, set default values, manage inheritance, and even animate these variables. &lt;/p&gt;

&lt;p&gt;This enhancement results in more dependable code, adaptable design patterns, dynamic animations, and improved testing capabilities. Features like the &lt;code&gt;registerProperty()&lt;/code&gt; method and the &lt;code&gt;@property&lt;/code&gt; rule enable developers to easily register and use the full potential of these customizable properties. &lt;/p&gt;

&lt;p&gt;This API not only simplifies the code, it also opens up new possibilities for creating expressive and responsive designs. Here are some of its features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Type checking&lt;/strong&gt;: Enables you to define valid data types for your custom properties (e.g., integer) and also catch typos and unexpected values that can break styling&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Default values&lt;/strong&gt;: Allows you to specify a fallback value if a custom property isn't explicitly set; this feature improves consistency and avoids unexpected rendering bugs&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Inheritance control&lt;/strong&gt;: Permits you to choose whether your custom property inherits its value from its parent elements, like regular variables&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Animation and translation support&lt;/strong&gt;: Enables you to animate and transition custom properties alongside other CSS properties and create dynamic and interactive effects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take a look at how the Properties and Values API is implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Properties and Values API Example&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"change-color"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Change Color&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"box"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;This box will change color.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@property&lt;/span&gt; &lt;span class="n"&gt;--custom-color&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;syntax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'&amp;lt;color&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;initial-value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;inherits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--custom-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;background-color&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* Enable smooth color transitions */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, the &lt;code&gt;@property&lt;/code&gt; at-rule defines a custom property named &lt;code&gt;--custom-color&lt;/code&gt; with a default value of &lt;code&gt;blue&lt;/code&gt; and inheritance disabled. The &lt;code&gt;.box&lt;/code&gt; class applies a background color using &lt;code&gt;var(--custom-color)&lt;/code&gt;, referencing the custom property. The &lt;code&gt;transition&lt;/code&gt; property enables smooth color changes. &lt;/p&gt;

&lt;p&gt;The following JavaScript code gets references to the &lt;code&gt;button&lt;/code&gt; and the &lt;code&gt;box&lt;/code&gt; element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change-color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.box&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Or any other valid color value&lt;/span&gt;
  &lt;span class="nx"&gt;box&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--custom-color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newColor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, an event listener is attached to the &lt;code&gt;button&lt;/code&gt;. Clicking the &lt;code&gt;button&lt;/code&gt; triggers the JavaScript code to update the custom propery’s value; the &lt;code&gt;--custom-color&lt;/code&gt; property is set to a new color (&lt;code&gt;red&lt;/code&gt;) using &lt;code&gt;style.setProperty()&lt;/code&gt;. The browser detects the change and applies the new color to the &lt;code&gt;box&lt;/code&gt; element in a smooth transition. &lt;/p&gt;

&lt;p&gt;We can take this example a step further by animating it, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Colorful Box Animation&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Colorful Box Animation&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"box"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"colorful-box"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;This box will change color.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"buttons"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"change-color"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Change Color&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"toggle-rainbow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Toggle Rainbow&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@property&lt;/span&gt; &lt;span class="n"&gt;--hue-offset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;syntax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'&amp;lt;number&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;initial-value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;inherits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f0f0f0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--hue-offset&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;80%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;background-color&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rainbow&lt;/span&gt; &lt;span class="m"&gt;3s&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;rainbow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--hue-offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--hue-offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;360&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.buttons&lt;/span&gt; &lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#4caf50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;background-color&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.buttons&lt;/span&gt; &lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#45a049&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changeColorButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change-color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggleRainbowButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle-rainbow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;colorfulBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;colorful-box&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;changeColorButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;indigo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;colorfulBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--custom-color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newColor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;toggleRainbowButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;colorfulBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code sets up functionality for a simple webpage with three elements: a button to change the color of a box, a button to toggle a "rainbow" effect on the box, and the box itself. &lt;/p&gt;

&lt;p&gt;When the &lt;code&gt;changeColorButton&lt;/code&gt; is clicked, an event listener changes the custom CSS &lt;code&gt;property '--custom-color&lt;/code&gt; of the &lt;code&gt;colorfulBox&lt;/code&gt; to &lt;code&gt;indigo&lt;/code&gt;, effectively changing the background color of the box. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;toggleRainbowButton&lt;/code&gt; is linked to another event listener, which toggles the active class on the &lt;code&gt;colorfulBox&lt;/code&gt; when the button is clicked. This class contains CSS rules to create a rainbow effect on the box, giving the user the ability to switch the visual appearance of the box between a static color and a dynamic, rainbow-like display. &lt;/p&gt;

&lt;p&gt;Here‘s the box, animated to dynamically change colors: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aCCSCAV6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-properties-and-values-api-dynamic-color-box.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aCCSCAV6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-properties-and-values-api-dynamic-color-box.gif" alt="CS Houdini Properties and Values API Dynamic Color Box" width="486" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Font Metrics API
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Houdini#font_metrics_api"&gt;Font Metrics API&lt;/a&gt; is a proposed interface that exposes font metrics, offering access to typographic layout results. It is intended to provide detailed information about font and other relevant parameters, helping developers achieve precise text layout in web applications. &lt;/p&gt;

&lt;p&gt;As of this writing, this API lacks browser implementations and comprehensive documentation and, due to its proposed status, is not currently supported in browsers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Painting API
&lt;/h2&gt;

&lt;p&gt;The CSS Houdini &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Painting_API"&gt;Painting API&lt;/a&gt; enables developers to define how an element is painted on the screen. It provides a way to create custom graphics, background images, and visual effects that go beyond the capabilities of traditional CSS. &lt;/p&gt;

&lt;p&gt;The primary purpose of the Painting API is to give developers more control over the rendering process of elements. With traditional CSS, developers are limited to a predefined set of properties for styling. &lt;/p&gt;

&lt;p&gt;The Painting API breaks through these limitations by enabling the creation of custom paint worklets, which are JavaScript modules defining how an element should be painted. CSS Houdini's paint worklet is automatically enabled in Chrome 65+, so you can easily add custom images without relying on external files or predefined functions. &lt;/p&gt;

&lt;p&gt;To use the Painting API, you’ll need to follow a specific workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Define a paint worklet&lt;/strong&gt;: A paint worklet is a JavaScript module that defines the custom painting logic. This module should implement a paint method, which receives a &lt;code&gt;CanvasRenderingContext2D&lt;/code&gt; context and other parameters&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Register the paint worklet&lt;/strong&gt;: Use &lt;code&gt;CSS.paintWorklet.addModule&lt;/code&gt; to register the paint worklet with the browser. This is an asynchronous operation, so you should wait for the promise to resolve before applying the custom paint logic&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Use CSS properties&lt;/strong&gt;: Define CSS custom properties that can be dynamically updated to influence the custom painting logic&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Apply the paint worklet&lt;/strong&gt;: Apply the custom paint worklet to specific elements using CSS properties&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's take a look at a simple example using the Painting API to draw a gradient background dynamically. We'll create a custom paint worklet that takes two colors as input and draws a linear gradient:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
 HTML &lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Painting API Example&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"custom-element"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;CSS&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;styles&lt;/span&gt;&lt;span class="nc"&gt;.css&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;JavaScript &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;CSS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paintWorklet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;paint-worklet.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Paint worklet module loaded.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;JavaScript &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paint&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;worklet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;registerPaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gradient&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;{
    &lt;/span&gt;&lt;span class="nc"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gradient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createLinearGradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addColorStop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addColorStop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s the resulting gradient: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Wkl6yGp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-painting-api-gradient-box.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Wkl6yGp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-painting-api-gradient-box.png" alt="CSS Houdini Painting API Gradient Box" width="800" height="367"&gt;&lt;/a&gt; Now, let’s look at a different example using a paint worklet to create an animation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stylesheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;Paint&lt;/span&gt; &lt;span class="nx"&gt;worklet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Logrocket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s Example!
  &amp;lt;/div&amp;gt;
  &amp;lt;script&amp;gt;
    if (!CSS.paintWorklet) {
      document.body.innerHTML("PaintWorklet not supported by this browser");
    }
    async function init() {
      await CSS.paintWorklet.addModule("./paint-worklet.js");
      const example = document.querySelector("#example");
      let start = performance.now();
      let x, y;
      document.querySelector("#example").addEventListener("click", evt =&amp;gt; {
        example.classList.add("animating");
        [x, y] = [evt.clientX, evt.clientY];
        start = performance.now();
        requestAnimationFrame(function raf(now) {
          const count = Math.floor(now - start);
          example.style.cssText = `--animation-tick: ${count};`;
          if (count &amp;gt; 4000) {
            example.classList.remove("animating");
            example.style.cssText = `--animation-tick: 0; background-color: red;`; // Change background color here
            return;
          }
          requestAnimationFrame(raf);
        });
      });
    }
    init();
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.background&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;84&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-around&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;214&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;219&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;224&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c"&gt;/* Required for animation by the worklet */&lt;/span&gt;
  &lt;span class="py"&gt;--animation-tick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.background.animating&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;custom-animation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// paint-worklet.js&lt;/span&gt;
&lt;span class="nf"&gt;registerPaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custom-animation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;{
  &lt;/span&gt;&lt;span class="nc"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;inputProperties&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--animation-tick&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--animation-tick&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;centerX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;centerY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tick&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginPath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;centerX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;centerY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`rgba(255, 255, 255, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s the resulting animation: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8l4EK0ki--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-painting-api-custom-animation.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8l4EK0ki--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-painting-api-custom-animation.gif" alt="CSS Houdini Painting API Custom Animation" width="788" height="368"&gt;&lt;/a&gt; When the document is loaded, the code checks if the browser supports the Painting API. If it’s supported, it initializes the custom animation by loading the paint worklet module. When the &lt;code&gt;#example&lt;/code&gt; element is clicked, it triggers an animation effect using the custom paint worklet. The custom paint worklet creates a dynamic animation with concentric circles based on the &lt;code&gt;--animation-tick&lt;/code&gt; value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Animation Worklet API
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://drafts.css-houdini.org/css-animation-worklet/"&gt;Animation Worklet API&lt;/a&gt; is part of the CSS Houdini initiative and provides a way to create custom animations that run in a dedicated worklet thread. Offloading animation calculations to a separate thread can help improve performance and avoid jank or stuttering in complex animations. &lt;/p&gt;

&lt;p&gt;You’ll need to first register an animation worklet using the &lt;code&gt;registerAnimator&lt;/code&gt; function. This associates a custom animation class with a name that can be used in CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// animation-worklet.js&lt;/span&gt;
&lt;span class="nf"&gt;registerAnimator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customAnimation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;{
  &lt;/span&gt;&lt;span class="nc"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Custom animation logic&lt;/span&gt;
    &lt;span class="c1"&gt;// Update the state of the animated element based on the currentTime&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the animation worklet is registered, it can be referenced in CSS using the &lt;code&gt;animation&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;CSS&lt;/span&gt;
&lt;span class="nc"&gt;.element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;customAnimation&lt;/span&gt; &lt;span class="m"&gt;3s&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the animation worklet was registered with the name &lt;code&gt;customAnimation&lt;/code&gt;. Unfortunately, there is currently little or no support for this API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    // Check &lt;span class="k"&gt;if &lt;/span&gt;animationWorklet is supported
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;CSS.animationWorklet&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      // Animation Worklet is supported
      console.log&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"AnimationWorklet is supported in this browser"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      // Animation Worklet is not supported
      document.body.innerHTML &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AnimationWorklet not supported by this browser"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o_a5RfL3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-animation-worklet-broswer-support.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o_a5RfL3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2024/01/css-houdini-animation-worklet-broswer-support.png" alt="CSS Houdini Animation Worklet Browser Support" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations of CSS Houdini
&lt;/h2&gt;

&lt;p&gt;At the time of writing, there are some common limitations associated with CSS Houdini:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Browser support&lt;/strong&gt;: Some browsers, such as Chrome and Firefox, have implemented certain aspects of CSS Houdini, but others lag behind&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Incomplete specification&lt;/strong&gt;: As CSS Houdini is still evolving, some parts of the specification are not finalized; certain features may change or be subject to updates in future releases&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Security concerns&lt;/strong&gt;: Extending and manipulating the rendering process raises potential security concerns. Browsers must carefully manage CSS Houdini’s APIs to prevent malicious use or unintended side effects; this may be why browser adoption is moving slowly&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Learning curve&lt;/strong&gt;: Working with CSS Houdini requires a solid understanding of web technologies, CSS, and JavaScript. The learning curve can be a bit much for developers who are new to these concepts&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Limited documentation&lt;/strong&gt;: At the time of writing, the documentation for CSS Houdini is not as extensive or well-established as that of other web technologies. Developers looking for help may have difficulty finding adequate resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;CSS Houdini has emerged as a powerful toolset that revolutionizes the way developers approach styling and layout on the web. CSS Houdini’s APIs empower developers to extend the capabilities of the browser, providing a level of customization and creativity previously unseen in the history of traditional CSS. &lt;/p&gt;

&lt;p&gt;The magic the CSS Houdini aims to perform is reminiscent of the famous illusionist. Its creativity and flexibility will help developers to break free from the constraints of predefined styles and animations, fostering innovation and unique design solutions. Keep coding!&lt;/p&gt;




&lt;h2&gt;
  
  
  Is your frontend hogging your users' CPU?
&lt;/h2&gt;

&lt;p&gt;As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, &lt;a href="https://lp.logrocket.com/blg/css-signup"&gt;try LogRocket&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/css-signup"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dgonwT9o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.logrocket.com/wp-content/uploads/2019/12/cpu-memory-usage.png" alt="LogRocket Signup" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/css-signup"&gt;LogRocket&lt;/a&gt; is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.&lt;/p&gt;

&lt;p&gt;Modernize how you debug web and mobile apps — &lt;a href="https://lp.logrocket.com/blg/css-signup"&gt;Start monitoring for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Leveraging TypeScript for domain-driven design</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Thu, 11 Jan 2024 17:33:23 +0000</pubDate>
      <link>https://dev.to/logrocket/leveraging-typescript-for-domain-driven-design-76f</link>
      <guid>https://dev.to/logrocket/leveraging-typescript-for-domain-driven-design-76f</guid>
      <description>&lt;p&gt;Domain-driven design (DDD) is a software development approach that aims to simplify the creation of applications that involve complex business logic. In this article, we’ll explore how to leverage TypeScript for DDD. TypeScript’s sophisticated type system enables fine-grained domain modeling and is highly adaptable, lending itself to complex app development. &lt;/p&gt;

&lt;p&gt;We’ll dive into the main principles and guidelines of domain-driven design, discuss how TypeScript can assist with DDD, and investigate if DDD can benefit frontend programming. We’ll also take a look at a domain-driven design example written in TypeScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is domain-driven design?
&lt;/h2&gt;

&lt;p&gt;In software engineering, a domain is the specific area of knowledge used by the computer program. In other words, the domain of software is the subject area where the software applies. &lt;/p&gt;

&lt;p&gt;For example, if we develop an infotainment application for a car model, the domain will be automotive. Different domains often bring different definitions for the same concepts. For instance, the word “engine” in the automotive domain might convey a different meaning in another domain. &lt;/p&gt;

&lt;p&gt;When we model our software based on the specific domain we’re in, we talk about domain-driven design. With this approach, the terms used in our source code, such as class names, method names, and so forth, should match concepts in the business domain. Going back to the automotive infotainment system, we might have classes called &lt;code&gt;Radio&lt;/code&gt;, &lt;code&gt;Engine&lt;/code&gt;, &lt;code&gt;Wheel&lt;/code&gt;, &lt;code&gt;MusicTrack&lt;/code&gt;, and so on. &lt;/p&gt;

&lt;p&gt;Generally speaking, to structure code like this, programmers must interact with domain experts, to understand the context their software will be working within.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principles of domain-driven design
&lt;/h2&gt;

&lt;p&gt;The main aim of domain-driven design is to simplify the creation of complex applications by combining several, smaller, pieces of software into a business model. &lt;/p&gt;

&lt;p&gt;Here are the main principles of DDD:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The primary focus is on the core domain and domain logic. This means we have to identify what the core domain or main area of knowledge, is, both in terms of information and behavior&lt;/li&gt;
&lt;li&gt;  The software design is based on a model of the domain. Once we identify the core domain and model it in our software, the rest of the design should follow&lt;/li&gt;
&lt;li&gt;  Technical and domain experts must collaborate to iteratively refine a conceptual model of the domain. The input of the domain experts helps the programmers understand how to model the core domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main building block for business models are entities, or objects that have an important meaning in the domain of interest. Several other object types work on entities. For instance, factories are components that are meant to create a single entity or a group of them, hiding the initialization details from the users. &lt;/p&gt;

&lt;p&gt;Similarly, repositories deal with persisting entities somewhere, for example on a database. Lastly, services model specific operations in a business logic. &lt;/p&gt;

&lt;p&gt;In the automotive domain, for instance, we may have a &lt;code&gt;MusicTrack&lt;/code&gt; entity modeling a music track stored somewhere in our car infotainment system. A &lt;code&gt;MusicTrackRepository&lt;/code&gt; class could be responsible for storing new music tracks, retrieving information on existing tracks, and deleting them. Similarly, we might have a &lt;code&gt;MusicService&lt;/code&gt; to play selected tracks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros and cons of domain-driven design
&lt;/h2&gt;

&lt;p&gt;The main benefit of domain-driven design is that the main concepts, or entities, are defined at the very beginning of the project. This leads to easy communication because everything has a fixed meaning and there are no ambiguities. &lt;/p&gt;

&lt;p&gt;Furthermore, modeling entities, services, factories, and repositories with objects, while following the principles of object-oriented design, results in a codebase that’s easier to maintain in the long run. Typically, each component has a well-defined scope and responsibility, enhancing the encapsulation and modularity of the software. &lt;/p&gt;

&lt;p&gt;However, DDD requires very strong domain-related knowledge. It lends itself to projects with very complex business logic, like our infotainment system. &lt;/p&gt;

&lt;p&gt;Projects with very complex technical requirements (e.g., performance) or with a relatively simple business logic (e.g., an embedded system for processing only a few signals) are generally less suitable for DDD.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can domain-driven design benefit from TypeScript?
&lt;/h2&gt;

&lt;p&gt;Domain-driven design is suitable for problems with complex business logic. TypeScript’s powerful type system enables very fine-grained domain modeling. Several TypeScript features are useful in this regard, like &lt;a href="https://blog.logrocket.com/level-up-typescript-record-types/" rel="noopener noreferrer"&gt;record types&lt;/a&gt;, &lt;a href="https://blog.logrocket.com/types-vs-interfaces-typescript/" rel="noopener noreferrer"&gt;union and intersection types, tuples, literal types&lt;/a&gt;, and &lt;a href="https://blog.logrocket.com/using-typescript-generics-create-reusable-components/" rel="noopener noreferrer"&gt;generics&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;By leveraging these features when needed, we can write type-safe, readable, and maintainable codebases. A clean and well-defined domain model also offers the benefit of being a useful documentation tool. &lt;/p&gt;

&lt;p&gt;One of TypeScript’s primary strengths is that its sophisticated type system lets us pick features as needed, employing and adapting the language to several software design frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain-driven design and frontend
&lt;/h2&gt;

&lt;p&gt;Domain-driven design offers a nice way to design our business model. With DDD, the complexity of the backend grows along with the business requirements, keeping the model and the requirements aligned. &lt;/p&gt;

&lt;p&gt;Whether or not this is also true for frontend codebases depends on several factors. Many frontend codebases deal more with technical complexity, like choosing the right technology stack, rather than with the complexity of the business domain. &lt;/p&gt;

&lt;p&gt;It’s often preferable to centralize the domain model in the backend, possibly creating subdomains (i.e., projections of the main domain model) dedicated to the frontend. This way, the frontend won’t contain any reference to the business logic. &lt;/p&gt;

&lt;p&gt;Some frontend projects may not have a backend, in which case, domain-driven design can be a good choice. Furthermore, it may be beneficial to also &lt;a href="https://blog.logrocket.com/build-micro-frontend-application-react/" rel="noopener noreferrer"&gt;leverage micro-frontends&lt;/a&gt;, which are quite similar to microservices and enable us to break down a complex frontend into smaller, simpler parts. &lt;/p&gt;

&lt;p&gt;When a micro-frontend does not have a backend behind it, leveraging DDD can help further simplify the domain complexity of the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  An example of domain-driven design
&lt;/h2&gt;

&lt;p&gt;To better understand how TypeScript can be used for data-driven design, let’s take a look at a simple application that is used to manage sports competition records.&lt;/p&gt;

&lt;h3&gt;
  
  
  The entity
&lt;/h3&gt;

&lt;p&gt;Entity objects are the main components of the domain model. Here’s an example of an entity from our TypeScript application, recording the best times of the competitors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Competition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;maleRecordInSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
    &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;femaleRecordInSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maleRecordInSeconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mr&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;femaleRecordInSeconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fr&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The repository
&lt;/h3&gt;

&lt;p&gt;We can use repository components to retrieve entities, or aggregates of entities, from a means of storage, such as a database. The goal of this type of component is to hide the complexity of the underlying storage layer. Ideally, they should be declared as interfaces, so that we can easily swap one concrete implementation for another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CompetitionRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Competition&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="nf"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Competition&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
    &lt;span class="c1"&gt;// more CRUD-based functions here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySQLCompetitionRepository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CompetitionRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Competition&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Competition&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The service
&lt;/h3&gt;

&lt;p&gt;We can use service classes to model operations that do not belong to any other objects. For example, they can be the entry point to model and implement the use cases of our application. In this case, their implementations make use of different repositories to fetch the entities and possibly modify them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CompetitionService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setNewFemaleRecordForCompetition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Competition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// 1\. get competition from DB using MySQLCompetitionRepository&lt;/span&gt;
                &lt;span class="c1"&gt;// 2\. set new record&lt;/span&gt;
                &lt;span class="c1"&gt;// 3\. store new object in the DB&lt;/span&gt;
                &lt;span class="c1"&gt;// 4\. return new object&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layers
&lt;/h3&gt;

&lt;p&gt;When organizing the TypeScript code, we can divide it into different layers. Here are the most widely used layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Domain&lt;/strong&gt;: Contains our business model, as well as the definitions of the repositories (not the current implementations!)&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Infrastructure&lt;/strong&gt;: Contains the implementation of the repository classes, as well as any other component that depends on the actual application context (e.g., message brokers)&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Application&lt;/strong&gt;: Defines the services and models the use cases of the application&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Presentation&lt;/strong&gt;: User interface-related logic, if any&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we explored the main principles, terminology, and concepts associated with modeling software according to domain-driven design. We discussed cases where DDD is most beneficial, and when it’s more advantageous to look for another modeling pattern. &lt;/p&gt;

&lt;p&gt;We also mentioned some lifesaving TypeScript features that turn out to be very useful in modeling complex business domains and explored the idea of applying domain-driven design to frontend and micro-frontend projects. &lt;/p&gt;

&lt;p&gt;Even though DDD is more backend-oriented, we can apply its principles and ideas to the frontend world as well. Lastly, we reviewed a simple, yet practical, example of DDD in TypeScript. &lt;/p&gt;

&lt;p&gt;Domain-driven design is just a set of guidelines to model our business domain and regulate the way we develop an application. Of course, no design pattern will ever apply to all domains, scenarios, and application types. In fact, each pattern is just another tool on our belt. Modern software design is an iterative process and we, as engineers and developers, can select one pattern over the other.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://lp.logrocket.com/blg/typescript-signup" rel="noopener noreferrer"&gt;LogRocket&lt;/a&gt;: Full visibility into your web and mobile apps
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/typescript-signup" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgytow1cup40vuqnyvwdl.png" alt="LogRocket Signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/typescript-signup" rel="noopener noreferrer"&gt;LogRocket&lt;/a&gt; is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.&lt;/p&gt;

&lt;p&gt;In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/typescript-signup" rel="noopener noreferrer"&gt;Try it for free&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Using EvaDB to build AI-enhanced apps</title>
      <dc:creator>Matt Angelosanto</dc:creator>
      <pubDate>Wed, 10 Jan 2024 19:46:10 +0000</pubDate>
      <link>https://dev.to/logrocket/using-evadb-to-build-ai-enhanced-apps-1ne1</link>
      <guid>https://dev.to/logrocket/using-evadb-to-build-ai-enhanced-apps-1ne1</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://blog.logrocket.com/author/rosariodechiara/" rel="noopener noreferrer"&gt;Rosario De Chiara&lt;br&gt;
&lt;/a&gt;✏️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;EvaDB is a comprehensive, open source framework that developers can use to add AI-powered regression, classification, image recognition, and question answering to their applications. &lt;/p&gt;

&lt;p&gt;EvaDB queries can be executed over data stored in existing SQL and vector database systems. The data can be manipulated by using pre-trained AI models from Hugging Face, OpenAI, YOLO, PyTorch, and other AI engines. &lt;/p&gt;

&lt;p&gt;In this article, we’ll demonstrate how to include EvaDB in a simple project to provide AI-powered sentiment analysis. Since we’re focusing on how to use the toolkit, we’ll steer away from too much complexity in this guide. However, EvaDB may also be used with OpenAI, PyTorch, or other tools that require API keys or GPU.&lt;/p&gt;
&lt;h2&gt;
  
  
  AI sentiment analysis demo
&lt;/h2&gt;

&lt;p&gt;To easily follow along with the examples in this article, refer to this &lt;a href="https://github.com/rosdec/guide_to_evadb" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;. For our demo, we’ll perform a simple &lt;a href="https://blog.logrocket.com/natural-language-processing-node-js/" rel="noopener noreferrer"&gt;natural language processing (NLP) task&lt;/a&gt; on some of strings (e.g., tweets, posts, or forum comments) in a table: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2023%2F12%2Fevadb-sentiment-analysis-table.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.logrocket.com%2Fwp-content%2Fuploads%2F2023%2F12%2Fevadb-sentiment-analysis-table.png" alt="EvaDB Sentiment Analysis Table"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting started with EvaDB
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://evadb.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;EvaDB&lt;/a&gt; plugs AI into traditional SQL databases, so as a first step, we’ll need to install a database. For this article, we’ll use SQLite because it's fast enough for our tests and does not require a proper database server running somewhere. You may choose a different database, if you prefer.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up the project
&lt;/h2&gt;

&lt;p&gt;To start, install EvaDB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; evadb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://textblob.readthedocs.io/" rel="noopener noreferrer"&gt;TextBlob&lt;/a&gt; is a Python toolkit for text processing. It offers some common NLP functionalities such as part-of-speech tagging and noun phrase extraction. We’ll use TextBlob in our project to perform some quick sentiment analysis on tweets. &lt;/p&gt;

&lt;p&gt;Once we install TextBlob, we’ll have everything we need to start experimenting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; textblob
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the sentiment analysis functions
&lt;/h2&gt;

&lt;p&gt;EvaDB offers a sophisticated, declarative language-extending SQL, designed for crafting AI queries. This language enables software developers to integrate AI-enhanced capabilities into their database applications. &lt;/p&gt;

&lt;p&gt;The following code, from the repo’s &lt;code&gt;analyze_twit.py&lt;/code&gt; file, is simple but contains all the concepts on which EvaDB is based:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;evadb&lt;/span&gt;

&lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;evadb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    CREATE FUNCTION IF NOT EXISTS SentimentAnalysis
        IMPL &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sentiment_analysis.py&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;df&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    CREATE TABLE IF NOT EXISTS twits (
        id INTEGER UNIQUE,
        twit TEXT(140));
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;df&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LOAD CSV &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tweets.csv&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; INTO twits;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;df&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    SELECT twit, SentimentAnalysis(twit) FROM twits    
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;df&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is a sequence of SQL statements executed by using the &lt;code&gt;cursor&lt;/code&gt; object of EvaDB. The first statement defines a new function, &lt;code&gt;SentimentAnalysis&lt;/code&gt;, that will execute a Python script. We’ll talk about this more in just a bit. It’s possible to specify more details about the function (e.g., the types of inputs and outputs), but this is the most basic example and it is good enough for our purposes. &lt;/p&gt;

&lt;p&gt;The second statement creates a table to hold the strings that we’ll analyze. We load them from the &lt;code&gt;tweets.csv&lt;/code&gt; file right into the table. &lt;/p&gt;

&lt;p&gt;The last statement performs the analysis by calling the &lt;code&gt;SentimentAnalysis&lt;/code&gt; function on each row of the table. Just appreciate how easily it integrates into the standard SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SentimentAnalysis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AbstractFunction&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SentimentAnalysis&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="nd"&gt;@setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cacheable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;function_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object_detection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batchable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Setup&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;input_signatures&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="nc"&gt;PandasDataframe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;twit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;column_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NdArrayType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STR&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;column_shapes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,)],&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;output_signatures&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="nc"&gt;PandasDataframe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;label&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;column_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NdArrayType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STR&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;column_shapes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,)],&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;tb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TextBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;sentiment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;polarity&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;twit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;label&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function above is pretty simple (just two methods and a property), but it contains everything we need to see how EvaDB handles the interaction between the data from the traditional SQL engine and any additional engine you may wish to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing the tweets
&lt;/h2&gt;

&lt;p&gt;To keep things simple, we’ll use the sentiment analysis provided by TextBlob; we won’t need an API key or external dependencies. EvaDB uses &lt;a href="https://peps.python.org/pep-0318/" rel="noopener noreferrer"&gt;Python Decorators&lt;/a&gt; to add information to any specific methods that we want to implement. &lt;/p&gt;

&lt;p&gt;The abstract method &lt;code&gt;setup&lt;/code&gt; will create the running environment and can be used to initialize the parameters for executing the function. It must be implemented in our function. The following parameters must be set in the decorator:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;cacheable:bool&lt;/code&gt;&lt;/strong&gt;: When this parameter is &lt;code&gt;True&lt;/code&gt;, the cache should be enabled and will be automatically invalidated when the function changes. When this parameter is &lt;code&gt;False,&lt;/code&gt; the cache should not be enabled. This parameter is used to instruct EvaDB to cache the results of the function’s call. This will accelerate the execution of the function with the same parameters. If a function with the same set of parameters (e.g., image, string, or a generic chunk of data) could behave differently because of the non-determinism of the model, then the &lt;code&gt;cacheable&lt;/code&gt; parameter should be &lt;code&gt;False&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;function_type:str&lt;/code&gt;&lt;/strong&gt;: This function is for object detection&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;batchable:bool&lt;/code&gt;&lt;/strong&gt;: If this parameter is &lt;code&gt;True,&lt;/code&gt; batching will be enabled; otherwise, the batching is disabled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Any additional arguments needed to create the function can be passed as arguments to the &lt;code&gt;setup&lt;/code&gt; function to perform some specific initialization for our environment. Similarly, the new function must implement the &lt;code&gt;forward&lt;/code&gt; abstract method. This function is responsible for receiving chunks of data (e.g., frames, strings, prompts) and executing the function logic. &lt;/p&gt;

&lt;p&gt;This is where our deep learning model will execute on the provided data and where the logic for transforming the input data will run. Use of the &lt;code&gt;forward&lt;/code&gt; decorator is optional. &lt;/p&gt;

&lt;p&gt;Ensure that the following arguments are passed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;input_signatures: List[IOArgument]&lt;/code&gt;&lt;/strong&gt;: Specifies the data types of the inputs expected by the &lt;code&gt;forward&lt;/code&gt; function. If no constraints are provided, no validation is performed on the inputs&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;output_signatures: List[IOArgument]&lt;/code&gt;&lt;/strong&gt;: Specifies the data types of the outputs expected from the &lt;code&gt;forward&lt;/code&gt; function. If no constraints are given, no validation is carried out on the outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The column names in the dataframe must correspond with the names specified in the decorators. At the time of writing, the following input and output arguments are available: &lt;code&gt;NumpyArray&lt;/code&gt;, &lt;code&gt;PyTorchTensor&lt;/code&gt;, and &lt;code&gt;PandasDataframe&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In the code above, we specify the &lt;code&gt;PandasDataframe&lt;/code&gt; package in the decorators for both the input and output data. The input consists of one column (the &lt;code&gt;column_shapes&lt;/code&gt; parameter) named &lt;code&gt;'twit'&lt;/code&gt; (the &lt;code&gt;column&lt;/code&gt; parameter) containing a string (the &lt;code&gt;column_type&lt;/code&gt; parameter). The output has a similar shape and type, but the column is named &lt;code&gt;'label'&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Our goal is to conduct sentiment analysis on a bunch of tweets. Our function will consume and produce an evaluation of each string’s sentiment. &lt;/p&gt;

&lt;p&gt;The logic of the &lt;code&gt;forward&lt;/code&gt; function is fairly simple. The function will be invoked on every row of the &lt;code&gt;twits&lt;/code&gt; table, returning the following result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    SELECT twit, SentimentAnalysis(twit) FROM twits    
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;df&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On every invocation, the &lt;code&gt;forward&lt;/code&gt; function will receive the &lt;code&gt;frames&lt;/code&gt; parameter containing the &lt;code&gt;PandasDataframe&lt;/code&gt; input that, in our case, will be a simple &lt;code&gt;string&lt;/code&gt;. At this point, we just have to initialize &lt;code&gt;TextBlob&lt;/code&gt; with each string contained in the &lt;code&gt;frames&lt;/code&gt; parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt; &lt;span class="n"&gt;tb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TextBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;sentiment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;polarity&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;twit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function is marked as &lt;code&gt;batchable&lt;/code&gt;, meaning we may expect more than one row in the input dataframe. Therefore, the &lt;code&gt;TextBlob&lt;/code&gt; sentiment analysis function will be called on each row in the dataframe. &lt;/p&gt;

&lt;p&gt;The successive line of the &lt;code&gt;forward&lt;/code&gt; function will just manipulate the &lt;code&gt;tb&lt;/code&gt; array with the sentiment analysis result which will be packaged and returned to us in a dataframe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;EvaDB has the potential to convey the power of a wide range of so-called AI engines to the most traditional approach to manipulating data: SQL. &lt;/p&gt;

&lt;p&gt;Adding functions to SQL isn’t new — the glorious &lt;a href="https://blog.logrocket.com/build-rest-api-node-express-mysql/#advanced-example-using-store-procedures" rel="noopener noreferrer"&gt;store procedures&lt;/a&gt; have been available for decades. However, EvaDB is tailored to the specific task of accommodating a number of AI engines right in the code, saving us from handling interfaces and API keys and translating input and outputs between the engine and the SQL code. This approach is new and contains some good ideas – just consider that IBM is starting to provide &lt;a href="https://www.ibm.com/docs/en/db2-for-zos/13?topic=running-ai-queries-sql-data-insights" rel="noopener noreferrer"&gt;similar functionalities in DB2&lt;/a&gt;, a mammoth enterprise-grade RDBMS. &lt;/p&gt;

&lt;p&gt;Another benefit of EvaDB is that it allows the use of standard types for the inputs and outputs of our function. This assures expansion in the most general case of using libraries and engines not explicitly foreseen by EvaDB, like we did with TextBlob. &lt;/p&gt;

&lt;p&gt;A similar approach is followed by &lt;a href="https://docs.dask.org/en/stable/" rel="noopener noreferrer"&gt;Dask&lt;/a&gt;, a library that allows developers to execute parallel Python code within SQL statements. In some respects, Dask can be thought of as an EvaDB competitor, although EvaDB is more focused on the task of using AI Engine in SQL. &lt;/p&gt;

&lt;p&gt;I hope you enjoyed this article and will experiment with including EvaDB in your projects.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get set up with LogRocket's modern error tracking in minutes:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://logrocket.com/signup/" rel="noopener noreferrer"&gt;https://logrocket.com/signup/&lt;/a&gt; to get an app ID.&lt;/li&gt;
&lt;li&gt;Install LogRocket via NPM or script tag. &lt;code&gt;LogRocket.init()&lt;/code&gt; must be called client-side, not server-side.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save&lt;/span&gt; logrocket 

// Code:

import LogRocket from &lt;span class="s1"&gt;'logrocket'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
LogRocket.init&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app/id'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Script Tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.lr-ingest.com/LogRocket.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogRocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.(Optional) Install plugins for deeper integrations with your stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Redux middleware&lt;/li&gt;
&lt;li&gt;  ngrx middleware&lt;/li&gt;
&lt;li&gt;  Vuex plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://lp.logrocket.com/blg/signup" rel="noopener noreferrer"&gt;Get started now&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
