<?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: Manuel Martín</title>
    <description>The latest articles on DEV Community by Manuel Martín (@manolakis).</description>
    <link>https://dev.to/manolakis</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%2F29809%2F9ad2aad8-d403-4d18-bf09-830fcecf1b4a.jpg</url>
      <title>DEV Community: Manuel Martín</title>
      <link>https://dev.to/manolakis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manolakis"/>
    <language>en</language>
    <item>
      <title>The evolution of Open-wc scoped-elements</title>
      <dc:creator>Manuel Martín</dc:creator>
      <pubDate>Mon, 06 Apr 2020 06:11:09 +0000</pubDate>
      <link>https://dev.to/open-wc/the-evolution-of-open-wc-scoped-elements-195b</link>
      <guid>https://dev.to/open-wc/the-evolution-of-open-wc-scoped-elements-195b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;In this blog post I'm going to talk about the evolution of &lt;code&gt;@open-wc/scoped-elements&lt;/code&gt; package. If you want to know the context behind it and why we created it, you might want to read my previous &lt;a href="https://dev.to/open-wc/open-wc-scoped-elements-3e47"&gt;blog post&lt;/a&gt; first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A few months ago we shipped the first experiment about scoping web component definitions, &lt;code&gt;@open-wc/scoped-elements&lt;/code&gt;, allowing us to use in our apps different versions of the same components. Since then, we learned and improved some things about using scoped elements that I would like to share with you in this post.&lt;/p&gt;

&lt;p&gt;First, we improved our development experience. From using the &lt;code&gt;createScopedHtml&lt;/code&gt; function we have gone to using a Mixin for our LitElement components, so now the use of scoped-elements looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;LitElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lit-element&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;ScopedElementsMixin&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;@open-wc/scoped-elements&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;FeatureA&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;feature-a&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;FeatureB&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;feature-b&lt;/span&gt;&lt;span class="dl"&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;class&lt;/span&gt; &lt;span class="nx"&gt;PageA&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;ScopedElementsMixin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LitElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;scopedElements&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;feature-a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feature-b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureB&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="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;styles&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;css&lt;/span&gt;&lt;span class="s2"&gt;`
      :host {
        display: block;
        padding: 10px;
        border: 2px solid #ccc;
      }
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&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;html&lt;/span&gt;&lt;span class="s2"&gt;`
      &amp;lt;h3&amp;gt;I am page A&amp;lt;/h3&amp;gt;
      &amp;lt;feature-a&amp;gt;&amp;lt;/feature-a&amp;gt;
      &amp;lt;feature-b&amp;gt;&amp;lt;/feature-b&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As developers, we can now apply the &lt;code&gt;ScopedElementsMixin&lt;/code&gt; to our component and add the static &lt;code&gt;scopedElements&lt;/code&gt; method, with the elements that we want to scope. So far so good!&lt;/p&gt;

&lt;p&gt;But, what happens if we don't know which element we want to use at the moment of the scoped elements definition? It could happen, for example, that we may want to lazy-load some components. To cover this use-case the mixin has a method named &lt;code&gt;defineScopedElement(tagName, element)&lt;/code&gt; that allows us to define scoped elements at any time. Let's see an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;LitElement&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;lit-element&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;ScopedElementsMixin&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;@open-wc/scoped-elements&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;MyPanel&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;./MyPanel.js&lt;/span&gt;&lt;span class="dl"&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;class&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;ScopedElementsMixin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LitElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;scopedElements&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;my-panel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyPanel&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;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connectedCallback&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./MyButton.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;MyButton&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defineScopedElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyButton&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&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;html&lt;/span&gt;&lt;span class="s2"&gt;`
      &amp;lt;my-panel class="panel"&amp;gt;
        &amp;lt;my-button&amp;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;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/my-button&amp;gt;
      &amp;lt;/my-panel&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the previous example, &lt;code&gt;my-button&lt;/code&gt; is not registered as a scoped element in the static &lt;code&gt;scopedElements&lt;/code&gt; method because it is loaded lazily, and once loaded it is defined through the &lt;code&gt;definedScopedElement&lt;/code&gt; function, which causes the tag &lt;code&gt;my-button&lt;/code&gt; to be upgraded to the actual component.&lt;/p&gt;

