Who am I and introducing piecesjs
quentinhocde
Hello 👋 I am Quentin Hocdé, a freelance creative and front-end developer with over 10 years of experience. I mainly create animated and interactive websites. I am also ex-lead front-end at Locomotive.
I have always shared a lot about my workflow, my way of building websites, and I am one of the creators of locomotive-scroll.
For years, my front-end stack has been based on the boilerplate we created at Locomotive, using modularJS for component-style management of JavaScript.
With the desire to have a real approach based on web components, with dynamic imports of JS and CSS to improve code optimization and reduce page loading times, I decided to embark on creating a small front-end JavaScript framework.
piecesjs is born, with the idea of keeping the same way of working, tools, utility functions but written in a more modern way and adapted to new needs.
This project will evolve according to the projects I develop.
piecesjs
[alpha] - [1.1kb] - Front-end js framework, using native web components.
Main features
- Dynamic JS & CSS import.
- Scoped event manager.
- Easy access to all elements inside a component with a
this.$(yourQuery)
. - Easy communication between active components.
- Common and global CSS import management.
- A PiecesManager to access to all active components.
Installation
npm i piecesjs --save
Create your first component
With dynamic attributes (reactive)
<c-add class="c-add" value="0"></c-add>
import { default as Piece } from "piecesjs";
export class Add extends Piece {
constructor() {
super("add", {
stylesheets: [() => import("/assets/css/components/add.css")],
});
}
mount() {
this.$button = this.$('button')[0];
this.addEvent("click", this.$button, this.click);
}
unmount() {
this.removeEvent("click", this.$button, this.click);
}
render() {
return `
<h2>${this.name} component</h2>
<p>Value: ${this.value}</p>
<button class="c-button">Increment</button>
`;
}
click() {
this.value = parseInt(this.value) + 1;
}
set value(value) {
return this.setAttribute("value", value);
}
get value() {
return this.getAttribute("value");
}
// Important to automatically call the update function if attribute is changing
static get observedAttributes() {
return ["value"];
}
}
// Register the custom element
customElements.define("c-add", Add);
With static content
<c-header class="c-header">
<h1>Hello world 🫶</h1>
</c-header>
import { default as Piece } from "piecesjs";
class Header extends Piece {
constructor() {
// Set the name of your component and stylesheets directly with the super();
super("Header", {
stylesheets: [() => import("/assets/css/components/header.css")],
});
}
}
// Register the custom element
customElements.define("c-header", Header);
Register and load dynamically your component
import { load } from "piecesjs";
load("c-button", () => import(`/assets/js/components/Button.js`));
Lifecycle
premount(){}
mount(){}
update(){} //Called if an attribute is changed : unmount(), premount(), mount()
unmount(){}
Query with this.$
Shortcut to query an element
// return an array of elements
this.$('button');
Events
Register an event
/*
You can add an event in the mount().
The called function is automatically binded to this
params: (eventName, HTMLElement or array of HTMLElement, func [, parameters])
*/
mount() {
this.addEvent('click', this.$button, this.click, {hello: 'world'});
}
Unregister the event
/*
You can remove the event listener in the unmount().
params: (eventName, HTMLElement or array of HTMLElement, func)
*/
unmount() {
this.removeEvent('click', this.$button, this.click);
}
Call a function of any components, from any components
/*
params: (functionName, args, pieceName [,pieceId])
*/
this.call("increment", {}, "Add", "myAddComponentId");
If no pieceId are specified, all occurrences of the component will be called.
A pieceId can be set directly with an attribute cid
<c-button cid="myButtonUId"></c-button>
PiecesManager
Used to manage all active components. To access to the current components active in the page:
import { piecesManager } from "piecesjs";
console.log(piecesManager.currentPieces);
// or in a Piece
console.log(this.piecesManager);
class Header extends Piece {
mount() {
console.log(this.piecesManager.currentPieces);
}
}
/*
{
Add: {
c0: {
name: 'Add',
id: 'c0',
piece: HTMLElement
},
myAddComponentId: {
name: 'Add',
id: 'myAddComponentId',
piece: HTMLElement
}
},
Button: {
c2: {
name: 'Button',
id: 'c2',
piece: HTMLElement
}
},
Header: {
c1: {
name: 'Header',
id: 'c1',
piece: HTMLElement
}
}
}
*/
Utils
Logs
You can log the lifecycle of your component with an attribute log
<c-header log>Hello</c-header>