Git Product home page Git Product logo

yrv's Introduction

yrv

Build status NPM version Known Vulnerabilities donate

The v is for Svelte

Built on top of abstract-nested-router, so you can use nested routers, also:

  • Advanced parameters can be used, e.g. /:id<\d+> β€” see docs
  • ARIA-compliant, sets [aria-current="page"] on active links
  • Seamless <base href="..." /> integration
  • Conditionals and redirection through props
  • Fallback <Route /> handlers
  • Hash and URI-based routes
  • Support for query-string
  • REPL ready!

yrv will use any base-href found on the current page to rewrite links and routes.

Usage

Install yrv through NPM or Yarn:

<script>
  import { Router, Route, Link } from 'yrv';
</script>

<Link href="/">Home</Link>
| <Link href="/World">Hello</Link>
| <Link href="/not/found">NotFound</Link>

<p>
  <Router>
    <Route exact>Hello World</Route>
    <Route fallback>Not found</Route>
    <Route exact path="/:name" let:router>Hey {router.params.name}!</Route>
  </Router>
</p>

Notice fallback routes can’t be placed at the beginning, otherwise further routes will not be mounted. πŸ’£

Components

You MUST declare at least, one top-level Router to setup the bindings.

<Router {path} {pending} {disabled} {condition} {nofallback} />

This component will hold any given routes as children, path is always derived from parent routes.

Available props:

  • {path} β€” Any segment to derive a fullpath from, defaults to /
  • {pending} β€” Svelte-component or String; top-level pending support
  • {disabled} β€” Boolean; Similar to condition, but for bound props
  • {condition} β€” Function; if given, render only if evaluates to true
  • {nofallback} β€” If set, non-matched routes will never raise a failure

Nested routers does not need the same path to be declared inside, e.g. if the router for /top has a /sub router inside, inner router will use the route /top/sub, (the same as declaring /top/sub route outside the parent router).

<Route {key} {path} {exact} {pending} {fallback} {component} {disabled} {condition} {redirect} let:router />

Main container for routing, they can hold any component or children.

Available props:

  • {key} β€” The route identity, not its path; defaults to random pseudo-hash
  • {path} β€” Any segment to derive a fullpath from, default to /
  • {exact} β€” If set, the route will render only if the route exactly matches
  • {pending} β€” Svelte-component or String; rendered during the loading of dynamic components
  • {fallback} β€” If set, the route will render only if no more routes were matched
  • {component} β€” Accepts either a valid svelte-component, a promise, or a dynamic import function
  • {disabled} β€” Boolean; Similar to condition, but for bound props
  • {condition} β€” Function; if given, the route will render only if evaluates to true
  • {redirect} β€” Alternate redirection location, only if the previous condition was true
  • let:router β€” Injects the router context, it also provides failure in case of errors

If you omit exact, then /x would match both / and /x routes β€” see docs

