DEV Community

Cover image for Use the platform with Web Components
Gabriel Mayta
Gabriel Mayta

Posted on • Edited on

3 2

Use the platform with Web Components

Major browsers support many features like Classes, Arrow Functions, Spread Operator, Template Literals, Instersection Observer, Web Components and with the introduction of ES Modules we can develop Web Applications without the help of module bundlers like Webpack or Rollup.

I know what do you think... Talk is cheap, show me the code!

So I created a repository to share my test with Web Components and ES Modules.
I used the Github's API to develop 3 Web Components:

    <github-profile nickname="timbl"></github-profile>
    <github-repositories nickname="timbl"></github-repositories>
    <github-followers nickname="timbl"></github-followers>
Enter fullscreen mode Exit fullscreen mode

As you can see I added the nickname attribute, I used this attribute to retrieve data from Rest API. With WCs you can use html templates to handle fragments of markup to load with JS. For your information the template content is not render by the browser, but can be instantiated later or at runtime.
Below you can find the profile template:

      <template id="github-profile-template">
         <style>
            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }

            div {
                display: inline-block;
                padding: 20px;
                width: 240px;
                height: 300px;
                border: 2px solid #f0f0f0;
                border-radius: 4px;
                overflow: hidden;
            }
            img {
                width: 100%;
                border-radius: 50%;
            }
            h1 {
                margin-top: 20px;
                font-size: 16px;
                color: #f0f0f0;
                text-transform: uppercase;
                text-align: center;
            }
        </style>
        <div>
            <img>
            <h1></h1>
        </div>
    </template>
Enter fullscreen mode Exit fullscreen mode

Below you can find the javascript classes of every WC and you can see how the templates are loaded:

Github Profile

import http from '../services/http-wrapper.js';
export default class GithubProfile extends HTMLElement {
static get observedAttributes() {
return ['nickname'];
}
get nickname() {
return this.getAttribute('nickname');
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.template = document.querySelector('#github-profile-template');
this.shadowRoot.appendChild(this.template.content);
this.nameEl = this.shadowRoot.querySelector('h1');
this.imageEl = this.shadowRoot.querySelector('img');
}
async attributeChangedCallback() {
const profile = await http.getProfile(this.nickname);
this.render(profile);
}
render(profile) {
const { login, name, avatar_url: avatar } = profile;
this.nameEl.innerText = name || login;
this.imageEl.setAttribute('src', avatar);
}
}
customElements.define('github-profile', GithubProfile);

Github Repositories

import http from '../services/http-wrapper.js';
export default class GithubRepositories extends HTMLElement {
static get observedAttributes() {
return ['nickname'];
}
get nickname() {
return this.getAttribute('nickname');
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.template = document.querySelector('#github-repositories-template');
this.shadowRoot.appendChild(this.template.content);
this.listEl = this.shadowRoot.querySelector('span');
}
repositoriesTpl(repos = []) {
return repos.reduce((acc, repo) => `${acc} ${this.repositoryTpl(repo)}`, '');
}
repositoryTpl(repo) {
const { name, html_url: url } = repo;
return `
<a href="${url}" target="_blank">${name}</a>
`;
}
async attributeChangedCallback() {
const repositories = await http.getRepositories(this.nickname);
this.render(repositories);
}
render(repositories) {
this.listEl.innerHTML = this.repositoriesTpl(repositories);
}
}
customElements.define('github-repositories', GithubRepositories);

Github Followers

import http from '../services/http-wrapper.js';
export default class GithubFollowers extends HTMLElement {
static get observedAttributes() {
return ['nickname'];
}
get nickname() {
return this.getAttribute('nickname');
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.template = document.querySelector('#github-followers-template');
this.shadowRoot.appendChild(this.template.content);
this.listEl = this.shadowRoot.querySelector('span');
}
followersTpl(followers = []) {
return followers.reduce(
(acc, follower) => `${acc} ${this.followerTpl(follower)}`,
''
);
}
followerTpl(follower) {
const { login, html_url: url } = follower;
return `
<a href="${url}" target="_blank">${login}</a>
`;
}
async attributeChangedCallback() {
const followers = await http.getFollowers(this.nickname);
this.render(followers);
}
render(userfollowers) {
this.listEl.innerHTML = this.followersTpl(userfollowers);
}
}
customElements.define('github-followers', GithubFollowers);

I developed a service function to make http calls with Fetch. This function will be load from every WC.

const httpWrapper = {
BASE_URL: 'https://api.github.com',
service: {},
async getConfig(endpoint) {
const response = await fetch(`${this.BASE_URL}/${endpoint}`);
if (!response.ok) return { message: 'Opss, something is wrong!' };
return response.json();
},
getProfile(id) {
return this.getConfig(`users/${id}`);
},
getRepositories(id) {
return this.getConfig(`users/${id}/repos`);
},
getFollowers(id) {
return this.getConfig(`users/${id}/followers`);
}
};
export default httpWrapper;
view raw http-wrapper.js hosted with ❤ by GitHub

And then I created a script file to import my 3 Web Components, I called this file bootstrap.js:

import GithubProfile from './components/github-profile.js';
import GithubRepositories from './components/github-repositories.js';
import GithubFollowers from './components/github-followers.js';
view raw bootstrap.js hosted with ❤ by GitHub

After that I added in the bottom the bootstrap script, I used the type="module" (ES Modules) in the tag:

    <script type="module" src="bootstrap.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

If you open the index.html with your browser, you should see the following files:

Scripts downloaded

To improve performance you can enable HTTPS/2 on server side like Facebook:

Facebook http2

Conclusion

In this project I didn't use Babel, Webpack, libraries or frameworks, but I used the Web Standards and my code is working on Chrome, Safari, Firefox and Opera.
You need polyfill to support Microsoft Edge for now.

The Web is changing so fast in the last years, so maybe in some cases is better to choose the standard.

Links

Keep calm and code!

Top comments (0)

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay