npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@dvo/fc

v0.0.8

Published

Helper function to create web components without using classes.

Downloads

3

Readme

fc

What

fc is a helper function for classless web components. It allows you to declare a web-component by calling fc(componentObject) instead of the class boilerplate, and allows you to do away with the this keyword.

Why

To make web-components more palatable to me, or hopefully to anyone else who prefers functional programming over class-based object orientation.

Javascript was designed with a beautiful object and prototypical inheritance system. It was subsequently, modified to support another complete different paradigm, based on classes and object orientation, in an attempt to make it more palatable to Java and C# ("real") programmers.

I find it tolerable that javascript is "frankensteined" to make it more accessible to all backgrounds. But I found it deeply regrettable that web-components were locked in the other side of the fence, that is to say, that it requires the use of classes. The effect of this, to me, is that web components became ugly and cumbersome in their vanilla version, compared to the cheap and elegant functional components of React, for example.

This tool is one of a set I've built in the hopes of making websites without frameworks. The other tools are:

  • @dvo/chips: allows for automatically lazy loading web components written as HTML files;
  • @dvo/stamp: allows dynamically populating containers with template components;
  • @dvo/raven: a lightweight state management tool.

How

fc is a function that receives a single object (we'll call it componentObject) defining the component's configurations, properties, and methods. Let's create a hello-world sample component:

<!-- index.html -->
<template id="tpl-hello-world">
  <p>hello-world</p>
  <style>
    p {
      color: purple;
      font-weight: bold;
    }
  </style>
</template>
// javascript
import fc from "/node_modules/@dvo/fc/src/index.js";
  fc({
    tag: "hello-world",
    props: {
      connectedCallback: (el) => () => console.log("connectedCallback", el),
      logMeFunction: (el) => (...args) => console.log(el),
    }
  });
</script>

Notice you must create the markup of your component in the HTML, wrapped in a <template> tag. fc will look for the template whose id matches tpl-<tag>.

Finally, notice that there is a few special keys in the componentObject:

  • tag refers to the custom element tag that will invoke the component. It is the only required property. fc will look in the HTML for a template with id equals to tpl-<tag> and use that to create the web-component.
  • observedAttributes expects a list of strings identifying attributes that, when changed, should trigger attributeChangedCallback.
  • shadowRoot determines if the component will make use of shadowRoot to encapsulate styling.
  • props expect and object, whose properties are going to be moved to the component (see writing properties, below). Any methods you wish to add to the component shoud be added here as a prop.
  • Inside props, there are five special keys mapping to the lifecycle of web components: constructor, connectedCallback, disconnectedCallback, adoptedCallback, and attributeChangedCallback. As all methods, they must be written as partial application, as described below.

Writing properties

fc tries to avoid using the this keyword. When adding a property to the component, your can just add it to the componentObject.props. If that property relies on knowing something about the element, you must add it as a function that receives the component instance as the argument. For example:

const hpPerLevel = 10;
fc({
  tag: "warrior",
  props: {
    // A static prop
    hpPerLevel,
    // A dynamic prop relying on dataset.level.
    // It will run when the component is instantiated, using the instance data-level.
    hp: (el) => el.dataset.level * hpPerLevel,
  },
});

To add a function as a property (aka. method), you must then use a partial application. That means, you must write a function that receives the component instanace (just like in the dynamic prop above), and that in turn returns the function you to be added to the component. Instead of relying on this keyword, it has access to the instance through the partial application.

const hpPerLevel = 10;
fc({
  tag: "warrior",
  props: {
    // A component method
    warCry: (el) => () =>
      console.log(`I'm a ${el.dataset.level} level warrior!`),
  },
});

A final note: this is an experimental script that doesn't aim to reproduce everything available in web-components, but only the basic behaviour needed by the vast majority of components. In particular, it is expected to make components "cheap" to produce, much the same way that they are in React.