When yrv adds a new route, it'll use any given key from its props β€” once routes are detached they're also removed from the router registry, due to that, the next time the same route is mounted a new key is generated (if isn't present already).

<script>
  import SvelteComponent from 'path/to/svelte-component.svelte';
</script>

<Link href="/">Home</Link>
| <Link href="/svelte-component">Svelte component</Link>
| <Link href="/promise">Promised component</Link>
| <Link href="/lazy">Lazy component</Link>

<p>
  <Router>
    <Route exact>Hello World</Route>
    <Route exact path="/svelte-component" component={SvelteComponent}/>
    <Route exact path="/promise" component="{import('path/to/other-component.svelte')}"/>
    <Route exact path="/lazy" component="{() => import('path/to/another-component.svelte')}"/>
  </Router>
</p>

Behind the scenes, for making dynamic-imports work, the bundler should inline them or just write-out the required chunks to make it work natively (<script type="module" />) or through shimport, etc.

<Link {go} {href} {open} {title} {exact} {reload} {replace} {class} />

In order to navigate, you can use Link components, or regular links, etc.

All href values MUST be absolute, only links starting with / or # are allowed.

Available props:

  • {go} β€” History shortcut (see below)
  • {href} β€” New location, default to /
  • {open} β€” Same behavior as <a target="_blank">
  • {title} β€” HTML title-attribute value
  • {button} β€” If set, will use button-tag instead
  • {exact} β€” Determine if link should match exactly to be set as active
  • {reload} β€” Use location.href instead
  • {replace} β€” Use history.replaceState() instead
  • {class} β€” Custom class-name for the mounted anchor

The value for open can be a string including the window specs, e.g. width=400,height=200 β€” a on:close event will be fired once the opened window is closed.

Normal on:click events are still allowed, so you can use:

<Link on:click={() => location.reload()}>Reload</Link>

Active links will gain the [aria-current] attribute, and [disabled] if they're buttons.

Aditionally, you can setup go to move around:

  • "back" β€” String; if given, will invoke history.back()
  • "fwd" β€” String; if given, will invoke history.fwd()
  • n β€” Number; if given, it'll be used to invoke history.go(n)

If navigating through history is not possible a normal redirection will run. βš“

Public API

  • navigateTo(path[, options]) β€” Change the location, supported options are:
    • reload β€” If true, it will use document.location.href instead
    • replace β€” If true, it will use history.replaceState() instead
    • params β€” Used to replace :placeholders from given path
    • queryParams β€” Additional search-params for the new location
  • $router β€” Store with shared routeInfo details, similar to let:router

yrv gracefully degrades to location.hash on environments where history is not suitable, also it can be forced through router.hashchange = true.

Route Info

Route changes are propagated through stores, if you want to listen too just subscribe, e.g.

import { router } from 'yrv';

router.subscribe(e => {
  if (!e.initial) console.log(e);
});

Using this technique you gain access to the same detail object as let:router does.

Notice the initial property is present as soon the store is initialized, consecutive changes will not have it anymore.

IE11 support

Support for IE11 is granted if you include, at least, the following polyfills before your application:

<script>if (!!window.MSInputMethodContext && !!document.documentMode)
  document.write('<script src="https://polyfill.io/v3/polyfill.min.js?features=default,Promise,Object.getOwnPropertyDescriptors"><\/script>');</script>
<script src="your-app.js"></script>

document.write() is used because conditional comments were dropped in IE10, so this way you can conditionally load polyfills anyway.

Also, you MUST enable either buble or babel within your build pipeline to transpile down to ES5.

Frequently Asked Questions

How to conditionally render a <Router /> component?

Both Route/Router components support the disabled and condition props, but:

  • Use condition to allow/disallow route-dispatching dynamically
  • Use disabled to skip from rendering, it will add/remove the route

This new disabled prop would work as you're expecting:

<Router disabled={!showNavBar}>
  ...
</Router>

What means the exact property and how it works?

Say you have three routes:

  • /a (exact)
  • /a/b (non-exact)
  • /a/b/c (exact)

Now, you navigate from /a to /a/b/c:

  • Since /a was active, and it was exact, yrv clears out the routeInfo for that route.
  • Since /a/b is not exact, yrv activate this route because is half-way to the final route.

If you plan to have more routes nested, then the route will never be exact (at least at top-levels).

This is also true for <Link /> components β€” as soon as they match the [aria-current] attribute will be added on them to denote active links.

If the link for /a were also exact, then it'll be active if the matching route is /a only.

Why path can't be an empty string like other routers does?

Even if browsers treat http://localhost:8080 and http://localhost:8080/ as the same thing I wanted to keep paths clear as possible.

Internally yrv normalizes any given URI to keep a trailing slash, so /foo is /foo/ for matching purposes.

Also, the default path is usually / so there's no point on having to declare anything else:

<Route>OK</Route>
<Route path="/">OK</Route>

What is routeInfo and how can I access it outside routes?

This object is very similar to what you get with let:router inside components.

Use the $router store to access it, e.g.

<script>
  import { router } from 'yrv';
</script>
<pre>{JSON.stringify($router, null, 2)}</pre>

Why does Yrv not work with Parcel or webpack/snowpack?

If you're getting any of the errors below:

  • store.subscribe is not a function
  • Class constructor SvelteComponent cannot be invoked without 'new'
  • 'on_outro' is not exported by [...]
  • 'target' is a required option

Make sure you're using the right settings:

  1. Add mainFields into resolve config, e.g. mainFields: ['svelte', 'browser', 'module', 'main']
  2. Remove exclude: /node_modules/ from svelte-loader config

If you're using an online tool that is not the official Svelte REPL the behavior is unexpected and no further support will be granted.

Can I use hash-based routes Γ  la Gmail? e.g. index.html#/profile, index.html#/book/42?

Yes, URIs like that are suitable for embedded apps like Electron, where normal URLs would fail.

Also this mode is the default used on the Svelte REPL, because is not an iframe, nor a regular webpage... it's a weird thing!

If you enable router.hashchange = true all your regular links will be automatically rewritten to hash-based URIs instead, see how it works in our test suite.

Why I'm getting <Component> was created with unknown prop 'router' in the browser's console?

If you're not using the router prop inside your route-components then just add:

<script>
  export const router = null;
</script>

That will remove the warning and also will make eslint-plugin-svelte3 in your workflow happy.

Why router.subscribe is called two times when I first open the page?

Any subscription to stores will fire twice as they have an initial value, once the router resolves (e.g. the initial route) then a second event is fired.

In this case, and additional property initial is added to identify such event.

Is there any method that allows me to detect route change?

Yes, you can subscribe to the router store, e.g. router.subscribe(...) β€” see above.

Is there a way to reduce the bundle size of yrv?

Since v0.0.46 you'll be getting the most reduced version we can ship, however it comes without development warnings.

Consume it as import { ... } from 'yrv/debug' right away and you'll get a more complete version with included DEBUG information.

yrv's People

Contributors

cliqqz avatar dependabot[bot] avatar frederikhors avatar github-actions[bot] avatar ilyavf avatar jhechtf avatar mikemaccana avatar pateketrueke avatar theclarksell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

yrv's Issues

Optional params

"abstract-nested-router" docs say (of params):
"By default all segments are optional, e.g. /a/:b/:c matches with /a, /a/x and /a/x/y so you can say :b and :c are optional parameters."

For "yrv" it is not so. If i need a page with optional params, i have to declare three routes, one for each case:

<Route path="/page/:x/:y">Page</Route>
<Route path="/page/:x">Page</Route>
<Route path="/page">Page</Route>

I need the same component with params based on current path.

Could it be made as in "abstract-nested-router"?

Route with id param messes up stylesheet.

Hi i've been using this router to get to know Svelte, and so far all good.

But when i got to creating a route with an id parameter, refreshing the page on that route causes the app to look for the stylesheet in the wrong place.

Screenshot 2020-09-08 at 15 54 58

Screenshot 2020-09-08 at 15 55 19

instead of looking for index.css in localhost:4200/index.css like all other routes, this one for some reason attempt to look in a nested folder.

Thus if i navigate around, starting somewhere else, no problem. But if i refresh the page on http:localhost:4200/report/1234 it won't find the stylesheet.

Any ideas?

Index.html for reference

Screenshot 2020-09-08 at 16 00 58

Proposal, redirect on Router too

Thanks for your work, yrv is amazing.

Taking your example:

<Router path="/auth">
  {#if !loggedIn}
    <Route exact redirect="/auth/login" />
  {:else}
    <Route exact>Welcome back.</Route>
  {/if}

  <Route path="/protected" condition={() => loggedIn} redirect="/auth/login">O.K.</Route>
  <Route path="/login">Log-in</Route>
</Router>

Why can't we rewrite it like this instead?

<Router path="/auth" condition={() => loggedIn} redirect="/auth/login">
  <Route exact>Welcome back.</Route>
  <Route path="/protected">O.K.</Route>
</Router>
<Router path="/auth" condition={() => !loggedIn} redirect="/auth">
  <Route exact path="/login">Log-in</Route>
</Router>

What do you think about this?

I think we need redirect on Router because I can have many routes like this:

<Router path="/auth" condition={() => loggedIn} redirect="/auth/login">
  <Route exact>Welcome back.</Route>
  <Route path="/protected">O.K.</Route>
  <Route path="/protected/something">O.K.</Route>
  <Route path="/protected/players">O.K.</Route>
  <Route path="/protected/another">O.K.</Route>
</Router>
<Router path="/auth" condition={() => !loggedIn} redirect="/auth">
  <Route exact path="/login">Log-in</Route>
</Router>

Am I wrong?

UPDATE:

I can also use it like this:

<Router condition={() => loggedIn}>
  <Route exact>Welcome back.</Route>
  <Route path="/protected">O.K.</Route>
  <Route path="/protected/something">O.K.</Route>
  <Route path="/protected/players">O.K.</Route>
  <Route path="/protected/another">O.K.</Route>
</Router>
<Router condition={() => !loggedIn}>
  <Route exact redirect="/login" />
  <Route exact path="/login">Login</Route>
</Router>

Problem when use nested router with route path `/`

Seem we can't use nested route with default '/' path, do we have any plan or work around for this case?

Example: main router

<Router>
  <Route path="/" component="{Home}" />
  <Route path="/login" exact component="{Login}" />
</Router>

Then in Home component we also have a router

<Router>
  <Route exact component="{Dashboard}" />
  <Route path="/:id" exact component="{DetailItem}" />
</Router>

I tried many combination, including add/remove exact prop, but seem the router render is not working as I want, when use exact in path "/", the child router not rendering at all.
When clear exact, the /login will also render the Home component.

For now, I have to use /main or /home for the Home component instead of / that I actually need :(

<Link> used inside route component causes error

When I use Link inside component that is loaded into Route, clicking on the link causes error:

image

When Link is used outside the Router it works correctly

<Link>link</Link>

<Router>
  <Route>
</Router>
// Also using inside component loaded to Route does not work.
navigateTo(path)

Hope I explained well the issue.

Any help is appreciated.

Uncaught Error

YRV Version: 0.0.30

Going to a project i haven't touched in awhile, starting the dev server up I now get this error.

Uncaught TypeError: Object(...) is not a function
    at eval (Router.svelte:280)
    at run (index.mjs:167)
    at Array.map (<anonymous>)
    at eval (index.mjs:1525)
    at flush (index.mjs:861)
    at init (index.mjs:1611)
    at new Main (main.svelte:133)
    at eval (main.js:8)
    at Module../src/main.js (dashboard.9635fb5645339333ce10.js:823)
    at __webpack_require__ (dashboard.9635fb5645339333ce10.js:64)

Which is caused by the following code

<script>
import {Router, Route} from "yrv";
</script>
<Router>
  <Route exact path="/" component={() => import('./routes/main.svelte')} />
</Router>

If I remove the Route component the error goes away, but obviously this is not optimal.

`condition` doesn't seem to work

I have a Route with a condition, showNavBar, which shows a Nav component.

<Route condition={ showNavBar } component={Nav} />

showNavBar is set to false (shown from console.log()) but the Nav still launches!

Thanks for making yrv!

<script>

  import { Router, Route } from 'yrv';

  import Nav from './nav.svelte'
  import RecordEvents from './record-events.svelte'
  import ChatWidget from './chat-widget.svelte'
  import FrontPage from './front-page.svelte'
  import LoginPage from './login-page.svelte'
  import LaunchPage from './launch-page.svelte'
  import About from './about.svelte'
  import Pricing from './pricing.svelte'
  import Forgot from './forgot.svelte'
  import ForgotSent from './forgot-sent.svelte'
  import PrivacyPolicy from './privacy-policy.svelte'
  import Blog from './blog.svelte'
  import SignupPage from './signup-page.svelte'
  import ResetPasswordPage from './reset-password.svelte'
  import ErrorPage from './error-page.svelte'
  import Footer from './footer.svelte'

  let title = window.serverVars.title
  document.title = title

  var showNavBar = (! ['/login', 'signup'].includes(window.location.pathname))

  log({showNavBar})
</script>

<Router>  
  <Route condition={ showNavBar } component={Nav} />

  <Route exact path="" component={FrontPage} />
  <Route path="/about" component={About} />
  <Route path="/pricing" component={Pricing} />
  <Route path="/login" component={LoginPage} />
  <Route path="/launch" component={LaunchPage} />
  <Route path="/signup" component={SignupPage} />
  <Route path="/blog" component={Blog} />
  <Route path="/forgot" component={Forgot} />
  <Route path="/privacyPolicy" component={PrivacyPolicy} />
  <Route path="/forgotSent" component={ForgotSent} />
  <Route path="/resetPassword" component={ResetPasswordPage} />
  <Route fallback component={ErrorPage} error={window.serverVars.error}/>
</Router>

(More things here, cut for brevity)

Better clarify differences between promise and async import

Can we better clarify the difference between these two import modes?

<Route exact path="/promise" component={import('path/to/other-component.svelte')}/>
<Route exact path="/async" component={() => import('path/to/another-component.svelte')}/>

Dynamic component not functioning

YRV Version: 0.0.27
Svelte: 3.20.1

Okay, so let's get ready for a fairly long ticket -- trying to be as thorough as possible to make sure I'm documenting what I am seeing.

Description

According to the readme, the following should work by dynamically importing the '404.svelte' file:

<script>
import {Router, Route} from 'yrv';
import Dashboard from './dashboard.svelte';
</script>
<Router>
  <Route component={Dashboard} path="/" exact />
  <Route component={() => import('./_404.svelte')} fallback pending="Loading..." />
</Router>

However, all I am seeing on the page is 'Loading...'

Switching this to something a little bit more wordy, such as

<script>
// same stuff
</script>

<Router>
  <Route component={Dashboard} path="/" exact/>
  <Route component={() => {
    console.log('Testing');
    return import('./_404.svelte');
  }} fallback pending="Whoops"/>
</Router>

never shows 'Testing' in the console -- this function is never called. BUT if we re-arrange that to

<script>
// same imports
  function loadMe(){
    console.log('Load Me!')
    return import('./_404.svelte').then(res=>{
      console.log(res);
      return res;
    });
  }
</script>

<!-- Creates an index route with an errorpage fallback -->
<Router>
  <Route component={Dashboard} path="/" exact/>
  <Route component={loadMe} fallback pending="Whoops"/>
</Router>

I now see "Load Me!" in the console, but I receive this error:

Route.svelte:224 Uncaught (in promise) TypeError: Cannot read property 'fragment' of undefined
    at Object.create [as c] (Route.svelte:224)
    at Object.create [as c] (Route.svelte:90)
    at Object.update [as p] (Route.svelte:607)
    at update (index.mjs:834)
    at flush (index.mjs:803)

In fiddling around I thought maybe the arrow function binding messed something up and the end function needed to be bound differently, so I changed the given <Route> to read:

<Route component={loadMe.bind(this)} fallback pending="Whoops" />

Which removes the error, but no longer shows 'Load me!' to indicate the function has been invoked.

Out of sheer morbid curiosity I decided to change the function declaration for loadMe to the following:

<script>
// same includes
const loadMe = () => {
  console.log('Load Me!');
  return import('./_404.svelte');
}
</script>
<Route component={loadMe} fallback pending="Whoops" />

Which likewise no longer shows 'load me!'

Other Information

Does import('./_404.svelte') work?
Yes -- if I add a .then(res => { console.log(res); return res; }) to it and just have it load passively in the component it works just fine.

`'target' is a required option` Error

I'm relatively new to Svelte v3 (though I've used v2 some time ago) and I'm currently porting an educational app for my students from React to Svelte.

With all the routers I've tried (yours is the 3rd) I've had different issues :)

Not sure if the problem is specifically with the router or Svelte in general, but currently I'm getting 'target' is a required option
The simplistic repro app: https://codesandbox.io/s/svelte-yrv-issue-zvelg
I've created it by cleaning up my real app so it is possible I've overlooked something but it's so small I think it's actually OK.

Bundle size

I have tried to analyze the final weight impact in my application.

image

Compared to svelte-spa-router:

image

https://bundlephobia.com/[email protected]

Not just 10 KB.

Final bundle's size is different:

image

With svelte-spa-router:

image

Many src/*.svelte have a lot of stuff more with yrv.

And finally query-string about 3 KB.

25 KB more is huge!

Can I ask you why and if there is a way to "fix"?

How do we style Links (or the 'a' elements generated from them)?

Heya!

yrv works great, thank you! One quick question - how do I style a link? For example, I have:

<Link href="/{work.slug}" class="link">

which becomes:

<a href="/boomsaas" class="link" title="">

But if I try and style using a class "link" svelte complains the selector is unused:

Error: css-unused-selector

.link {
    width: 100%;
  }

How can I style a Link/a element?

Thanks! πŸ˜ƒ

Typescript support and warnings on build

Hey! Thanks for the package, it was a delight to use it due to it's simplicity.

However, I've run into a few problems here, it's not exactly show-stopping, but maybe it's something that may require some attention from you.

First thing is typescript support, I wonder if there is typescript support for yrv? Running yarn validate will give hints/errors that there are no type definitions for yrv, and I tried doing yarn add --dev @types/yrv too, but it seems that it does not exists.
image

Another thing are warnings on build, it seems like after a recent update, yrv is doing something that may have unintended consequences, I wonder if this is also something that may need your attention? This can be triggered with yarn build or yarn dev.
image

Please do let me know if there is anything else you need from me, thanks!

Open in New Tab only works with Anchor Elements.

@pateketrueke I know we just added #58 but we introduced a new issue that I'd be happy to fix.

Because we added the check for e.target.tagName === 'A' we limited ourselves to "only" handling the click on an anchor tag. But in cases like mine very often we're wrapping something in the anchor like so:

     <Link
        href="{l.href}"
      >
        <div class="flex items-center">
          <svg class="h-5" fill="currentColor" viewBox="0 0 20 20">
            <path d="M11 0h3L9 20H6l5-20z"></path>
          </svg>
          <span>{l.text}</span>
        </div>
      </Link>

ref: https://github.com/ThatConference/that.us/blob/master/src/components/nav/mainNav/Desktop.svelte#L11-L25

I think we should remove the check for A all together. The right thing should occur and bubble our since we're already taking our and binding our own onClick fuunciton.

Thoughts?

Turning on Svelte's dev causes "Uncaught (in promise) Error: 'target' is a required option"

The full text of the issue is

index.mjs?017d:1558 Uncaught (in promise) Error: 'target' is a required option
    at new SvelteComponentDev (index.mjs?017d:1558)
    at new Dashboard (dashboard.svelte?6e88:435)
    at Array.ut (yrv.es.js?4cd2:1)
    at it (yrv.es.js?4cd2:1)
    at Object.p (yrv.es.js?4cd2:1)
    at q (yrv.es.js?4cd2:1)
    at B (yrv.es.js?4cd2:1)

I initially thought this was due to the fact that I had created a wrapper component for the index / routes setup, so I instead moved the page in question to simply use the router / route elements directly with the same results.

My webpack config is

const { resolve } = require('path');
const { ProvidePlugin } = require('webpack');
const CssPlugin = require('mini-css-extract-plugin');
const HtmlPlugin = require('html-webpack-plugin');

const fromRoot = (...args) => resolve(process.cwd(), ...args);
const fromSrc = (...args) => fromRoot('src', ...args);

const { NODE_ENV = 'development' } = process.env;

module.exports = {
  target: 'web',
  mode: NODE_ENV,
  resolve: {
    extensions: ['.svelte', '.mjs', '.js', '.json'],
    alias: {
      '@': fromSrc('.'),
      'svelte': fromRoot('node_modules', 'svelte'),
      'config': fromRoot('configs/browser_config.json')
    }
  },
  entry: {
    dashboard: fromSrc('dashboard.js')
  },
  output: {
    path: fromRoot('dist'),
    filename: '[name].[hash].js',
    chunkFilename: '[id].js'
  },
  devServer: {
    host: '0.0.0.0',
    historyApiFallback: true
  },
  module: {
    rules: [
      {
        test: /\.svelte$/,
        exclude: /node_modules/,
        use: {
          loader: 'svelte-loader',
          options: {
            dev: true, // setting to false or removing this line removes the error.
          }
        }
      },
      {
        test: /\.css$/,
        use: [{
          loader: CssPlugin.loader,
          options: {
            hot: NODE_ENV === 'development'
          }
        }, 'css-loader', 'postcss-loader']
      }
    ]
  },
  plugins: [
    new CssPlugin(),
    new HtmlPlugin({
      template: fromSrc('index.html')
    })
  ]
};

The place where the router is used looks like this

<script>
  import {Router, Route} from 'yrv';
  import ErrorPage from './_404.svelte';
  import Dashboard from '../components/dashboard.svelte';
  
  const routes = [
    {
      component: Dashboard,
      exact: true,
      path: '/'
    },
    {
      component: ErrorPage,
      fallback: true
    }
  ];
</script>

<!-- Creates an index route with an errorpage fallback -->
<Router>
  <Route
    component={Dashboard}
    exact={true},
    path="/"
  />
  <Route
    component={ErrorPage}
    fallback={true}
  />
</Router>

exact as default

Maybe a breaking change but I think we need this.

From Readme:

<Router>
  <Route exact>Hello World</Route>
  <Route exact path="/svelte-component" component={SvelteComponent}/>
  <Route exact path="/promise" component={import('path/to/other-component.svelte')}/>
  <Route exact path="/async" component={() => import('path/to/another-component.svelte')}/>
</Router>

Can we omit exact? Can we use it as default?

All my routes are exact.

Can we use not-exact or similar for when not exact?

Link: Scroll to top option?

Hi,
thank you for fixed the latest issues relating to babel and IE11 !!!
I have only an issue, using your library.
I'm using directly the Linkcomponent with only a href parameter. If I have a link at the bottom of a page/component, when I load the new route the scrollbar remains on bottom instead of positioning on top.
Probably I'm missing something but there is a possibility to scroll on top after a route update, without reloading a page completely?

Thanks in advance !

OnChange Event

Is there any method that allows me to detect route change?
Or im doing things wrong? Im trying to make a fetch when my route changes.

Change the tagline to something more inclusive

I'm writing a book about development with Svelte. I like the work you've done, so I'd like to recommend yrv as the router for people who want to use one based on the HTML5 history API.

However, the tagline for the project ("Your routing bro!") makes me feel uncomfortable and stops me short of doing that. This is present on GitHub at the top of the page, as well as in multiple parts in the code: https://github.com/pateketrueke/yrv/search?q=bro&unscoped_q=bro

Would you please consider changing the tagline to something more inclusive? The "bro" term is connected to a toxic culture in tech (you might have heard the term "brogrammers") that is hurting women and non-binary individuals.

Your code is really good, there's no reason why "non-bros" can't use it πŸ˜‰

Inconsistency with path="" vs path="/"

Heya. Here's a subtle issue with the route for /, the top level of my site:

Using yrv 0.0.12, the following will break

<Router>
  <Route exact path="" component={FrontPage} />
  <Route path="/about" component={About} />
  <Route path="/pricing" component={Pricing} />
  <Route path="/login" component={LoginPage} />
  ...

I can fix it with (note the path on the first line):

<Router>
  <Route exact path="/" component={FrontPage} />
  <Route path="/about" component={About} />
  <Route path="/pricing" component={Pricing} />
  <Route path="/login" component={LoginPage} />
  ...

Note while this works, it's a bit inconsistent - /about has no trailing slash.,/pricing has no trailing slash, why does `` need a trailing slash?

Ideally / should be normalised and the trailing / not needed.

Works very well than any other router i found for svelte

Hi,

First of all let me thank you for creating this wonderful router. I was able to make it work for me from the example without any extra effort.

But i found it really hard to find a proper router for svelte. It would be great if we can change the name of the router to something very easy to find.

Just a proposal, svelte-router-dom or anything than makes this library easy found in npm search!.

Issue with Parcel bundler

Hi!

I am trying to use this with Parcel. However, when starting a dev server Parcel grabs a minified version of the plugin as defined in pkg.browser. For some reason things break in the browser.

Uncaught TypeError: store.subscribe is not a function

When changing the pkg.browser entry to src/index.js everything works as expected. The pkg.svelte already points to it, but this is a reserved property for the svelte compiler options and should not be used as an entry point, right?

I am a little unsure on how to proceed here. On what side the error is. Isn't it a bundler's job to minify the assets? What's your opinion?

Trailing slash handling

For example we have route like:

<Route exact path="/auth" component={Auth}/>

Using SPA navigation without any troubles. But when run app on production, some servers may redirect URL like http://mydomain/auth to http://mydomain/auth/ - with trailing slash. In this case router won't show the needed page. Usually, it is configurable on the server side - but maybe it is better to add support for both URL in the router?

Dynamic Imported Components

Great library, glad to have it!

Quick question though -- I come from a largely Vue background and I was wondering if there was any way implement Vue's dynamic import? e.g.

<script>
import {Router, Route} from 'yrv';
</script>

<Router>
  <Route component={() => import('./pages/SomePage.svelte')} path="/some-page" />
  <Route fallback>
    Whoops!
  </Route>
</Router>

I figured I'd ask here and see if it is a feature you can implement yourself (I've not looked at the source) or if it should be asked further up the pipeline.

Thanks!

Example of <Routers> spread across components?

I have this setup:

App.svelte:

<main>
    <Navbar />
    <div class="master-container {extraClassesString}">
        <Router>
            <Route exact path="/" component={IndexPage} />
            <Route path="/blog" component={BlogListPage} />
            <Route fallback component={NotFoundPage} />
        </Router>
    </div>
</main>

BlogListPage.svelte

    ... some common header stuff
    <Router path="/blog">
        <Route exact path="/:year/:id" let:router>{router.params.year} {router.params.id}</Route>
    </Router>

Can you provide an example of how to make this routing configuration work?

Component props

Hi,

Thanks for an excellent svelte router.

How would one pass props to routed components?

E.g.:
<Route exact path="/#faq" component={<FAQ prop1=true/>} /> ? (this doesn't work)

Link component href not updating when bound

<script>
export let path = '/'
</script>

<Link href={path}><fancy stuff /></Link>

When I try to create a dynamic link like this, the corresponding <a> tags href attribute does not reflect the change of the path variable. It does, however, lead to wherever path points to when clicked.

So when I change the path from / to /about, the href is still /, but when I click on the link, it leads me to /about.

How to use hash based routes

I have a simple route setup, that i can't get to work.

/foos
/foo/:id

<Route exact path="/foos" component={foosComponent} /> <Route exact path="/foo/:id" component={fooComponent} /> <Route fallback>404 Not found</Route>

Foos is a list
Foo refers to a specific item.

When i'm on a specific item i would like to use fragment based routing to allow the user to scroll to certain items on the page, however the router thinks it's a route attempt and redirects to the fallback.

so /foo/123#someItem takes me to the fallback route

how do i define the route for foo so that it optionally can have a fragment parameter? and stays on the same component?

Support for cmd+click open in new window

@pateketrueke thank you for the great work on YRV. We've heavily used it with that.us (github.com/thatconference/that.us).

I don't know if I am doing something wrong, or if it's just not supported but is there a way to support cmd+click where you open that link in a new window?

Thanks!
Clark

Global or Router pending component

Using something like this:

<Router>
  <Route exact path="/lazy1" component={() => import('path/to/another-component1.svelte')} pending={Loading}/>
  <Route exact path="/lazy2" component={() => import('path/to/another-component2.svelte')} pending={Loading}/>
  <Route exact path="/lazy3" component={() => import('path/to/another-component3.svelte')} pending={Loading}/>
  <Route exact path="/lazy4" component={() => import('path/to/another-component4.svelte')} pending={Loading}/>
</Router>

I think we need something to avoid repetition of pending={Loading}.

Maybe a pending on <Router/> like this:

<Router pending={Loading}>

or better something like:

import { Router } from 'yrv';

Router.pending={Loading}

What do you think about?

new build with later svelte

I’m using this with snowpack and ran into the error pasted below.

I traced this to having svelte version ^3.4.4 hardcoded in the devDependencies. When updated to latest 3.17.3 and rebuilding, the snowpack import works fine.

I didn’t have time to bisect this to find out which version of svelte broke this.

- snowpack installing... 
Error: 'on_outro' is not exported by node_modules/svelte/internal/index.mjs
    at error (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:5330:30)
    at Module.error (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:9733:16)
    at handleMissingExport (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:9634:28)
    at Module.traceVariable (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:10072:24)
    at ModuleScope.findVariable (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:8679:39)
    at FunctionScope.findVariable (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:3015:38)
    at ChildScope.findVariable (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:3015:38)
    at FunctionScope.findVariable (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:3015:38)
    at ChildScope.findVariable (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:3015:38)
    at Identifier$1.bind (/Users/jan/Work/timeliner/node_modules/rollup/dist/rollup.js:4353:40)

IE11 do not update page

Hi,
I'm using this routing library for a specific project that must run even on IE11.
Currently it works perfectly on MS Edge but on IE11 the address bar is correctly updated while the page is not changed.
It seems that the update on history and in location too it will cause some issue.

Currently I use a very very ugly workaround:

  const ua = window.navigator.userAgent
  const ie11 = ua.indexOf('rv:11.0') !== -1

  if (ie11) { // detect it's IE11
    window.addEventListener("hashchange", (event) => {
      window.location.reload();
    }, false);
  }

that reload the page everytime an hashchange event is triggered.

Hash-based routes?

What it really means Hash and URI-based routes in Readme.md?

I can use hash-based routes Γ  la Gmail? e.g.: index.html#/profile, index.html#/book/42?

warning with rollup on compile in Route.svelte

(!) Plugin svelte: Route has unused export property 'props'. If it is for external reference only, please consider using export const 'props'
node_modules/yrv/src/Route.svelte
27: export let key = null;
28: export let path = '/';
29: export let props = null;
^
30: export let exact = null;
31: export let disabled = false;

Using bind directive with activeRouter

Hello!

Liking the library. Tried svero and couldn't make good sense of things, swapped in yrv and everything started making sense.

However I am interested in having activeRouter be an exported prop so that I can bind to it from the outside. Let me know how you feel about that and if desired I can submit a PR. Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.