JSPM

  • Created
  • Published
  • Downloads 1195
  • Score
    100M100P100Q100578F
  • License MIT

Package Exports

  • webjsx
  • webjsx/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (webjsx) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

webjsx

webjsx is a lightweight virtual DOM library for building web applications with JSX and Web Components. It offers a minimal approach to creating, diffing, and rendering virtual nodes for efficient DOM updates. webjsx is NOT a framework - it's a library.

Installation

Install webjsx via npm:

npm install webjsx

Getting Started

The easiest way to get started with webjsx is by setting up a project using your preferred build tools. Below is a basic example of how to create and render elements using webjsx with a focus on JSX and Web Components.

Creating Elements with JSX

webjsx fully supports JSX syntax, enabling you to write more readable and maintainable code. Use the createElement function to create virtual DOM elements and the applyDiff function to render them to the real DOM.

/** @jsx webjsx.createElement */
import * as webjsx from "webjsx";

// Define a simple virtual DOM element using JSX
const vdom = (
  <div id="container">
    <h1>Welcome to webjsx</h1>
    <p>This is a simple example.</p>
  </div>
);

// Select the container in the real DOM
const container = document.getElementById("app");

// Apply the virtual DOM diff to update the real DOM
applyDiff(container, vdom);

Defining and Using Web Components with JSX

webjsx excels at integrating JSX with Web Components, allowing you to define custom elements and render them using JSX syntax.

/** @jsx webjsx.createElement */
import * as webjsx from "webjsx";

// Define a custom Web Component
class MyElement extends HTMLElement {
  static get observedAttributes() {
    return ["title", "count"];
  }

  constructor() {
    super();
    this._count = 0;
  }

  connectedCallback() {
    this.render();
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === "title" || name === "count") {
      this.render();
    }
  }

  set count(val) {
    this._count = val;
    this.render();
  }

  get count() {
    return this._count;
  }

  render() {
    // Use webjsx's applyDiff to render JSX inside the Web Component
    const vdom = (
      <div>
        <h2>{this.getAttribute("title")}</h2>
        <p>Count: {this.count}</p>
      </div>
    );
    applyDiff(this, vdom);
  }
}

// Register the custom element
if (!customElements.get("my-element")) {
  customElements.define("my-element", MyElement);
}

// Create a virtual DOM with the custom Web Component
const vdom = <my-element title="Initial Title" count={10}></my-element>;

// Render the custom Web Component
const container = document.getElementById("app");
applyDiff(container, vdom);

Handling Events in JSX

Attach event listeners directly within your JSX using standard HTML event attributes.

/** @jsx webjsx.createElement */
import { createElement, applyDiff } from "webjsx";

// Define an event handler
const handleClick = () => {
  alert("Button clicked!");
};

// Create a button with an onclick event
const Button = () => {
  return <button onclick={handleClick}>Click Me</button>;
};

// Render the Button component
const container = document.getElementById("app");
applyDiff(container, <Button />);

Using Fragments

Group multiple elements without introducing additional nodes to the DOM using Fragment.

/** @jsx webjsx.createElement */
import * as webjsx from "webjsx";

const List = () => {
  return (
    <Fragment>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </Fragment>
  );
};

const container = document.getElementById("app");
applyDiff(
  container,
  <ul>
    <List />
  </ul>
);

API Reference

createElement

Creates a virtual DOM element.

Usage:

createElement(type, props, ...children);
  • type: string | typeof Fragment
    The type of the element, e.g., 'div', 'span', or Fragment for grouping.
  • props: object | null
    An object containing attributes and properties for the element.
  • children: VNode | VNode[]
    The child elements or text content.

Example:

createElement("div", { id: "main" }, "Hello, World!");

applyDiff

Applies the differences between the new virtual node(s) and the existing DOM.

Usage:

applyDiff(parent, newVirtualNode);
  • parent: Node
    The parent DOM node where the virtual nodes will be applied.
  • newVirtualNode: VNode | VNode[]
    A single virtual node or an array of virtual nodes.

Example:

const vdom = createElement("p", { class: "text" }, "Updated Text");
applyDiff(container, vdom);

Fragment

A special type used to group multiple elements without adding extra nodes to the DOM.

Usage:

<Fragment>
  <Element1 />
  <Element2 />
</Fragment>

Example:

<Fragment>
  <span>First</span>
  <span>Second</span>
</Fragment>

Creating Web Components with JSX

webjsx simplifies the creation and rendering of Web Components using JSX. By leveraging the power of JSX, you can define complex custom elements with ease.

Example: Creating a Counter Web Component

/** @jsx webjsx.createElement */
import { createElement, applyDiff } from "webjsx";

// Define the custom Web Component
class CounterElement extends HTMLElement {
  static get observedAttributes() {
    return ["title", "count"];
  }

  constructor() {
    super();
    this._count = 0;
  }

  connectedCallback() {
    this.render();
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === "title" || name === "count") {
      this.render();
    }
  }

  set count(val) {
    this._count = val;
    this.render();
  }

  get count() {
    return this._count;
  }

  render() {
    // Render JSX inside the Web Component
    const vdom = (
      <div>
        <h2>{this.getAttribute("title")}</h2>
        <p>Count: {this.count}</p>
        <button onclick={this.increment.bind(this)}>Increment</button>
      </div>
    );
    applyDiff(this, vdom);
  }

  increment() {
    this.count += 1;
  }
}

// Register the custom element
if (!customElements.get("counter-element")) {
  customElements.define("counter-element", CounterElement);
}

// Create and render the CounterElement
const vdom = <counter-element title="My Counter" count={0}></counter-element>;

const container = document.getElementById("app");
applyDiff(container, vdom);

Testing

webjsx comes with a comprehensive test suite to ensure reliability and correctness. The tests cover various aspects, including basic rendering, element management, event handling, fragments, keys handling, multiple updates, props handling, and integration with custom Web Components.

To run the tests:

npm test

Ensure that all tests pass before deploying your application.

Building

webjsx is written in TypeScript and can be built using standard TypeScript and bundling tools.

TypeScript Configuration

Ensure your tsconfig.json is set up to handle JSX and module resolution correctly.

{
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "webjsx.createElement",
    "jsxFragmentFactory": "webjsx.Fragment",
    "target": "es6",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true
  }
}

Running the Build

npm run build

Ensure that your build scripts are correctly defined in package.json.

Example Projects

Explore these example projects to see webjsx in action:

  • Basic Rendering: Demonstrates simple element creation and rendering.
  • Event Handling: Shows how to attach and manage event listeners.
  • Fragments and Keys: Illustrates grouping elements and optimizing list rendering.
  • Custom Web Components: Integrates custom elements with webjsx.
  • JSX Syntax with Web Components: Focuses on rendering Web Components using JSX.

Contributing

Contributions are welcome! Whether it's reporting bugs, suggesting features, or submitting pull requests, your help is appreciated.

  1. Fork the repository.
  2. Create a new branch: git checkout -b feature-name.
  3. Commit your changes: git commit -m 'Add new feature'.
  4. Push to the branch: git push origin feature-name.
  5. Open a pull request.

Please ensure that your contributions adhere to the project's coding standards and include appropriate tests.

License

webjsx is open-source software licensed as MIT.

Support

If you encounter any issues or have questions, feel free to open an issue on GitHub or reach out via Twitter @jeswin.