Giter Club home page Giter Club logo

solid-router's People

Contributors

100terres avatar albertsabate avatar aminya avatar amoutonbrady avatar andrewrosss avatar birkskyum avatar brendan-csel avatar brendonovich avatar brenelz avatar btakita avatar cliffordfajardo avatar csarnataro avatar danieltroger avatar davedbase avatar edemaine avatar femincan avatar gabrielelpidio avatar high1 avatar jeski-bright avatar jutanium avatar marvin-j97 avatar nksaraf avatar orenelbaum avatar rturnq avatar rvlzzr avatar ryansolid avatar sanichkotikov avatar schniz avatar thetarnav avatar yhdgms1 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar

solid-router's Issues

Support optional path params

Add support for optional params so /page and /page/unknown both match in this example:

<Route path="/page/:pathParam?" component={MyPage} />

Adding a title property to the route config to update the document title on navigation

Was reading some articles recently around SPA's and the issue of a document title when pages change. I thought there might be an opportunity to add something into the router config to capture a page title (potentially combined with a "template" title for building a title of site name - page name for example)

I was thinking something along the lines of having a router config property (and route component prop) of "title", which is then used during the navigation function to set the document title. The "template" could be a top level config item (or even a property of the main Router object) which sets the template string and has some sort of placeholder that is replaced with the actual title to be updated.

I'm happy to look at getting a PR together to see if it could work, but just wanted to see if it's something that would be liked/supported.

Go to previous route

Hi.

For example, as a user I can navigate to some edit page from different routes, and after changes is applied, I need to navigate back to previous route. Is there any way to do this?

If I remember right, in react-router there was a state that can be anything (for example state: { prev: location.pathname }). But state here is just a string or null. And looks like it doesn't work (or I don't understand something). navigate('/users/edit', { state: location.pathname }) after this, I've still got null state on edit page.

Default value of `href`

Could you add an option for empty links. Links that could be used as buttons, for example.
Then usually don't need href. But a link must have href, so there's a trick with javascript:void(0).

Input

<Link>To the moon</Link>

Output

<a href="javascript:void(0)">To the moon</a>

The idea is to set href to javascript:void(0) as a default value.

Expose the entire router state in data function

I guess it would be more of a discussion than an issue, but while working on the real world example rewritten with solid app router, I encountered a situation where I'd like to access the router.location and listen to the change within the data function.

I thought about just using the useRouter and access router.location but it turns out we can't access this context in data functions. Digging a bit into the source code, I figured you manually generate getters for query and params to be passed into the data function props.

Is there a reason we just don't feed the whole state proxy into the data function here:

https://github.com/ryansolid/solid-app-router/blob/bb251041c245ed2247cbb1885f16acf981c11e70/src/index.tsx#L205-L212

Like so:

return levels[i].handler.data!(state); 

I did patch it locally and it seems to work and since the proxy already exist I don't think we pay any perf price. That being said, I guess we are exposing more than the user could ever need.. And I would understand if you'd prefer discarding that issue.

Using a <Link> component to navigate to the current route does not update data

It seems routing to the current page, but using a different pattern than the one you are currently on, does not update the data associated with that route. An example of when this might be done is on a product page, linking to another related product.

Steps to reproduce:

  1. Run the given code on a server
  2. Visit https://127.0.0.1/foo/1
  3. Click on "Go to page 2"

Expected result: The title reads "You are on page 2"
Actual result: The title reads "You are on page 1", even though the URLhas updated

import { createSignal, Accessor } from 'solid-js';
import { MountableElement, render } from 'solid-js/web';
import { Router, Routes, Route, Link, useData } from 'solid-app-router';
import { Params } from 'solid-app-router';

function FooData({ params }: { params: Params}): Accessor<number| undefined> {
	return createSignal(parseInt(params.id))[0];
}

function Foo() {
	const routingData = useData() as Accessor<number| undefined>;

	return <>
		<h1>You are on page {routingData()}</h1>
		<Link href={`/foo/1`}>Go to page 1</Link>
		<br/>
		<Link href={`/foo/2`}>Go to page 2</Link>
	</>;
}

render(
	() => (
		<Router>
			<Routes>
				<Route path="/foo/:id" element={<Foo />} data={FooData} />
			</Routes>
		</Router>
	),
	document.getElementById('app') as MountableElement
);

(Screenshot of step 2)
image
(Screenshot of step 3)
image

Serve + Nested Routing results in Error

I'm currently using serve with the following config to redirect all routes back to index.html:

{
  "rewrites": [
    { "source": "/**", "destination": "/index.html" },
    { "source": "/**/**", "destination": "/index.html" }
  ]
}

My Routes are defined as follows in Solid:

