carbon-design-system / carbon-labs

An innovation space for the creation of components leveraging Carbon Design System
Apache License 2.0
13 stars 15 forks source link

[POC]: Investigate feasibility of integrating v11 components into a v10 application #25

Closed jeffchew closed 9 months ago

jeffchew commented 10 months ago

User story

As a [user role below]:

Developer working on an IBM Software product on Carbon v10

I need to:

integrate v11 based Carbon components with AI capabilities

so that I can:

have AI experiences embedded into our product before we fully migrate to Carbon v11

Additional information

Acceptance criteria

lee-chase commented 9 months ago

First up, we think it is possible and Taylor believes he can create an example for product teams to work from.

The system in use by Clayton's team appeared to be one of proxying Carbon 10 and using Carbon 11 directly. Taylor believed this might be possible to do without the proxy project using an alias such as that I shared "@carbon/layout-10": "npm:@carbon/layout@^10.37.1",

Product teams wanting to make a minimal change could, using a proxy project, and compiled Carbon CSS could start using V11 components alongside V10. This could leave the migration of non-component CSS as a separate exercise e.g. type, layout, theme.

Switching from @import to @use and dealing with SASS name spacing is not needed if compiled Carbon V11 CSS is used. Use of compiled CSS, with theming, is permitted by @carbon/ibm-products

Taylor is going to produce an example repository showing the stages of moving from V10 to V11 as described above.

mattrosno commented 9 months ago

@lee-chase thanks! With this, @tay1orjones, I'm curious what other constraints exist. For example, I don't expect us to test this with every version of Webpack and npm... but if we know required Webpack and npm versions to pull this off, it would be great to state that. Knowing non-Carbon constraints would help us determine feasibility with product teams.

tay1orjones commented 9 months ago

From my explorations, to use v10 and v11 in the same project you need:

tay1orjones commented 9 months ago

I want to emphasize that it is possible to run v10 and v11 together without any strenuous configuration. My initial concerns about duplicate transitive dependencies (like downshift) were unfounded. Package managers and bundlers handle duplicate transitive dependencies with different versions just fine, though you do have to be aware of what's happening and the potential caveats you can run into.

[!NOTE]
I have created a stackblitz example showing it is possible to use various components and styles from v10 and v11, including the new Slug. It takes a few moments to load because it has live sass compliation, which takes a bit to complete with v10 styles.

At a high level the process I took was:

  1. Install and configure Carbon v10 (or have an existing application using v10)
  2. Install @carbon/react
  3. Configure the @carbon/react styles with @use
  4. Import v11 components from @carbon/react and icons from @carbon/react/icons

Caveats

The complications we're seeing with some teams running into odd errors stem from an additional layer of sub/transitive dependencies. Often, projects use additional library(ies) that proxy Carbon v10, like Cloud PAL. Sometimes the libraries don't fully proxy carbon but they list carbon as hard dependencies.

[!IMPORTANT]
So far, all the errors we've seen are only styling-based (sass) errors. We haven't seen any javascript errors resulting from mixing v10 and v11. It commonly presents as Sass errors of "mixin not found", "... is not a number", etc. indicating the erroring stylesheet is looking for part of an API that can't be found in that version.

If a developer adds @carbon/react to their project, configures the styles, and then sees an error, it's most likely due to the bundler using a v10 carbon package/dependency when it should be using a v11 one. For instance,

  1. A project is using Carbon v10 via carbon-components@10.x and carbon-components-react@7.x
  2. A developer installs @carbon/react to the project.
  3. Both carbon-components-react@7.x and @carbon/react list @carbon/layout as a dependency:
carbon-components-react@7.x @carbon/react@1.x
"@carbon/layout": "^10.37.2" "@carbon/layout": "^11.20.0"

If the developer brings in styles or js assets from @carbon/layout, which version is used, v10 or v11? In my tests, it uses v10.

Potential solutions

The two approaches we've seen been used successfully to get around this are:

  1. Alias the package names
  2. Isolate the styles

Option 1: Alias the package names

Any package can be aliased to a different name to prevent inadvertent conflicts. For example:

npm install @carbon/layout-v11@npm:@carbon/layout@11