&lt;p&gt;Last but not least, it could also happen that in an awesome feature you are implementing you need to get a scoped tag name for any other reason or perhaps you want to create the element through &lt;code&gt;document.createElement&lt;/code&gt; 🤷‍♂️.&lt;/p&gt;

&lt;p&gt;Static method &lt;code&gt;getScopedTagName&lt;/code&gt; to the rescue! This method returns the scoped tag name used by your component for a specific tag name. Even if the component that uses that tag name is not yet defined! (remember, lazy components 😉).&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;LitElement&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;lit-element&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;ScopedElementsMixin&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;@open-wc/scoped-elements&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;MyPanel&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;./MyPanel.js&lt;/span&gt;&lt;span class="dl"&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;class&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;ScopedElementsMixin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LitElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;scopedElements&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;my-panel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyPanel&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="kd"&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;super&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;scopedTagName&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="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getScopedTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-panel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// do whatever you need with the scopedTagName&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;But those are not the only improvements made by the use of the mixin. Another important point is that this type of use will probably allow us to upgrade our mixin to use &lt;a href="https://gist.github.com/justinfagnani/d67d5a5175ec220e1f3768ec67a056bc"&gt;scoped custom element registries&lt;/a&gt; behind the scenes once they are a reality, so our applications will not need to be migrated whenever this happens. Great, isn't it? 🤗&lt;/p&gt;

&lt;p&gt;Finally, scoped-elements has been very useful in my company because we have a large shared component library that recently released a major version, and scoped-elements allows us to migrate our apps seamlessly without doing a big bang.&lt;/p&gt;

&lt;p&gt;You can find more information about scoped-elements in &lt;a href="https://open-wc.org/"&gt;Open-wc&lt;/a&gt; website.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>litelement</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>Open-wc scoped-elements</title>
      <dc:creator>Manuel Martín</dc:creator>
      <pubDate>Thu, 23 Jan 2020 14:39:30 +0000</pubDate>
      <link>https://dev.to/open-wc/open-wc-scoped-elements-3e47</link>
      <guid>https://dev.to/open-wc/open-wc-scoped-elements-3e47</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Good frontend development is hard. Scaling frontend development so that many teams can work simultaneously on a large and complex product is even harder." (&lt;a href="https://martinfowler.com/articles/micro-frontends.html"&gt;martinfowler.com - micro frontends&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Micro-frontends, as well as micro-services, are gaining popularity. Many organizations are adopting those architectures allowing multiple autonomous teams to work on the same applications without the limitations of large monoliths.&lt;/p&gt;

&lt;p&gt;To have visual consistency across micro-frontends, one common approach is to have a shared library of reusable UI components, but basing this library on web components could be a problem in certain situations. We are going to create some dumb components to emulate it, analyze the problem, and see how to fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context
&lt;/h2&gt;

&lt;p&gt;Imagine we have the first version of a shared component library, containing two components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;feature-a&lt;/li&gt;
&lt;li&gt;feature-b&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, two pages use those components contained in our shared library. Imagine that each page has been developed by autonomous teams.&lt;/p&gt;

&lt;p&gt;Finally, we have the shell app that contains the pages. Once the app is built we will obtain the following &lt;code&gt;node_modules&lt;/code&gt; tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;├─ node_modules
│  ├─ feature-a@1.0.0
│  │  ├─ feature-a.js
│  │  └─ index.js
│  ├─ feature-b@1.0.0
│  │  ├─ feature-b.js
│  │  └─ index.js
│  ├─ page-a@1.0.0
│  │  ├─ page-a.js
│  │  └─ index.js
│  └─ page-b@1.0.0
│     ├─ page-b.js
│     └─ index.js
├─ demo-app.js
└─ index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So far so good. Everything is up and running and you can check the application &lt;a href="https://open-wc.org/scoped-elements/demo/before-nesting/"&gt;online&lt;/a&gt; [&lt;a href="https://github.com/open-wc/open-wc/tree/master/packages/scoped-elements/demo/before-nesting"&gt;see the code here&lt;/a&gt;].&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---XZgaE5z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/gw1nr0sd8v9oxd4j6z8l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---XZgaE5z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/gw1nr0sd8v9oxd4j6z8l.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Imagine now the requirement of release a breaking change on &lt;code&gt;feature-a&lt;/code&gt; to fulfill new business requirements. A new major version of &lt;code&gt;feature-a&lt;/code&gt; would be released.&lt;/p&gt;

