AlexxNB / tinro

Highly declarative, tiny, dependency free router for Svelte's web applications.
MIT License
675 stars 30 forks source link

Support for guarded routes #9

Closed DairAidarkhanov closed 4 years ago

DairAidarkhanov commented 4 years ago

Hello, just saying this project is awesome!

However, I do have a question. Is there a best practice to guard routes, e.g. handling auth case? For example, it seems that React Router encourages imperative approach to guards leveraging a Switch component: (stackoverflow link).

At the moment, I see only one approach to implement guards in tinro:

{#if $isAuthenticated}
  <Route path="/enter">Authenticated!</Router>
{:else}
  <Route path="/noenter" redirect="/newurl"/>
{/if}

Also, I would like to help expanding the documentation with such a case, thanks!

AlexxNB commented 4 years ago

Thanks! Switch in React looks boilerplaty. Your if statement looks more declarative, and I like it.

Also it is simple to make the guard-component like I did here: https://svelte.dev/repl/5673ff403af14411b0cd1785be3d996f?version=3.21.0

Also, I would like to help expanding the documentation with such a case, thanks!

Be free to make PR. I think it is good case for Recipes section.

DairAidarkhanov commented 4 years ago

Cool idea! Let me see how the guard component works in order to write about it.

Also, I love the fact that on:click event and redirection with href are combined locally in one tag.

AlexxNB commented 4 years ago

I realy love just {#if} statement, my <Guard/> example is only to be like React =)

This looks more declarative, as I think.

{#if $user}
    <Route path="/login/*" redirect="/profile"/>
    <Route path="/profile"><h1>It is User's profile page</h1></Route>
{:else} 
    <Route path="/profile/*" redirect="/login"/>
    <Route path="/login">
        <h1>Please sign in</h1>
        <button on:click={()=>$user=true}>Sign In</button>
    </Route>
{/if}

The <Guard> or even <AuthGuard> component may be cool when the auth condition is checked inside this component.

AlexxNB commented 4 years ago

I rewrite my example to be with <Authguard> component

DairAidarkhanov commented 4 years ago

As I'm working on the routing in my project, I have noticed an issue, when empty div[slot="not_authed"] container constantly appears on every page.

As <svelte:fragment /> is being worked on, one solution is using svelte-fragment package with this fix.

So, with svelte-fragment, one can write:

<AuthGuard>
  <Route path="/login" redirect="/" />

  <template use:fragment slot="not_authed">
    <Route path="/login">
      <Lazy component={signInPage} />
    </Route>
    <Route path="/register">
      <Lazy component={signUpPage} />
    </Route>
  </template>
</AuthGuard>
// fragment.js

// Credits to @Swizz and @qutran
export default function fragment(node) {
  // We need to keep the reference of the parent because of the adoption
  const parent = node.parentElement;

  // As appening a fragment as node child remove its content, we need to save the
  // children references
  const children = Array.prototype.slice.call(
    (node.content || node).childNodes,
  );

  // As the given node could not be a template tag we need to create a fragment
  // for non template node
  if (!node.content || node.content.nodeType !== 11) {
    node.content = document.createDocumentFragment();

    for (let i in children) {
      node.content.appendChild(children[i]);
    }
  }

  // By appending a fragment, its content will be spread inside the parrent
  parent.appendChild(node.content);

  // Svelte except an used node to have parent, so a fragment should adopt the node
  document.createDocumentFragment().appendChild(document.adoptNode(node));

  return {
    destroy() {
      // Node content fragment doesnt longer have the references to the children
      // so its content need to be removed reference by reference
      requestAnimationFrame(function() {
        for (let i in children) {
          if (parent && parent.contains(children[i])) {
            parent.removeChild(children[i]);
          }
        }
      });
    },
  };
}
AlexxNB commented 4 years ago

As I'm working on the routing in my project, I have noticed an issue, when empty div[slot="not_authed"] container constantly appears on every page.

Can you reproduce this in REPL?

DairAidarkhanov commented 4 years ago

Sorry, had to delete the example using actions. Fragment action does not work as general-purpose solution, because it eagerly runs outside the constraints.

At the moment, div[slot="not_authed"] works well.

AlexxNB commented 4 years ago

Added info in readme myself =)