The goal with this approach is to avoid naming conflicts by either aliasing v10 packages, or the v11 packages. If you alias v10 package names, you'll have to update all your existing imports. If you alias v11 packages, your existing imports can stay the same, but new imports for v11 components will have to use the alias. For these style-only errors, it may be easiest to install and alias v11 packages.

The reason this works is because when the bundler goes to look for @carbon/layout for instance, it will only use the non-aliased version. This way you can then specify exactly when/where you want to bring in and use the aliased version, @carbon/layout-v11.

Option 2: isolate the styles

The goal with this approach is to totally separate the v10 and v11 styles into separate stylesheets that are loaded independently via webpack. Here's an example from a cloud team using this approach.

The reason this works is that the imports/use statements are totally separate from one another, which prevents the sass global namespace from being polluted with invalid stylesheets from the other version. v10 styles import carbon-components stylesheets and related sub-dependencies. v11 styles @use '@carbon/react stylesheets and related sub-dependencies.

For bundlers other than webpack it may be more difficult to separate these into isolated execution contexts.

Things to avoid

We've seen the following things cause issues:

Is it worth it?

Maybe! For some teams, this additional overhead is worth it to bide time avoiding a full migration to v11 right now. For others, they'd prefer to work on the actual v11 migration instead of adding more tech debt to their stack. The decision also heavily relies on if the project is using 1 or more PAL libraries, and how intense the configuration of those styles is.

This thinking applies to all the approaches outlined in the initial body of this issue whether it be v10/v11 react mixed use, using web-components in a react/angular app, or using assets from a CDN. The end result is the same: the project fulfills the immediate need of being able to use v11 things like Slug but each path ultimately results in additional tech debt to be paid off later.

Mikadv commented 9 months ago

@tay1orjones Great post! But one point here: How is about duplicate carbon in our chunks. When we pull in carbon 10 and 11 we will have twice carbon in our bundles, making chunks bigger and page load slower. Or do you have some tips to keep the footprint low on those? And maybe also an idea how much that would affect teams? You only talked about transitive deps, that is why I ask.

tay1orjones commented 9 months ago

@Mikadv That's a good question, sorry I didn't directly address it. You're correct - bundle size will temporarily increase with this approach.

Most teams that have taken this approach are okay with paying this bundle-size "price" to facilitate the migration. It's only temporary, and eventually they will be able to remove the carbon-components styles and carbon-components-react js once they're fully migrated to v11.

Impact to javascript bundle size

For javascript imports, treeshaking will still work as you'd expect to only bring in the components you end up using. Icons are bucketed in both v10 and v11, and if you import a @carbon/react component that uses an icon, a collection of new icons in the same bucket will end up in your bundle.

Mitigation

You can reduce the likelihood of this by avoiding using @carbon/react/icons until you migrate all your icon usages at once. We have a codemod available through @carbon/upgrade to assist with this migration.

npx @carbon/upgrade migrate icons-react-size-prop --write
npx @carbon/upgrade migrate update-carbon-icons-react-import-to-carbon-react --write

Also I think this goes without saying, but you want to avoid bringing in anything more than you're using, so avoid things like

import * from '@carbon/react';

Impact to style/css bundle size

Style bundle size is going to increase because you're including new styles for v11. Most v10 projects are going to already be loading all the styles available through carbon-components, then by adding @carbon/react styles it'll probably nearly double in size of total final css output. These two packages use different prefixes for all the selectors so there's no risk of conflicts, but there's effectively quite a bit of duplication while you're running both packages at the same time.

Mitigation

You can mitigate the scope of this increase by selectively @import or @use only the styles you need. Here's an updated version of my initial example that only brings in the individual style modules required for the components on the page: Button, Accordion, Slug (and therefore Toggletip, but this will be included automatically in the future, https://github.com/carbon-design-system/carbon/issues/15341).

lee-chase commented 9 months ago

Further to Taylors investigation I have both updated the Carbon React v11 stackblitz and created a Carbon WebComponents version.

The updates add a theme selector and a Carbon prefix for V10. The prefix is was added to avoid clashes on some CSS settings such as the hover background. It appears to only affect V10 in both versions.

Carbon React V11 with V10 - https://stackblitz.com/edit/github-pdxjpu-8texfv CWC with Carbon V10 - https://stackblitz.com/edit/github-pdxjpu-qkh5qn