visionmedia / page.js

Micro client-side router inspired by the Express router
http://visionmedia.github.com/page.js
7.67k stars 687 forks source link

PageJS and WebComponents #569

Open aress31 opened 3 years ago

aress31 commented 3 years ago

Hi everyone,

I am considering moving from Vaadin Router to PagesJS since PagesJS is almost half the size. I am creating a project using web components - https://github.com/open-wc/open-wc - I need to have a centralized place where I configure the router (ideally using a JSON object of all my routes) and make it accessible application wide.

What would be the best way to proceed?

Thanks in advance, Alex

jorenbroekema commented 3 years ago

I use it in a web component based app so I'll just share a snippet.

class MyApp extends HTMLElement {
  constructor() {
    super();
    this.currentPage = 'home';
  }

  connectedCallback(c) {
    this.setupRouting();
  }

  setupRouting() {
    page('*', (ctx, next) => {
      // do stuff on each page request
      next();
    });

    page('/', () => {
      this.currentPage = 'home';
      this.pageTemplate = html`
        <jb-home></jb-home>
      `;
    });

    page('/work', () => {
      this.currentPage = 'work';
      this.pageTemplate = html`
        <jb-work></jb-work>
      `;
    });

    page();

    this.addEventListener('change-route', e => {
      page(`/${e.detail}`);
    });
  }

  render() {
    this.innerHTML = `
      <jb-nav></jb-nav>
      ${this.pageTemplate}
    `;
  }
}

This app shell is the top most component in my app, you just re-render whenever currentChange property changes. Simplest way is to create getter/setter for it, reflect to an attribute, and listen for attributeChangedCallback, and call the render method when the value of the attribute is different than current. That, or add a MutationObserver or something. Libraries like LitElement, stencil, Fast element, etc. etc. all provide you with easy helpers for changing props + re-rendering what has changed.

Some component deep deep down that has a click that changes the route

<jb-button
  @click=${() =>
    host.dispatchEvent(
      new CustomEvent('change-route', { bubbles: true, composed: true, detail: 'work' }),
    )}
  >EXPLORE WORK</jb-button
>

This event gets caught in the app shell on the event listener for change-route, if you set composed:true it also goes through shadow dom boundaries. The "normal" way would just be through anchors with href attributes though, usually.

klauss194 commented 3 months ago

Did anyone else try this with webcomponents ? ( Lit in particular )

jorenbroekema commented 3 months ago

Lit works with it as well, very similar to my snippet using HTMLElement, except you use LitElement