loading...

Discussion on: Lets Build Web Components! Part 3: Vanilla Components

Collapse
jimisdrpc profile image
jimisdrpc

Two questions: 1 - Since you added "unpkg.com/@webcomponents/webcompon..." doesn't it mean you are using polifills and then not really using Vanilla Components? By Vanilla Components I understand you are reling on on native Browser features to create a reuseable web components. 2 - What is the best approach in your opinion to work with Vanilla Components and consume rest service? I guess you would recommend add some third library (eg. React, Angular, Redux ou Lit-html) if I want to consume some NodeJs backend. If so, which one you recommend that I will not face surprises for most general cases.

Collapse
bennypowers profile image
Benny Powers đŸ‡źđŸ‡±đŸ‡šđŸ‡Š Author

The webcomponents-loader.js polyfill will only load the code that's needed, so most of your users will not have to load any polyfill code and will just run the native APIs. For users on older browsers, the polyfills will load and simulate the native behaviour so that your site will be accessible to more users. See my post on the polyfills for more information.

To fetch data from a REST API, I recommend the browser-built-in Fetch API

For more complicated apps you can use a state container like redux if you like. Lately I've been moving away from that towards app shell architectures.

If you're using graphql, why not check out lit-apollo

Collapse
jimisdrpc profile image
jimisdrpc

Hi Benny. I have been doing several POCs (Prove of Concept) regard Vanilla Web-Components. One scenario is an alife dashboard created as Vanilla Webcomponent wich will connect via SSE to either a NodeJS or SpringFlux service that basically consume a Kafka. So it is WebComponent <- SSE Service <- Kafka topic or Kafka Stream. Now I am trying to unit test my webcomponent and I am failling on it. After read around, I am trying to use WCT but I am woondering if I am using the correct tool. Since I am coding a Vanilla WebComponent and WCT is provided by Polymer I am not sure I am in the right path. How arer you unit testing your vanilla webcomponents? You can find my whole POC in github.com/jimisdrpc/simplest-webc... and its backend in github.com/jimisdrpc/simplest-kafk.... If you want to see the error I am getting with WCT is well described in stackoverflow.com/questions/569084.... PS. it will be my pleasure chat with you via stackoverflow.

Thread Thread
bennypowers profile image
Thread Thread
jimisdrpc profile image
jimisdrpc

Benny, I have been studding open-wc but I am wondering if they are promoving really vanilla webcomponents or they are somehow promoving lit-html which I understand it is kind of new flavour of polymer from Google. See their vanilla example importing lit-html from github.com/open-wc/example-vanilla.... I am not saying is bad or worst, I am just interested to really learn webcomponent deepelly and avoid frameworks at least for now. What is your opinion? Is the code bellow really a vanilla webcomponent? I see extending from HTMLElement (vanilla) but importing lit-html.