const AppRoutes = () => {
  return (
    <Routes>
      <Route
        path="/"
        element={
          <div>
            <Link href={'/app/2'}>Link</Link>
          </div>
        }
      />
      <Route path={'/app'}>
      <Route path={'/'} element={<p>Hi</p>}></Route>
        <Route path={'/*all'} element={<p>Hello</p>}></Route>
      </Route>
    </Routes>
  );
};

Going directly in the browser to localhost:3000/app results in the correct

Hi

being displayed. Clicking the link if I go to localhost:3000 correctly displays

Hello

.

However, if I decide to hit localhost:3000/app/2 in my address bar, I get the following errors:

[Error] SyntaxError: Unexpected token '<'
	(anonymous function) (runtime.js:1)
[Error] SyntaxError: Unexpected token '<'
	(anonymous function) (solid-js.js:1)
[Error] SyntaxError: Unexpected token '<'
	(anonymous function) (regexparam.js:1)
[Error] SyntaxError: Unexpected token '<'
	(anonymous function) (rturnq.js:1)
[Error] SyntaxError: Unexpected token '<'
	(anonymous function) (main.js:1)
[Error] Did not parse stylesheet at 'http://localhost:3000/app/main.css' because non CSS MIME types are not allowed in strict mode.

I'm using the latest solid/solid-router and webpack

Any chance there's a known solution to this and I'm just being dumb?

useLocation and URL fragment?

I'm trying to create Facebook manual authentication flow using solid.js featuring solid-app-router. For response_type=token, Facebook API redirect url is called having access token data in URL Fragment. More info can be found here.

How can I parse URL Fragment using solid-app-router hooks? I suppose useLocation should return location with hash as a URL Fragment, right? At least my simple code returns hash as an empty string.

For url localhost:3000/auth-callback/?#access_token=<lots_of_characters> and the Component

import { Component } from "solid-js";
import { useLocation } from "solid-app-router";

const AuthCallback: Component = () => {
  const location = useLocation();

  return (
    <div>{JSON.stringify(location)}</div>
  );
};

export default AuthCallback;

the output is: {"pathname":"/auth-callback","search":"","hash":"","state":null,"key":"","query":{}}

Add named routes

The official router for Vue.js has a feature called "Named routes". It makes it possible to give the routes a separate name to refer to them instead of using the actual route. The benefit of this is that you can rename the route inside the config file but not where it has been referenced.

This feature would be a great addition.

Uncaught Error: Make sure your app is wrapped in a <Router />

When I use Dynamic to switch between "internal" components in my "main page component" using a signal, <Link>s fail with the error in the title.

Example

(Also, on a related note, is it a bad idea to store the "internal state component" in a signal? If it is, how else am I going to create components with dynamic data (when I, for example, receive data from a websocket and want to display that data in a new component by passing it as props which is then shown using <Dynamic/>)?)

Allow useMatch take RouteDefinition object instead of path.

Basically I want to know which route is currently active outside of <Routes/>, so I can for example change nav bar styles on specific page, currently this is hard to do correctly. So my proposed solution is to allow useMatch take RouteDefinition object so this works:

const LIST_ROUTE = {
  path: '/list',
  component: List,
  children: [
    { path: '/' },
    { path: '/apples' },
    { path: '/oranges' },
    { path: '/banana' },
  ],
}

const routes: RouteDefinition[] = [
  {
    path: '/',
    component: Home,
  },
  LIST_ROUTE,
]

export const App = () => {
  const Routes = useRoutes(routes)
  const isListRoute = useMatch(LIST_ROUTE)

  return (
    <div>
      <Routes />
      <BottomNavBar hide={isListRoute()} />
    </div>
  )
}

Alternative today is to use

const isListRoute = useMatch(() => '/list/*') // Matches everything and is not a correct solution
// or way more complicated
const isListRoute = useMatch(() => '/list/')
const isListAppleRoute = useMatch(() => '/list/apple') 
const isListOrangeRoute = useMatch(() => '/list/orange') 
const isListBananaRoute = useMatch(() => '/list/banana') 
const isListRouteActive= createMemo(() => isListRoute() && isListAppleRoute() && isListOrangeRoute() && isListBananaRoute())

There might be some other way to solve this like having <Routes /> fire change event with matched route id.

Route to path ="/" is not working in electron.js

td,dr

need Hashrouter equivalent for solid.

I was trying the routing in a basic electron app and got stuck with this.

The path="/" works fine in browsers but I cannot GET that page in my electron window.

STEPS TO REPRODUCE

app.tsx

import { Link ,Route, Routes } from "solid-app-router";