&lt;p&gt;The team in charge of page A has enough time and budget to update their page and implement the required changes using the latest release of &lt;code&gt;feature-a&lt;/code&gt;, but unfortunately, the team in charge of page B has other business priorities before adapting their code to the new version.&lt;/p&gt;

&lt;p&gt;As they are independent teams, each one releases their new page versions and the app is built obtaining the following &lt;code&gt;node_modules&lt;/code&gt; tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;├─ node_modules
│  ├─ feature-a@2.0.0
│  │  ├─ feature-a.js
│  │  └─ index.js
│  ├─ feature-b@1.0.0
│  │  ├─ feature-b.js
│  │  └─ index.js
│  ├─ page-a@1.1.0
│  │  ├─ page-a.js
│  │  └─ index.js
│  └─ page-b@1.1.0
│     ├─ mode_modules
│     │  └─ feature-a@1.0.0
│     │     ├─ feature-a.js
│     │     └─ index.js
│     ├─ page-b.js
│     └─ index.js
├─ demo-app.js
└─ index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As the user tries to &lt;a href="https://open-wc.org/scoped-elements/demo/no-scope/"&gt;execute the application&lt;/a&gt; he/she will find the following error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZVoX31D---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/i1n05yx52mpyhopbyscf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZVoX31D---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/i1n05yx52mpyhopbyscf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking at the web console we can read the following message&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;NotSupportedError: &lt;span class="s1"&gt;'feature-a'&lt;/span&gt; has already been defined as a custom element
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The problem here is that the custom element registry doesn't allow multiple versions of the same element to be registered and we are trying to register two versions of the &lt;code&gt;feature-a&lt;/code&gt; component with the same name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feature-a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FeatureA&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;but why is this happening?&lt;/p&gt;

&lt;p&gt;ES modules are only executed once per URL so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feature-b/feature-b.js&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 both, &lt;code&gt;page-a/index.js&lt;/code&gt; and &lt;code&gt;page-b/index.js&lt;/code&gt;, resolves to &lt;code&gt;node_modules/feature-b/feature-b.js&lt;/code&gt; so it's going to be executed only once. However, doing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feature-a/feature-a.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;in &lt;code&gt;page-a/index.js&lt;/code&gt; resolves to &lt;code&gt;node_modules/feature-a/feature-a.js&lt;/code&gt;&lt;br&gt;
while in &lt;code&gt;page-b/index.js&lt;/code&gt; it resolves to &lt;code&gt;node_modules/page-b/node_modules/feature-a/feature-a.js&lt;/code&gt; therefore these are separate URLs and &lt;code&gt;feature-a&lt;/code&gt; definition will be executed both times.&lt;/p&gt;

&lt;p&gt;If you want to dig deeper into how node resolution works you can read &lt;a href="https://dev.to/open-wc/nested-dependencies-in-frontend-558c#how-node-resolution-works"&gt;this article&lt;/a&gt; which explains it very well.&lt;/p&gt;
&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;There are two possible solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Synchronizing updates of shared dependencies across teams. e.g. make sure all teams always use the same version upon release. This can be a viable solution but it comes with high organizational overhead and is hard to scale. I would discard this option because I want to provide value to the user as soon as possible and this option requires extra work from the teams.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Temporarily (!) allow to ship similar source code (most breaking releases are not a total rewrite) and scope them via &lt;a href="https://open-wc.org/scoped-elements"&gt;@open-wc/scoped-elements&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://open-wc.org/scoped-elements"&gt;@open-wc/scoped-elements&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Recently &lt;a href="https://open-wc.org"&gt;Open-wc&lt;/a&gt; released &lt;a href="https://open-wc.org/scoped-elements"&gt;scoped-elements&lt;/a&gt; as an experiment, allowing us to use different versions of the same web-component in a single document. Let's see how we can use it to fix our sample application.&lt;/p&gt;