import { html, render } from 'lit-html';
export default class ExampleVanilla extends HTMLElement {...

Thread Thread
bennypowers profile image
Benny Powers đŸ‡źđŸ‡±đŸ‡šđŸ‡Š Author

Puts on open-wc hat đŸŽ©

At the moment open-wc certainly recommends lit-element. I don't think that's likely to change in the future, but if course it may. Surely, for now we think it's the best way to go.

However, while we think you'll have the best DX and performance with lit-element, our tools support any web components - after all web components are about interoperability.

Takes off open-wc hat đŸŠČ

I totally relate to your concerns about framework lock. Don't worry though: custom elements and the DOM provide strong encapsulation for your components' APIs. At work, were slowly migrating our front end away from angularjs. It's painful mostly because of the lack of DOM support. We're making it work though, with things like ng-custom-element to enable us to pass objects from the angular scope to the DOM.

Inside components we've already migrated to lit-element, however, it's a different story. We are free to (and do) bring in components from other libraries as needed.

An approach I take is to select by id in my shadow CSS rather than tag name, in case we decide to swap out a component's implementation later on.

- my-button {
+ #submit-button {

Is it the best idea to load multiple web component libraries on the front end? Probably not - we don't need the extra bundle bloat, it's nice to align around one interface on a team. We need to move fast though. If the datepicker we need is implemented with polymer instead of lit-element, that's fine and dandy. We'll bring in the polymer version today, and if we find the time later, maybe will implement it ourselves with lit, or swap it for a newer 3rd party version. And WRT bundle size, we could fit 10 lit-elements in the bundle space of one angularjs, so we're already winning.

So I don't think if lit-element as a "framework" per-se. They only non-standards APIs it gives are templating, converting attributes, and observed properties, and all if those are provided as mixins to HTMLElement. If we work the whole thing with some shiny new API like the very-cool hybrids or haunted, it wouldn't be so easy to replace a component's base class (or more broadly, helper library). If we opted for something magical and bespoke like svelte, all the moreso.

Putting it another way, if you're starting from scratch, much of the knowledge you'll gain learning lit-element will apply to other web component libraries and frameworks, where the reverse might not be true.

tl;dr: lit-element stays "closer to the metal" while patching some features missing from the browser and smoothing over some rough APIs that are there. That's the level of abstraction that my team has found most helpful.

Thread Thread
jimisdrpc profile image
jimisdrpc

Hello Benny. Have you tried code a WebComponent splitted in two files (javascript and html)? If so, how do you uit test it? Maybe you could try give your opinion how to fix github.com/open-wc/open-wc/issues/730 or stackoverflow.com/questions/575024.... The problem is I didn't find some way to unit test when I have a Vanilla WebComponent separated in two files, html and javascript. In github.com/jimisdrpc/skyscanner-op... you find a webcomponent composed by two files: src/skyscanner-flight-search/skyscanner-flight-search.html and src/skyscanner-flight-search/skyscanner-flight-search.js. If you try my unit test test/skyscanner-flight-search.test.js you will see that window.customElements.whenDefined('skyscanner-flight-search') will never be resolved. Anyl trick how uniit test a Vanilla WebComponent splitted int two files will be appreciatted.

Thread Thread
bennypowers profile image
Benny Powers đŸ‡źđŸ‡±đŸ‡šđŸ‡Š Author

Hello,

I didn't look too deeply into your code, it looks like you've solved most of the problems already. It did seem like you were having a bit of trouble with one of your unit tests, though.

Try this:

describe('skyscanner flight search', function() {
  it('show div', async function() {
    const el = await fixture(html`<skyscanner-flight-search></skyscanner-flight-search>`);
    console.debug('before promise');
    await window.customElements.whenDefined('skyscanner-flight-search')
    console.debug('after promise');
    expect(el).to.exist;
  });
});
Thread Thread
jimisdrpc profile image
jimisdrpc

Thanks for you promptly answer. Well, you removed the most relevant part of my test: el.shadowRoot.querySelector('#firstdiv2');. Basically, I want to check if there is a div with id firstdiv2 and it must fail since the correct id is firstdiv. Your suggestion will pass but, as fafr as I ccan see, you are just checking if the fixture works; you aren't checking anything from the webcomponent html.

Thread Thread
jimisdrpc profile image
jimisdrpc

Based on your suggestion, I found a solution:

import { html, fixture, expect } from '@open-wc/testing';

import '../src/skyscanner-flight-search/skyscanner-flight-search.js';

describe('skyscanner flight search', () => {
it('show div', async() => {
const el = await fixture(html
<skyscanner-flight-search></skyscanner-flight-search>
);
await window.customElements.whenDefined('skyscanner-flight-search')
expect(el.shadowRoot.querySelector('#firstdiv')).to.exist;

});

it('show input for session key', async() => {
    const el = await fixture(html `
  <skyscanner-flight-search></skyscanner-flight-search>
`);
    await window.customElements.whenDefined('skyscanner-flight-search')
    expect(el.shadowRoot.querySelector('#inputSessionKey')).to.exist;
});

});

Thread Thread
jimisdrpc profile image
jimisdrpc

What is your opinion about how I am testing? IN few words, it is based on Karma + Mocha and depending on fixture approaches.

Thread Thread
bennypowers profile image
Benny Powers đŸ‡źđŸ‡±đŸ‡šđŸ‡Š Author

if your goal is to test that the shadow root renders the way you expect, I suggest using the open-wc package semantic-dom-diff, which is built-in to open-wc's testing setup, like so:

import { expect, fixture } from `@open-wc/testing`;

describe('skyscanner flight search', function() {
  it('should render the correct Shadow DOM', async function() {
    const el = await fixture(`<skyscanner-flight-search></skyscanner-flight-search>`);
    await window.customElements.whenDefined('skyscanner-flight-search')
    expect(el).shadowDom.to.equal(`
      <!-- this dom string will be semantically compared to the real dom -->
      <!-- comments will be stripped out -->
      <!-- and you'll get a helpful diff as otuput if you use open-wc's testing setup -->
      <div id="firstDiv"></div>
      <input id="inputSessionKey"/>
    `);
  });
});