export const App = () => {
  const Nav = () => {
    return (
      <>
      <div style={{display:"flex"}}>
      <Link style={{"margin-right":"10px"}} href="/">homepage</Link>
      <Link style={{"margin-right":"10px"}} href="/newcomponent">new component</Link>
      </div> 
      </>
    );
  };
  const Homepage = () => {
    return (
      <>
        <Nav />
        <div>homepage component.</div>
      </>
    );
  };
  const Component1 = () => {
    return (
      <>
        <Nav />
        <div>new component.</div>
      </>
    );
  };
  return (
    <>
      {/* <Nav />  */} 
      <Routes>
        <Route path="/" element={<Homepage />} />
        <Route path="/newcomponent" element={<Component1 />} />
      </Routes>
    </>
  );
};

index.tsx

import { render } from "solid-js/web";
import { Router } from "solid-app-router";
import { App } from "./app.main";

render(
  () => (
    <Router>
      <App />
    </Router>
  ),
  document.getElementById("app")
);
`

EXPECTED OUTPUT

This code was supposed to show Homepage component on loading the window.

OUTPUT -

Both components were not loaded. I have to make the Nav component load on every page to route between pages.
The default path="/" is not getting loaded.

THIS CODE WORKS AS EXPECTED IN BROWSERS.

TECHSTACK

  • solid.js ^1.2.6
  • solid-app-router ^0.1.14
  • electron ^16.0.5
for creating a local solid-electron instance

use - https://github.com/DhansAL/solidjs-electronForge-TS-template

Expose createPathMatcher to public

Expose createPathMatcher function. useMatch only works with current path, so you have no options if you want for example compare previous path and see if it matches.

Expose RouteProps to public

Allows Route component to be extended or encapsulated. i.e. if I want an authenticated route, a good pattern might be...

type AuthenticatedRouteProp = RouteProp & { isAuthed: boolean };
const AuthenticatedRoute: Component<RouteProp> = (props) => {
  return (
    { props.isAuthed ? <Route {...props} /> : <Navigate href={'/login'} /> }
  );
} ;

which means that RouteProp needs to be exposed

MergeProps in RouteDefinitions data result in Proxy error

Good day, library maintainers!

I was playing around with this router (and solid in general) and wanted to say thank you for this awesome library, and ecosystem you are working on. This is a breath of fresh air and I am definitely looking forward to incorporate Solid into my work!

I looked into the source code for this router and found out how to use data object. But I found out that if you are using mergeProps in the data property in route definitions it's breaking with Proxy error, but if I just return new object (without mergeProps) it's working as intended.

I am not sure it's a solid-app-router bug or bug in the main library, but I didn't encounter this before, while using solid without this router.

Error:
'ownKeys' on proxy: trap result did not include 'Symbol(state-proxy)'

Repro link

I might've misunderstood something with mergeProps so it might not be a bug at all.

support conditional Route

I'd like to render one Route or another depending on the data from a store.

Is it supported somehow?

Document how components in nested routes work

This one threw me off for a while until I understood how it works. In the routes definition, when a route has children, its component must contain a Route component for those children to be rendered.

For example;

import { Route, Router } from 'solid-app-router';
import { lazy } from 'solid-js';
import { render } from "solid-js/web";

const routes = [
  {
    path: '/my-page',
    component: lazy(() => import('./pages/my-page')),
  },
  {
    path: '/my-page/:slug',
    component: Route, // <-- this is what I was missing
    children: [
      {
        path: '/',
        component: lazy(() => import('./pages/my-page/[slug]')),
      },
      {
        path: '/sub-page',
        component: lazy(() => import('./pages/my-page/[slug]/sub-page')),
      },
    ],
  },
];

const App = () => (
  <Router routes={routes}>
    <Route />
  </Router>
);

render(App, document.getElementById('app'));

In the example I've used Route as the actual component but it's enough for the route's component to contain a <Route />.

It's obvious in retrospect but after using so many different router implementations over the years I wasn't sure if it was automagically injected or just how flexible nesting is.

Note: I know there's no formal documentation yet, so this is just a tip for when you get to it!

Symbolic useData

As discussed in Discord, the current numeric input to useData is brittle (even with the negative-number extension of #69). Using a component at different depths of the hierarchy makes it difficult to find the right ancestor data.

The general agreement from the thread was to introduce a context-like API. I believe the plan is to pass in the same function that was given as a data attribute to the Route. For example, <Route data={UserData}> woudl get accessed like so:

const data = useData(UserData);

Type-wise, this could work as follows:

function useData<T>(dataFunc: () => T): T | undefined;
  // returns undefined if no ancestor route uses this dataFunc

There was also discussion about useDataLoader but that seemed more specific to Resources (maybe a Solid Start thing?).

A related question is whether this should replace the existing numeric model (breaking change), or augment it as a second option (more code). I think at least we should preserve the common case, where useData() returns the current route's data, though this version will be better for typing even in that case.

Document path pattern syntax

It looks like the syntax supported for path patterns is the same as React Router, but it'd be helpful to at least say "supports :param and *rest parameters", and perhaps for those unfamiliar, clarify that :param matches a single component between slashes, while * must be the final thing (and looking at the code, I think prefixed by a slash?).

I found this hard to figure out without reading the code, because you also mention Ember Router which I'm not familiar with, so I figured there might be some additional pattern syntax.

Admittedly I couldn't find this well documented in React Router either, but I found brief mention here and here.

Top level paths always matches even if nested paths were declared first

I am not sure if this is a bug or just me not understanding how routes priority works.
Reproduction

<Route path="/" component={User}>
  <Route path="/users" element={<div>Should match this</div>} />
</Route>
<Route path="/users" element={<div>But matches this</div>} />

I discovered this while trying to use <Navigate> and redirect from /|/users to /users/default-route

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'then')

    at routing.js:231
    at untrack (solid.js:401)
    at navigateFromRoute (routing.js:192)
    at routing.js:246
    at Object.fn (RouteGuard.tsx:52)
    at runComputation (solid.js:593)
    at updateComputation (solid.js:578)
    at runTop (solid.js:654)
    at runUserEffects (solid.js:753)
    at solid.js:714

RouteGaurd line 52 is just a navigate('/login')

I am using the latest solid-app-router and solid (v1.3.1)

Which points to https://github.com/solidjs/solid-app-router/blob/ea0edc85502225ab62085014e9fb309df351634f/src/routing.ts#L338

//From dev tools
if (resolvedTo !== current || nextState !== state()) {
                if (isServer) {
                    if (output) {
                        output.url = resolvedTo;
                    }
                    setSource({ value: resolvedTo, replace, scroll, state: nextState });
                }
                else {
                    const len = referrers.push({ value: current, replace, scroll, state });
                    start(() => {
                        setReference(resolvedTo);
                        setState(nextState);
                    }).then(() => { // Here is the error
                        if (referrers.length === len) {
                            navigateEnd({
                                value: resolvedTo,
                                state: nextState
                            });
                        }
                    });
                }
            }

Autowire routes based on a predefined folder

It would be interesting to have a feature like this:

    <Router autowire={true} root={process.env.PUBLIC_URL}>
      <Nav />
      <Route class="view" />
    </Router>

Which takes a predefined (hard-coded) folder, let's say "pages" (since I've seen it on every solid projects. It will parse this folder and get path.jsx/tsx with its path.data.js/ts and generate the routes

Vite, ssr => Error [ERR_REQUIRE_ESM]

Trying to setup ssr with vite. Created server.ts as described in solid/vite docs/examples but at

render = (await vite.ssrLoadModule('/src/entry-server.tsx')).render; // renderToStringAsync inside

got error:

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/rootfs/var/www/thesite/thesite/node_modules/solid-app-router/dist/index.js
require() of ES modules is not supported.
require() of /home/rootfs/var/www/thesite/thesite/node_modules/solid-app-router/dist/index.js from /home/rootfs/var/www/thesite/thesite/node_modules/vite/dist/node/chunks/dep-11db14da.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/rootfs/var/www/thesite/thesite/node_modules/solid-app-router/package.json.

    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1089:13)
    at Module.load (internal/modules/cjs/loader.js:937:32)
    at Function.Module._load (internal/modules/cjs/loader.js:778:12)
    at Module.require (internal/modules/cjs/loader.js:961:19)
    at require (internal/modules/cjs/helpers.js:92:18)
    at nodeRequire (/home/rootfs/var/www/thesite/thesite/node_modules/vite/dist/node/chunks/dep-11db14da.js:73337:17)
    at ssrImport (/home/rootfs/var/www/thesite/thesite/node_modules/vite/dist/node/chunks/dep-11db14da.js:73290:20)
    at eval (/src/AppDocument.tsx:18:31)
    at instantiateModule (/home/rootfs/var/www/thesite/thesite/node_modules/vite/dist/node/chunks/dep-11db14da.js:73323:166)

Could you help with it?

Thank you!

Error in `normalize(path)` function when `path` is `undefined`

When I run my app in development mode (with vite-plugin-solid) I run into an issue where normalize function (found in utils.js) receives undefined as parameter. (This happens before path becomes / or any other string)

The code in normalize function doesn't check if path is a string and is trying to use replace method which causes runtime error.

I don't see this error when I serve a built application, so it might be related to solid-refresh

Here's my App with the routing tree:

import { Suspense, lazy } from 'solid-js'
import { Router, Routes, Route } from 'solid-app-router'

import AppHeader from './components/AppHeader'
import AppFooter from './components/AppFooter'

import './app.css'

const Home = lazy(() => import('./screens/home/Home'))

const ScreenOne = lazy(() => import('./screens/screen-one/ScreenOne'))
const ViewOne = lazy(() => import('./screens/screen-one/ViewOne'))
const ViewTwo = lazy(() => import('./screens/screen-one/ViewTwo'))
const ViewThree = lazy(() => import('./screens/screen-one/ViewThree'))

const ScreenTwo = lazy(() => import('./screens/screen-two/ScreenTwo'))
const ScreenThree = lazy(() => import('./screens/screen-three/ScreenThree'))


const NotFound = () => {
  return (
    <main>
      <h2>404</h2>
      <p>Path not found.</p>
    </main>
  )
}

const App = () => {
  return (
    <div class="app">
      <Router>
        <AppHeader />
        <Suspense fallback="Loading...">
          <Routes>
            <Route path="/screen-one" element={ <ScreenOne /> }>
              <Route path="/view-one" element={ <ViewOne /> } />
              <Route path="/view-two" element={ <ViewTwo /> } />
              <Route path="/view-three" element={ <ViewThree /> } />
              <Route path="/" element={ <ViewOne /> } />
            </Route>
            <Route path="/screen-two" element={ <ScreenTwo /> } />
            <Route path="/screen-three" element={ <ScreenThree /> } />
            <Route path="/" element={ <Home /> } />
            <Route path="/*all" element={ <NotFound /> } />
          </Routes>
        </Suspense>
        <AppFooter />
      </Router>
    </div>
  )
}

export default App

AppHeader component contains Link components:

import { Link } from 'solid-app-router'

const AppHeader = () => {
  return (
    <header class="app-header">
      <h1><Link href="/">Home</Link></h1>
      <nav class="app-navigation">
        <ul>
          <li><Link href="/screen-one">Screen One</Link></li>
          <li><Link href="/screen-two">Screen Two</Link></li>
          <li><Link href="/screen-three">Screen Three</Link></li>
        </ul>
      </nav>
    </header>
  )
}

export default AppHeader

Attached is a debugging screenshot:
Screenshot from 2021-12-06 07-52-00

Route Loads before the lazy Route Component Finishes fetching.

The path changes instantly but the Route component is still fetching, because of that, a flash of the blank page occurs.
How can I achieve a blocking way of fetching the Route Component, so when navigating to another lazy page it doesn't show a blank page but stays on the current one, and maybe shows a progress bar/line like on youtube by using a "hook" useIsFetching(route?), I Looked into Data functions but I think it doesn't suit this use case because I just want to load a Route Component and no data alongside it.

Example https://codesandbox.io/s/solid-router-185j1

Change `base` does not work

function App() {
  const [base, setBase] = createSignal('old');
  return <Router base={base()}>
    <button onclick={() => setBase('new')}>Change base</button>
    <Link href="/about">about</Link>
    <Routes />
  </Router>
}

After change base to new then call useNavigator()('/about') still navigate to /old/about

Allow sub path '*all' to match top level '*all' instead.

Common use case is to show completely empty not found page, if route doesn't match, without any specific sub path elements, currently this is not possible without redirects which change current path or some position absolute styling hacks.

In this example I wish to show top level Not Found page and not sub level one when no other routes match.
Example

const User = () => (
  <div class="user-page">
    <div>User page</div>
    <Outlet />
  </div>
);
...
<Routes>
  <Route path="/" element={<div>Home</div>} />
  <Route path="/users" component={User}>
    <Route path="/" element={<div>User</div>} />
    <Route path="/sub" element={<div>UserSub</div>} />
    <Route
      path="/*all"
      element={
        <div>
          Foward this to top level "Not Found" page somehow
          while keeping current path.
        </div>
      }
    />
  </Route>
  <Route path="/*all" element={<div>Not Found</div>} />
</Routes>;

Using mergeProps in data causing TypeError

Possibly similar to #6 - using mergeProps in data seems to cause the following error on latest solid-js and solid-app-router:

TypeError
can't define property Symbol("state-node"): Object is not extensible
getDataNodes
https://uojg1.csb.app/node_modules/solid-js/dist/solid.js:1131:23
get
https://uojg1.csb.app/node_modules/solid-js/dist/solid.js:1158:33
Data/</<
tab1.tsx:12:18

   9 |       <button type="button" onClick={increment}>
  10 |         {count()}
  11 |       </button>
> 12 |       <code>{JSON.stringify(props, null, 2)}</code>
     |                  ^
  13 |     </>
  14 |   );
  15 | }

Here is the forked sandbox from #6 where I just updated the versions to latest solid-js and solid-app-router: https://codesandbox.io/s/silent-voice-uojg1

Removing the use of mergeProps allows it to work without error.

Data fetcher function is executed multiple times

I am trying out solidjs with solid-start. Here's the repo: https://github.com/HriBB/solid-started

I have two pages:

Homepage

// src/pages/index.data.ts
import { createResource } from 'solid-js'

export type Data = {
  page: string
  simulateFetch: boolean
  sleep: number
}

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))

const simulateFetch = async () => {
  console.log('fetch home data')

  const ms = 1000
  await sleep(ms)
  return {
    page: 'home',
    simulateFetch: true,
    sleep: ms,
  }
}

export default function HomeData() {
  const [data] = createResource(simulateFetch)
  return data
}

// src/pages/index.tsx
import { Resource } from 'solid-js'
import { useData } from 'solid-app-router'

import { Data } from './index.data'
import { Hero } from '~/components/home/hero'
import { CallToAction } from '~/components/home/call-to-action'
import { GettingStarted } from '~/components/home/getting-started'
import { LoremIpsum } from '~/components/home/lorem-ipsum'
import { Pricing } from '~/components/home/pricing'

export default function Home() {
  const data = useData<Resource<Data>>()
  return (
    <div class="leading-normal tracking-normal text-white gradient">
      <div text="center" p="t-20">
        {JSON.stringify(data(), null, 2)}
      </div>
      <Hero />
      <LoremIpsum />
      <GettingStarted />
      <Pricing />
      <CallToAction />
    </div>
  )
}

Blog

// src/pages/blog.data.ts
import { createResource } from 'solid-js'

export type Data = {
  page: string
  simulateFetch: boolean
  sleep: number
}

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))

const simulateFetch = async () => {
  console.log('fetch blog data')

  const ms = 1000
  await sleep(ms)
  return {
    page: 'blog',
    simulateFetch: true,
    sleep: ms,
  }
}

export default function BlogData() {
  const [data] = createResource(simulateFetch)
  return data
}

// src/pages/blog.tsx
import { Resource } from 'solid-js'
import { useData } from 'solid-app-router'

import { PostList } from '~/components/post'
import { Content } from '~/components/ui'
import { Data } from './blog.data'

export default function Blog() {
  const data = useData<Resource<Data>>()
  return (
    <Content>
      {JSON.stringify(data(), null, 2)}
    </Content>
  )
}

When I navigate back and forth between home and blog, simulateFetch function is execute multiple times. Here's the console.log:

client.ts:22 [vite] connecting...
client.ts:52 [vite] connected.
index.data.ts:12 fetch home data
blog.data.ts:12 fetch blog data
blog.data.ts:12 fetch blog data
blog.data.ts:12 fetch blog data
index.data.ts:12 fetch home data
index.data.ts:12 fetch home data
blog.data.ts:12 fetch blog data
blog.data.ts:12 fetch blog data
index.data.ts:12 fetch home data
index.data.ts:12 fetch home data
...

Is this a bug or am I doing something wrong?

More than 2 levels of nesting not work

It seems can not use more than 2 levels of nesting.
Is it a bug or design limit?

https://codesandbox.io/s/solid-router-nesting-thlvg?file=/src/main.tsx

import { Router,  Route,  Routes,  Link,  useParams,  Outlet} from 'solid-app-router'
import { render } from 'solid-js/web'

function AppFrame() {
  return (
    <>
      <h1>AppFrame</h1>
      <Outlet />
    </>
  )
}

function ArticleList() {
  return (
    <>
      <h2>Article List</h2>
      <ol>
        <li>
          <Link href="/articles/1">Article #1</Link>
        </li>
        <li>
          <Link href="/articles/2">Article #2</Link>
        </li>
        <li>
          <Link href="/articles/3">Article #3</Link>
        </li>
      </ol>
      <Outlet />
    </>
  )
}

function Article() {
  const params = useParams<{ id: string }>()
  return <p>Article Content: {params.id}</p>
}

export default function App() {
  return (
    <Router>
      <p>
        <Link href="/">Home</Link>
      </p>
      <hr />
      <Routes>
        <Route path="/" element={<AppFrame />}>
          <Route path="/" element={<ArticleList />}>
            <Route path="/articles/:id" element={<Article />} />
          </Route>
        </Route>
      </Routes>
    </Router>
  )
}

render(() => <App />, document.getElementById('app'))

route no working in production build

Hi,
When im in development, button is navigating to another url.
but when i run npm run build
and i do npm run serve
and i click the button to navigate its not working only the url is change.

TIA

default page when parent is click

Hi is this possible?
From
image
To
image

I want to achieve is when i click the parent link. then the first(or any) child should be the default page to show.

Thanks for help.

The active class triggers for `NavLink`s using the `/` path, regardless of what path you visit.

Summary: The active class triggers for NavLinks using the / path, regardless of what path you visit.

Steps to reproduce:

  1. Run the following code
  2. Navigate to the "list" page

Expected result: Only the list NavLink has an active class
Actual result: Boththe NavLinks have an active class

import { MountableElement, render } from "solid-js/web";
import { Router, useRoutes, NavLink } from "solid-app-router";

const routes = [
	{
		path: "/",
		component: () => <div>Home</div>
	},
	{
		path: "/list",
		component: () => <div>List</div>,
	},
];

function App() {
	const Routes = useRoutes(routes);
	return (
		<>
			<NavLink href="/">
				Home
			</NavLink>
			<NavLink href="/list">
				List
			</NavLink>
			<Routes />
		</>
	);
}

render(
	() => (
		<Router>
			<App />
		</Router>
	),
	document.getElementById("app") as MountableElement
);

Commentary
I get the logic behind this, in that if you are visiting product/<some id here> you might want to match against a /product NavLink. But I think there still should be a way to get an active class on your root directory without it always having to be active.

Also, thanks for all the hard work you guys have done on this router, and solidjs in general!

Improve documentation for useLocation

The parseQuery in the example for useLocation is a bit misleading IMHO. Mention that location.query returns a Proxy that can be used to access the query parameters, e.g.

const location = useLocation();

return <p>{location.query.code}</p>;

Also mention whether query parameters are downcased or not, so whether ?confirmationCode=123 has to be accessed as location.query.confirmationcode or location.query.confirmationCode.

Suspense & Solid app router together will break the suspense fallback.

Suspense & Solid app router together will break the suspense fallback if you click on a link where a resource is loading.
The page will be blocked instead until the resource is done loading.
I'm guessing this isn't expected behavior.

Example:

//App.js
export default () => {
  const Routes = useRoutes(routes);

  <Suspense fallback={<p>Loading Page...</p>}>
    <Routes />
  </Suspense>
};

//Dashboard.js
export default () => {
	const [data] = createResource(() => {
		return new Promise((resolve) => {
			setTimeout(() => {
				resolve('DATA LOADED');
			}, 3000);
		});
	});

	return <div>Dashboard Page {data()}</div>;
};

Using `useNavigate()` threw an error

When call the useNavigate function, useRouter() cannot find a router context.

Uncaught Error: Make sure your app is wrapped in a <Router /> arises, but the app is certainly wrapped in a Router component.

Here is some of the code:

// index.tsx
import { render } from 'solid-js/web'
import { Router, useRoutes } from 'solid-app-router'
import { Component, lazy } from 'solid-js'

const routes = [
 {
   path: '/',
   component: lazy(() => import('./pages/Home')),
   children: [
     {
       path: '/',
       component: lazy(() => import('./pages/scripts/ScriptList')),
     },
     {
       path: '/script/add',
       component: lazy(() => import('./pages/scripts/ScriptAdd')),
     },
   ],
 },
]

const App: Component = () => {
 const Routes = useRoutes(routes)
 return <Routes />
}

render(
 () => (
   <Router>
     <App />
   </Router>
 ),
 document.getElementById('root')
)

// other.tsx
import { useNavigate } from 'solid-app-router'

const fn = () => {
 const navigate = useNavigate()
 navigate('/script/add')
}

Is anything wrong in this?

useMatch is not consistence with classList

 <Link
      href="/about"
      classList={{
        "bg-blue-100 hover:bg-blue-100": Boolean(useMatch(() => "/about")()),
      }}
      className="rounded-full hover:bg-gray-100 px-2 py-1"
    >
     

      <span className="text-sm font-bold">About Us</span>
    </Link>

Refresh on /about path do not apply classList

Changing URL directly got 404 not found

Hello I have some problem when directly change the URL in URL bar or refresh page and it got "404 Not Found" but when I have changed URL by clicking on <Link> then it show the component normally

It's only affected to sub-route such as "/users", "/2", "/1" but the route "/" is perfectly fine.

Before refresh page
image

After refresh page
image

My project environment

  • snowpack.js ^3.7.1
  • solid.js ^1.0.0
  • solid-app-router: ^0.0.51

*Edit
This is my snowpack config file

 * @type {import('snowpack').SnowpackConfig}
 */
const config = {
  mount: {
    public: "/",
    src: "/assets"
  },
  packageOptions: {
    installTypes: true,
    NODE_ENV: true
  },
  devOptions: {
    out: "dist",
    open: "none",
    bundle: true
  },
  buildOptions: {
    clean: true,
    out: "dist"
  },
  plugins: ["@snowpack/plugin-typescript", "@snowpack/plugin-babel", "@snowpack/plugin-postcss"],
  optimize: {
    bundle: true,
    minify: true,
    target: "es2020",
    treeshake: true,
    splitting: true
  }
};

module.exports = config;

SSR with router

Hi all, I apologize in advance for the translation.

I am trying to start writing in this wonderful framework. I have set up a project build for server side rendering. Everything works fine for me. But I decided to use this router to move forward. Client-side works fine, but after connecting the library, server-side stopped building.

ERROR in ./node_modules/solid-app-router/dist/index.js 503:15-23
export 'template' (imported as 'template') was not found in 'solid-js/web' (possible exports: Assets, Dynamic, ErrorBoundary, For, HydrationScript, Index, Match, NoHydration, Portal, Show, Suspense, SuspenseList, Switch, createComponent, escape, generateHydrationScript, getHydrationKey, isServer, mergeProps, pipeToNodeWritable, pipeToWritable, renderToString, renderToStringAsync, resolveSSRNode, spread, ssr, ssrBoolean, ssrClassList, ssrHydrationKey, ssrSpread, ssrStyle)
@ ./src/shared/App.tsx 14:0-42 79:27-33
@ ./src/server/index.tsx 10:0-35 34:39-42

ERROR in ./node_modules/solid-app-router/dist/index.js 652:4-10
export 'insert' (imported as 'insert') was not found in 'solid-js/web' (possible exports: Assets, Dynamic, ErrorBoundary, For, HydrationScript, Index, Match, NoHydration, Portal, Show, Suspense, SuspenseList, Switch, createComponent, escape, generateHydrationScript, getHydrationKey, isServer, mergeProps, pipeToNodeWritable, pipeToWritable, renderToString, renderToStringAsync, resolveSSRNode, spread, ssr, ssrBoolean, ssrClassList, ssrHydrationKey, ssrSpread, ssrStyle)
@ ./src/shared/App.tsx 14:0-42 79:27-33
@ ./src/server/index.tsx 10:0-35 34:39-42

ERROR in ./node_modules/solid-app-router/dist/index.js 654:4-10
export 'effect' (imported as 'effect') was not found in 'solid-js/web' (possible exports: Assets, Dynamic, ErrorBoundary, For, HydrationScript, Index, Match, NoHydration, Portal, Show, Suspense, SuspenseList, Switch, createComponent, escape, generateHydrationScript, getHydrationKey, isServer, mergeProps, pipeToNodeWritable, pipeToWritable, renderToString, renderToStringAsync, resolveSSRNode, spread, ssr, ssrBoolean, ssrClassList, ssrHydrationKey, ssrSpread, ssrStyle)
@ ./src/shared/App.tsx 14:0-42 79:27-33
@ ./src/server/index.tsx 10:0-35 34:39-42

ERROR in ./node_modules/solid-app-router/dist/index.js 654:17-29
export 'setAttribute' (imported as 'setAttribute') was not found in 'solid-js/web' (possible exports: Assets, Dynamic, ErrorBoundary, For, HydrationScript, Index, Match, NoHydration, Portal, Show, Suspense, SuspenseList, Switch, createComponent, escape, generateHydrationScript, getHydrationKey, isServer, mergeProps, pipeToNodeWritable, pipeToWritable, renderToString, renderToStringAsync, resolveSSRNode, spread, ssr, ssrBoolean, ssrClassList, ssrHydrationKey, ssrSpread, ssrStyle)
@ ./src/shared/App.tsx 14:0-42 79:27-33
@ ./src/server/index.tsx 10:0-35 34:39-42

ERROR in ./node_modules/solid-app-router/dist/index.js 720:0-14
export 'delegateEvents' (imported as 'delegateEvents') was not found in 'solid-js/web' (possible exports: Assets, Dynamic, ErrorBoundary, For, HydrationScript, Index, Match, NoHydration, Portal, Show, Suspense, SuspenseList, Switch, createComponent, escape, generateHydrationScript, getHydrationKey, isServer, mergeProps, pipeToNodeWritable, pipeToWritable, renderToString, renderToStringAsync, resolveSSRNode, spread, ssr, ssrBoolean, ssrClassList, ssrHydrationKey, ssrSpread, ssrStyle)
@ ./src/shared/App.tsx 14:0-42 79:27-33
@ ./src/server/index.tsx 10:0-35 34:39-42

Doc: remove useRoutes hook from the README JSX example

It seems the JSX example in the README contains the useRoutes hook when it shouldn't be needed for it and will cause confusion for incoming new users :)

...
import { Router, Routes, Route, Link } from "solid-app-router";
...

function App() {
  const Routes = useRoutes(routes); <--- To remove
  return (
    <>
      <h1>Awesome Site</h1>
      <Link class="nav" href="/">
        Home
      </Link>
      <Link class="nav" href="/users">
        Users
      </Link>
      <Routes>
        <Route path="/users" element={<Users />} />
        <Route path="/users/:id" element={<User />}>
          <Route path="/" element={<UserHome />} />
          <Route path="/settings" element={<UserSettings />} />
          <Route path="/*all" element={<UserNotFound />} />
        </Route>
        <Route path="/" element={<Home />} />
        <Route path="/*all" element={<NotFound />} />
      </Routes>
    </>
  );
}

Document how to read routing data in a component

Take for example the route "/users/:id/orders?order=popular".

How does one read the following inside the component which is routed to?:

  • the route parameters (:id)
  • the query parameters (order=popular)

I've been trying to read through the source code and at first glance it looks like these ought to be set as props on the component, but it's not proving to a very productive exercise.

Would you be able to provide a little more documentation regarding the basic usage?

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.