Improvements and Fixes on v1.1.0
This version brings several improvements in the component code and its structure, also it fixes problems and bugs it had, now it works a lot better, it is less dependent and much more agnostic, just as it has to be.
The component now requires less intervention to work properly, it now requires only an import of the component javascript file and that is just it, then the developer only uses the custom tag with its attributes and it just works easily.
Paths
In the component there are elements that require a path, such as images, img tags need an src attribute, and this attribute works better with absolute paths from the project root directory, but from the component perspective, it does not know what is the folders tree and how it is structured, so it used to seem work with relative paths with the location of the component javascript file as the initial reference, but this not always proved to work properly, and this caused the cover background image to not being detected and not load, so this was a problem, and in order to fix it a solution was found, the solution was the import.meta.resolve()
method.
For example, in the html template, to show the ClarkCodes Logos images the previous version was doing it like this:
<button id="clarkCodesLogoImagotypeButtonId">
<img id="clarkCodesLogoImagotypeId" src="../common/images/ClarkCodes Logo OnTransparent_100x100px_300ppi.webp" width="30px" alt="ClarkCodes Logo Imgotipo">
</button>
The path to the image in the src attribute was hardcoded assuming this relative path would be effective, but in some scenarios it did not work making the image not been found and not been shown.
Now this same part of the code is being done this way:
<button id="clarkCodesLogoImagotypeButtonId">
<img id="clarkCodesLogoImagotypeId" src=${import.meta.resolve( '../assets/images/ClarkCodes Logo OnTransparent_100x100px_300ppi.webp' )} width="30px" alt="ClarkCodes Logo Imgotipo">
</button>
This method is capable of resolving dynamically and retrieving properly the absolute path in the site server, matching the beggining of the proper path with the ending part of it that is being specified, so it returns the absolute path to the specified resource, and with this path the img element is able to identify, find the resource and show the image correctly.
This method is also used in the mapComponentAttributes() function to resolve the fallback image path to set it if the 'cover-img' attribute is not provided.
So this implemenation is a new way to resolve paths, agnostic to the project, so images that were not been shown due to not being able to determine paths to them before, now are shown properly.
Svgs
The svg icons to place in buttons such as play, stop, volume, etc. were being used as image svg files in img tags, and this has the same problem of the paths, makes the component more dependent of external elements and also the component folder has more files, and a web component should depend as little as possible on files and need the minimum possible from outside itself.
So, given it was possible, now all those svgs images are integrated as code of svg tags with their respective paths inside(in this context paths are geometrical shapes described with a special code syntax), this is the comparison between how it was and how it is now:
- Before:
const playIcon = '../common/icons/play_arrow_24dp_E8EAED_FILL1_wght400_GRAD0_opsz24.svg';
- Now:
const playIcon = `<svg height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M320-273v-414q0-17 12-28.5t28-11.5q5 0 10.5 1.5T381-721l326 207q9 6 13.5 15t4.5 19q0 10-4.5 19T707-446L381-239q-5 3-10.5 4.5T360-233q-16 0-28-11.5T320-273Z"/></svg>`;
This is implemented with every svg needed for the component, these svgs are stored in constants for easy handling, and for reusability and atomicity principles, then they are placed in buttons directly by demand, being able to work without svg images and directly with their code instead, less dependent and more practical and suitable for a component.
This improves the way the component works, makes it better and not dependent of svg images, so given these were no longer needed anymore, they were removed, and the icons folder deleted.
Adequations were made to adapt elements, variables and constants to the new integrated svg icons, img tags that used these icons in the html template were removed, due to these are directly placed inside the buttons and all those elements that were pointing to the svg files now point to the integrated icon elements, behavior methods were also adapted to fit this way.
Fonts
Displaying text in a good way is something really important, so fonts are key for a good element, product or tool, the fonts were being imported using a styles css file, and the developer had to import them manually, adding an aditional step, but this had finally changed, at the end it was something easy to do, but at the beggining due to lack of this specific knowledge it was difficult to achieve, or rather, what was actually difficult was closing the circle and get to the right solution, so experience was gained in the process.
Now the fonts declaration is inyected from inside the component to the client DOM automatically when the component is imported and loaded without further intervention, so it is sufficient just to import the component.
Due to this change the styles css file that used to declare the fonts in the client DOM is no longer required and has been removed.
Attributes
The 'artist-album' attribute has been deprecated, the compound way it was, now it has been separated into 2 attributes: 'artist' and 'album'.
- Before:
mapComponentAttributes() {
// Setting Title, Artist and Album visually in the corresponding interface elements
songTitle.innerHTML = this.hasAttribute( 'song-name' ) ? this.getAttribute( 'song-name' ) : 'Sin Nombre';
songArtistAlbum.innerHTML = this.hasAttribute( 'artist-album' ) ? this.getAttribute( 'artist-album' ) : 'Sin Artista - Sin Álbum';
}
static get observedAttributes() {
return ['src', 'type', 'autoplay', 'loop', 'song-name', 'artist-album', 'cover-img'];
}
- Now:
mapComponentAttributes() {
// Setting Title, Artist and Album visually in the corresponding interface elements
songTitle.innerHTML = this.hasAttribute( 'song-name' ) ? this.getAttribute( 'song-name' ) : 'Desconocido';
songArtistAlbum.innerHTML = this.hasAttribute( 'artist' ) ? this.getAttribute( 'artist' ) : 'Artista Desconocido';
this.hasAttribute( 'album' ) && ( songArtistAlbum.innerHTML += ' - ' + this.getAttribute( 'album' ) );
}
static get observedAttributes() {
return ['src', 'type', 'autoplay', 'loop', 'song-name', 'artist', 'album', 'cover-img'];
}
Making it this way allow them to work independently but linked, this adds more flexibility and less responsibility to the developer of adding the ' - ' char, it does it internally, easier and more practical, so if the album is provided a ' - ' char is added with the album next to the artist.
If the album is not provided, then only the artist will be shown, even if the artist is not provided then a fallback text will be shown: 'Unknown artist', in the case or the artist either the provided artist or the fallback text will be shown, but in the case of the album if it is not provided then it will be completely ommited.
Minor aspects
Assets Folder
The 'common' folder where resides the resources such as fonts and images, has been renamed to 'assets', this is maybe a name more used in the industry, many frameworks use this name and is kind of common to have this name actually(ironically), it is true that at the end the name of folders and files are decided by the project owner or maintainer, and every owner can decide this aspect and use different names, but it is a good practice using conventions and standards, this way it is easier to identify and know what it is and what purpose that element or folder serves.
Custom element
In the previous version of the component, the html custom element was being defined in the page where the component would be used, this is an additional responsibility for the developer and it becomes more dependent to work, so now the declaration of the custom element happens inside the component javascript file, at the end of the class, after it, there is the customElements.define() method doing this task(if the developer would want to change the name of the custom element tag they would do it in this method, so it is something actually not hard to do and still pretty flexible), so the developer now only has to do an import and nothing else, one line of code inside a script tag and that allows them to use the component, again, easier and more practical.
- Before:
<script type="module">
import {ClarkCodesAudioPlayer} from '../common/components/ClarkCodesMusicPlayer/ClarkCodesAudioPlayer/ClarkCodesAudioPlayer.js';
window.customElements.define( 'clark-codes-audio-player', ClarkCodesAudioPlayer );
</script>
- Now:
<script type="module">
import '../common/components/ClarkCodesMusicPlayer/ClarkCodesAudioPlayer/ClarkCodesAudioPlayer.js';
</script>
Doing it this way is much better, it only requires now one line of code, one import inside a script tag to allow the use of its custom tag, very much less dependent and easier to implement.
Change of the custom tag name by default
The tag name of the custom element has been changed to 'cc-audio-player' by default, a shorter and more compact name, also, this is a self-closing tag, so it only needs an opening tag.
Now the custom element tag can be used this way by default, for example:
<body>
...
...
<section id="audioPlayerSectionId">
<cc-audio-player src="../assets/audios/Love Thing.mp3" type="audio/mpeg" autoplay="true" song-name="Love Thing" artist="Joe Satriani" album="Crystal Planet" cover-img="../assets/images/Satriani-BCN-2023-1.jpg" />
</section>
...
...
<script type="module">
import '../assets/components/ClarkCodesMusicPlayer/ClarkCodesAudioPlayer/ClarkCodesAudioPlayer.js';
</script>
</body>
A little better code readability
Some parts of the code were a bit difficult to read, usually a code block with declaration of retrieving elements need not have much separation between them, but by changing the way svg works in the component something became evident, it was a bit difficult to read this part of the code, so blank lines of separation were added between each element declaration for better readability, making the code more maintainable and now it takes less time to find the declaration of a certain element.
Final words
Hi, I'm Clark... having the project finally in a stable state is pretty good, but first of all, I must clearify just for the record that this project is part of my learning journey, there are many things I don't know, even if I started my coding journey when I was a teenager, I just learnt web development not long ago, this is a whole world in the universe of software development, there are many things to learn, and I still learning and practicing, even if I have a job and I work coding, always there is something to learn and that is something I like of this industry, a lot of thing to practice if one gets bored, so as part of my learning, this is my first web component I built by myself as a personal project, by make a lot of research, with every resource I could, all I have learned in University, making a responsible use of AI explanations about how some things work and learn also of this, always contrasting information with several sources, so as many things I have learnt I do it in a self-taugh way, of course every source of knowledge sums to it, so yeah, maybe this web component is not perfect, maybe it is not the best in the world, but it was my first web component ever, and doing it made me very happy, at the end, I started this little project because I was bored and it was an excuse to learn something new, now I know how to make an web component, that's cool for me, so I keep learning, now I am learning some frontend frameworks, after that, maybe some of backend, after that, maybe master mobile development, after that, maybe some machine learning and AI making, AI training and that stuff, well... there are many things to learn and I will learn all I can, I'm a very curious person, of course I could like to specialize at something specific, but I am too curious as not learn all I can, so future is unknown but I will still learn and practice all my life.
After saying that, in this version there were several things that needed being fixed, the previous version had to be a pre-release version, but well, I am happy that now this is a decent first functional version and it looks ok after testing it in different scenarios, although the component works ok now, I probably will add unit testing, integration testing and visual style testing in the near future, it would be good to learn that, of course I have done testing before but not with web components yet, so it would be fun, also I want to add more skins and different visual distributions for the component, like vertical distribution and variations like that, of course I want to add the Music Player web component, until now there is only the audio player, but in the future there will be also the music player, and different skins, modes and some other features that would be nice to add, so that is the idea.
Well, this is all by now for this version changes, thank you for reading this notes, I will be back in future releases and other projects, bye for now.
Huge hug for you, cheers!!... with love, enthusiasm and of course...
Happy Coding! ❤️
Clark.