&lt;p&gt;First of all, we have to install &lt;code&gt;@open-wc/scoped-elements&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;--save&lt;/span&gt; @open-wc/scoped-elements
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once installed, we have to modify our page's components to use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// page-a/index.js&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;render&lt;/span&gt;&lt;span class="cm"&gt;/*, html */&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;lit-html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// (1)&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;createScopedHtml&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;@open-wc/scoped-elements&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// (2)&lt;/span&gt;
&lt;span class="c1"&gt;// import 'feature-a/feature-a.js'; (3)&lt;/span&gt;
&lt;span class="c1"&gt;// import 'feature-b/feature-b.js'; (3)&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;FeatureA&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;feature-a/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// (4)&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;FeatureB&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;feature-b/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// (4)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createScopedHtml&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="c1"&gt;// (5)&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feature-a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feature-b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeatureB&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;class&lt;/span&gt; &lt;span class="nx"&gt;PageA&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&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;super&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;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&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;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
      &amp;lt;style&amp;gt;:host { display: block; padding: 10px; border: 2px solid #ccc; }&amp;lt;/style&amp;gt;
      &amp;lt;h3&amp;gt;I am page A&amp;lt;/h3&amp;gt;
      &amp;lt;feature-a&amp;gt;&amp;lt;/feature-a&amp;gt;
      &amp;lt;feature-b&amp;gt;&amp;lt;/feature-b&amp;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;shadowRoot&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 see what we did here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Remove the &lt;code&gt;html&lt;/code&gt; function from &lt;code&gt;lit-html&lt;/code&gt; because we must use the &lt;code&gt;createScopedHtml&lt;/code&gt; provided one instead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Import the function &lt;code&gt;createScopedHtml&lt;/code&gt; from &lt;code&gt;scoped-elements&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove the imports that contain the self-definition of the components that we are going to use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Import the component classes that we want to use inside our component. This is an important step because now &lt;code&gt;FeatureA&lt;/code&gt; and &lt;code&gt;FeatureB&lt;/code&gt; components are not self-defined anymore.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;createScopedHtml&lt;/code&gt; to indicate how to use &lt;code&gt;FeatureA&lt;/code&gt; and &lt;code&gt;FeatureB&lt;/code&gt; components inside our component HTML. This function returns another &lt;code&gt;html&lt;/code&gt; function that transforms a template literal into a new one replacing the tags used by the developer with the ones defined by the custom elements. Finally, the transformed template literal is going to be processed by &lt;code&gt;lit-html&lt;/code&gt; returning a &lt;code&gt;TemplateResult&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can see that the &lt;a href="https://open-wc.org/scoped-elements/demo/with-scope/"&gt;final result&lt;/a&gt; [&lt;a href="https://github.com/open-wc/open-wc/tree/master/packages/scoped-elements/demo/with-scope"&gt;see the code here&lt;/a&gt;] works as expected using two different versions of the same component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7qbZoKON--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xp4rocenozqhpkzdfill.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7qbZoKON--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xp4rocenozqhpkzdfill.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;But it's not all fun and games. There are some limitations using &lt;code&gt;scoped-elements&lt;/code&gt; that are important to understand:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Imported components should not be self-registering.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Every component that contains subcomponents must use `scoped-elements´.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Imported components need to be fully side effect free.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Currently, only &lt;code&gt;lit-html&lt;/code&gt; rendering engine is supported.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can not use tag selectors in CSS, but you could use an id, a class name or even a property instead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can not use tag names using javascript querySelectors, but you could use an id, a class name or even a property instead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can not use &lt;code&gt;document.createElement&lt;/code&gt; to create a scoped element, but there is an open &lt;a href="https://github.com/open-wc/open-wc/issues/1270"&gt;issue&lt;/a&gt; to discuss how to improve the API and support it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using &lt;code&gt;scoped-elements&lt;/code&gt; may result in performance degradation of up to 8%.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As a good practice, loading of duplicate/similar source code (most breaking releases are not a total rewrite) should always be a temporary solution. However, temporary solutions tend to become more permanent, so be sure to focus on keeping the lifecycle of nested dependencies short.&lt;/p&gt;

&lt;p&gt;In a nutshell, it is all about stopping components from self-registering and telling them how they should be used. The concept is similar to how &lt;a href="https://gist.github.com/justinfagnani/d67d5a5175ec220e1f3768ec67a056bc"&gt;Scoped Custom Element Registries&lt;/a&gt; is going to work in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join the conversation
&lt;/h2&gt;

&lt;p&gt;If you like this feature please feel free to join the &lt;a href="https://github.com/open-wc/open-wc/issues/1262"&gt;conversation&lt;/a&gt; for feedback, criticism, concerns, or questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;scoped-elements&lt;/code&gt; is an experimental feature, so use it at your own risk and be sure to understand the previous limitations.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webcomponents</category>
      <category>microfrontends</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
