fridays / next-routes Goto Github PK
View Code? Open in Web Editor NEWUniversal dynamic routes for Next.js
License: MIT License
Universal dynamic routes for Next.js
License: MIT License
Hi and thanks again for this library, it's really helpful!
I have a case where I need to redirect when the user enters a URL which doesn't contain the locale. E.g if they go to "/", I want to redirect to "/en". If they go to "/courses", I want to redirect to "/en/courses". I have set up all the dynamic routes accordingly, seems to work. But I don't know how to redirect using the asPath
instead of the hidden URL (e.g how to redirect to "/en" instead of "/?locale=en"). Any hints?
My code currently looks like this:
import { format } from 'url'
...
static async getInitialProps(ctx) {
if (!process.browser) {
if (!ctx.query.locale) {
const sessionLocale = ctx.req.session ? ctx.req.session.user.locale : 'en'
const { pathname, query } = ctx
query.locale = locale = sessionLocale
ctx.res.writeHead(302, { Location: format({ pathname, query }) });
ctx.res.end();
}
...
}
...
}
Thanks a lot
I set up my index route like this:
routes.add('index', '/');
this.props.url is injected into my pages w/ a "pathname" attribute...among others. For this particular route, it's pathname value is "/index". I don't see how this value is useful. Shouldn't the pathname be the pattern param. We could also inject the route name param as a property on "url".
On another page I use this route:
routes.add('contactGeneral', '/contact/general', 'contact-general');
And this.props.url.pathname === '/contact-general'. Just doesn't make a lot a sense.
I have the route /post/:slug-:id
. It works fine on the client, but when SSRing I get a 500 error if the slug has a hyphen in it. I think it interprets the :id as the first thing after the first hyphen.
This technique had been working, installed the latest npm version and it's broken.
routes.add('entity', '/entity/:actor_id/:tab')
routes.add('entity', '/entity/:actor_id')
/node_modules/next-routes/dist/index.js:89
throw new Error('Route "' + name + '" already exists');
^
Error: Route "entity" already exists
I just want to say that this is a fantastic project, and you're doing a great job.
Next.js is great, but there are gaps that you & others are filing that makes the ecosystem very compelling.
Thanks for this, and have a happy Saturday!
I have defined the routes, all of them with parameters. But still, I can access them without parameters. Next-routes is not overriding the routes defined by next. How do I fix this?
Thanks a lot!
how would i handle a route like this domain.com/search?q=foo
. Creating a link <Link route="search" params={{ q: search }}>
does the right think when clicked but the adressbar only shows domain.com/search
.
I found that next-routes
API is not friendly.
In next.js
, each component could just depend on next/link
. So, component can reside in a standalone repo and published as npm package. However, when utilizing next-routes
, I have to import Link
from routes.js
file specific to given application. As a result, there is no way to create a standalone component to be shared.
import {Link} from 'path/to/routes';
How about making Link
and Router
accessible by singleton object in next-routes
? Like this
import {Link} from 'next-routes/link';
import {Router} from 'next-routes/router';
Internally, when next-routes
is executed to create instance, the instance is saved as singleton to be exposed by next-routes/link
and next-routes/router
.
Hi,
We've been using name routes which name starts with "/" for a while. For example, we had a route with name "/teacher/assignment". It was working fine, until the 1.0.30 update, which mistakes such routes to be unnamed routes.
It's not a big deal. We just need to change all the named routes so that they don't start with "/". Still, it would be nice if the developer is more mindful about breaking changes such as this.
Regards
Is there a recommended approach for adding Google Analytics?
Thank you!
Hi! Thanks for your work!
I have a question about .pushRouter()
method.
In my routes I have something like:
routes.add('users', '/people/:username/:page', 'index')
And when I do
Router.pushRouter("users", {username: 'nick', page: 'bio'})
I actually go to the necessary page, but url looks like /people/nick?page=bio
instead of /people/nick/bio
Am I doing something wrong or .pushRouter
doesn't have to do what I expect?
Thanks in advance and sorry if it is too silly question.
UPDATE
<Link />
does the same.
Hi,
I'm facing an issue that HMR is not working when using next-routes. It will do full reload instead.
I already followed the example given on the readme.
Here's my implementation:
routes.js
const nextRoutes = require('next-routes');
const routes = module.exports = nextRoutes();
const localeRegExp = '(/id|/en)?';
routes.add('index', localeRegExp);
routes.add('search', `${localeRegExp}/search/:urlName`);
server.js
const routes = require('./routes');
const handler = routes.getRequestHandler(app);
const server = express();
app.prepare()
.then(() => {
server
.use(handler)
.listen(3000, function (err) {
console.log('err', err);
})
})
Any idea about this?
I ran across this error today, and was thoroughly confused. I also found the solution, so wanted to share in case others hit the same thing!
TypeError: Cannot read property 'match' of undefined
at /node_modules/next-routes/dist/index.js:102:27
at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/node_modules/express/lib/router/index.js:317:13)
at /node_modules/express/lib/router/index.js:284:7
at Function.process_params (/node_modules/express/lib/router/index.js:335:12)
at next (/node_modules/express/lib/router/index.js:275:10)
at expressInit (/node_modules/express/lib/middleware/init.js:40:5)
at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/node_modules/express/lib/router/index.js:317:13)
at /node_modules/express/lib/router/index.js:284:7
I had changed the example code:
server.js
- const routes = require('./routes');
- const handler = routes.getRequestHandler(app);
+ const { getRequestHandler } = require('./routes');
+ const handler = getRequestHandler(app);
Ie; I had introduced a destructruing require
, which resulted in the above error.
Stick with a non-destructured require
like the docs show:
server.js
const routes = require('./routes');
// ...
const handler = routes.getRequestHandler(app);
From what I have experienced, since version 1.0.40 it seems nextjs always reloads the index page.
First, thanks for this. I've implemented it and it serves almost all of my needs.
I'd like to propose adding a feature: a parseParams
function of some sort as an option.
I'm rewriting a legacy app that supports hundreds of urls. For example, there's one legacy route I must support that is /add-to-cart?qty=n&sku=n
In my components however, I don't expect a qty
parameter. I expect quantity
.
I've monkey-patched route.match to support a parseParams
function, which takes the incoming query and transforms it:
nextRoutes.add(name, path, item.page)
const route = nextRoutes.routes[nextRoutes.routes.length - 1]
const _match = route.match
route.match = (path) => {
let params = _match.call(route, path)
return !params
? undefined
: item.parseParams(params) // defaults to `identity`
}
Example of a parseParams
function:
parseParams: (data) => ({
sku: data.sku,
quantity: data.qty,
title: humanizeUrlParam(data.title)
})
Would next-routes be open to supporting this as part of the library? If so, I can open a PR.
I'm trying to simplify my webapp by using your package, thanks for providing! ๐
Here is my attempt: https://github.com/relatenow/relate/compare/next-routes
However, I get EventSource's response has a MIME type ("text/html") that is not "text/event-stream". Aborting the connection.
Maybe it's because I have a route /:slug
which, when not handled properly, might also match Next.js' internal routes such as __webpack_hmr etc.
How can this be fixed?
Next.js provides a great SSR caching example which makes use of Next.js' renderToHTML
and renderError
. Can next-routes somehow be used in conjunction with this or could this be implemented?
https://github.com/zeit/next.js/tree/master/examples/ssr-caching
Hi I'm using next-routes "^1.0.20" currently. I should note that I also tried upgrading to the newest next beta and next-routes 1.0.40, but got the same "TypeError: routes.isNextPath is not a function" error in my console.
While poking around for answers I found a few github issues where you've referenced this function. Would you mind helping me out? For some reason I can't find this function inside next-routes or next and I'm not sure what I'm getting wrong.
An Issue where you suggested it
#4 (comment)
I thought I might be misunderstand something inside nextjs and saw another comment from you here:
vercel/next.js#1627 (comment)
My app is getting bogged down inside an if statement. Removing reference to isNextPath "!routes.isNextPath(req.url) &&" (in my forked code and pasted below) allows the app to run but I assume I lose SSR caching as a result(?)
Here's the code:
/server/session.js
const session = require('express-session');
const FileStore = require('session-file-store')(session);
const { SESSION_SECRET } = require('./config');
const acceptLanguage = require('./acceptLanguage');
const routes = require('../universal/routes');
// TODO store more persistently (this only survives while deployment is on same machine)
const store = new FileStore({ path: '/tmp/sessions' });
module.exports = {
configSession: session({
secret: SESSION_SECRET,
store,
resave: false,
rolling: true,
saveUninitialized: true,
httpOnly: true,
}),
defaultSessionData(req, res, next) {
if (!routes.isNextPath(req.url) && !req.session.user) {
req.session.user = { // eslint-disable-line no-param-reassign
locale: acceptLanguage(req),
};
}
next();
},
};
/universal/routes.js
const nextRoutes = require('next-routes');
module.exports = nextRoutes()
.add('/', 'index')
.add('about')
.add('discover')
.add('retreat', '/retreat/:id')
.add('track', '/track/:id')
.add('profile', '/:slug');
Thanks
Thanks for this great project.
I have been trying out the latest release of next.js
: 3.0.0-beta16
.
I have noticed that the Link component of next-routes
wasn't able to change the current route.
Is this library supporting that version of next.js yet?
How do you use next-routes with Koa v2?
Hey guys, I'm trying to resolve an issue and was hoping for some help. When navigating to a sub route from the client I am getting the sku
field as query string, but I need it as a parameter. It works as a parameter on server load but not client.
Example
<Link route='product' params={{sku:product.sku}}><a>Product 1</a></Link>
<Link route='product' params={{sku:product.sku}}><a>Product 2</a></Link>
Now if I load this url /product/123
directly it works and loads the correct page. However, if I am on another page and click on the links above the url read /product?sku=123
. I need both links to the the former. How can I get this fixed. Appreciate any pointers.
It seems that clicking on the Link component, the window location in the browser address bar is not updated.
What's the best approach to make it working without break SSR? Is this feature supported by the next-routes package?
Thank You.
This package breaks in IE 11 due to it's unpolyfilled use of Object.assign
.
It is risky to rely on Next.js to apply a global polyfill, because its not guaranteed - in v3 latest it is not present:
This issue can be resolved by refactoring all usage of Object.assign
to spread operator syntax. It's more elegant that way anyway.
I have a url that looks like:
http://localhost:3000/r/proud,cozy
And then have a route that looks like:
const nextRoutes = require('next-routes')
const routes = module.exports = nextRoutes()
routes.add('recommendations', '/r/:e')
This returns a query like:
{e: "proud,cozy"}
However I would like this returned instead:
{e: ["proud","cozy"]}
How could I apply a delimiter to the route, so that it knows that there can be one or more ':e', and that it would be split by ','?
From reading the README, it's not clear if Link supports Next.js' prefetch option?
Thanks ๐
After updating next-routes from 1.0.37
to 1.039
I get the error
Error when loading route: //c/HH
using next 3.0.1-beta.9
in production mode, on localhost is the same but the message is quite different
Hi, I have a url that is part of the data. I tried using the href value directly instead of params
and route
but it seems to be doing a full page navigation. Is it expected?
Thanks for this lib! I'm trying to implement SSR caching . Seems not to be working as expected. I'm unable to get the right page path to use the caching function.
We ended up having to do a quick cut over from our react-router + redux massive SPA to next.js. We used this lib to help convert the react-router style routes to next.js.
However we ended up "forking" (shoving into our repo) this lib to allow for:
You can see our implementation here
Our next-routes
implementation is here in the repo
Please feel free to reach out on this issue with questions, I hope to have more time to write a blog post on this / make some pull requests here, but I dont know if I will have the time for that as of yet
Thanks for such a great OS project!
With 1.0.15:
routes.js
:
const nextRoutes = require('next-routes');
module.exports = nextRoutes()
.add('/')
.add('about')
.add('discover')
.add('retreat', '/retreat/:id')
.add('track', '/track/:id')
.add('profile', '/:slug');
This code:
const { route, params } = routes.match(req.url);
console.log('Found next-routes: ', route, params);
(among other things) returns the log below:
Found next-routes: Route {
name: 'profile',
pattern: '/:slug',
page: '/profile',
keys:
[ { name: 'slug',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
partial: false,
asterisk: false,
pattern: '[^\\/]+?' } ],
regex: { /^\/((?:[^\/]+?))(?:\/(?=$))?$/i keys: [ [Object] ] },
getAs: [Function] } { slug: '__webpack_hmr' }
/:slug
matches on __webpack_hmr
, which it shouldn't.
Also not sure if it does or not, but should also ensure it won't match on /favicon.ico either.
Hi I have an issue like below:
server.js
app.prepare().then(() => {
const server = express();
const router = express.Router();
router.get('/:area', (req, res) => {
return app.render(req, res, '/index', req.query);
});
router.get('*', (req, res) => handle(wrappedRequest(req), res));
server.use('/prefix', router);
server.use('/prefix/static', express.static('static'));
server.listen(3000, err => {
if (err)
throw err;
console.log(`> Ready on http://localhost:3000/prefix`);
});
});
what I want to do is using next-routes? It worked fine when not using prefix
.
Is there any way to integrate prefix to next-route
?
Hi @fridays ,
currently im facing issue on the HMR again when integrating global stylesheets to the project.
Here's the repo to reproduce it: https://github.com/adrianha/next-routes-demo
Thanks!
How do I protect urls like using react router uses onEnter?
I have ran into an issue where next-routes
is called twice.
It's a mistake on my end, I have multiples routes to handle different subdomains.
I'm supposed to always import the routes of a the current subdomain.
However, a slight import mistake has wide side effect. I think that we have an opportunity to reduce the impact of such possible mistake.
What's the root cause? I have finally found that this modules is mutating next/router
.
What do you think of stopping doing such? I mean returning a new object reference.
Also, I'm gonna add a safe defensive code on my end to throw when the next-routes
is called a second time.
Hi!
Currently, I met some issues on iOS 8.4 devices.
When using <Link>
printWarning โ commons.js:102Warning: unmountComponentAtNode(): The node you're attempting to unmount was rendered by another copy of React.
React DOM tree root should always have a node reference.
When using Router.pushRoute('index', params)
TypeError: undefined is not a function (evaluating '_this5.keyNames.includes(key)')
This might be more related path-to-regexp
, but figured I'd start here.
I'd like to create a route definition that works with and without the ending slash. For example:
routes.add('myEntity', '/entity/:id\/*', 'entityPage');
What I want here is for the router to accept both of the following:
http://localhost:3000/entity/foo
and
http://localhost:3000/entity/foo/
Where foo
is mapped to the id
parameter.
Is this possible? Is this a question for path-to-regexp
instead?
It seems path-to-regexp
does this by default and it doesn't look like next-routes
is overriding this default. So maybe this is a bug? Should the following routes, be default, both resolve to the same page:
http://localhost:3000/entity/foo
http://localhost:3000/entity/foo/
If I have a route like:
/foo
or
/foo/bar
And I try to type that directly into the URL field of a browser rather than clicking a link generated in the website, I get a 404.
I'd like to be able to prevent loading the route before an animation is done, issue the route change, and then have a loading in animation.
So something like:
onRouteChange = e => {
e.preventDefault()
document.body.classList.remove('anim-in')
document.body.classList.add('anim-out')
document.body.addEventListener('animationend', () => {
issueRouteChange()
document.body.classList.add('anim-in')
}
}
obviously psuedocode
Here's my project which I just upgraded to use next-routes ๐
https://github.com/relatenow/relate
Unfortunately I was a bit fast, it looks like non-dynamic routes (like /about) aren't handled properly, they give a not found page when reloading from server (but work client-side). Did I miss something in the configuration or would this be a bug?
It would be awesome if a changelog.md
was added and Github releases were used to keep track of changes.
A common practice is to track changes under a next
version heading at the top of changelog.md
, then when ready to release:
package.json
.next
heading in changelog.md
to the new version.npm publish
.You can see that process in action at jaydenseric/apollo-upload-client.
Is it possible to support shallow rendering to skip rendering getInitialProps? Example: I'd like to use link/router to push a query string to a component that displays a modal based on the query string. Trying to figure out how this can be done without rendering the profile on the server again.
I have a serious of routes created that render to the page with named route properties.
The rendered react looks like this:
<Link route="blog">
<a onClick=bound linkClicked()>Blog</a>
</Link>
Which is defined by my menu.js component here:
import React from 'react'
import Link from 'next/link'
import {menu} from './routes'
export default () => (
<ul>
{
menu.map( (menuchen, index) =>
<li key={index}><Link route={menuchen.path}>
<a>{menuchen.title}</a>
</Link></li>)
}
</ul>
)
But when I click on the link the client console complains about a url
parameter.
Parameter 'url' must be a string, not undefined
I define the routes.js
here:
const routes = module.exports.routes = require('next-routes')()
const menu = module.exports.menu = [
{
title: "Blog",
path: "blog"
}
]
menu.forEach(menuchen => {routes.add(menuchen.path, menu.path, "index")})
and my server.js
setup looks like this:
const next = require('next')
const routes = require('./comps/menu/routes').routes
const app = next({dev: process.env.NODE_ENV !== 'production'})
const handler = routes.getRequestHandler(app)
const express = require('express')
app.prepare().then(() => {
express().use(handler).listen(3000)
})
I want to push to an error page if the status of a response from a request made in getInitialProps
returns 404 or 500.
We get the following error in ie 11 object doesn't support this property or method find
. We only use nextjs and next-routes. Maybe we need to chnage your babel Settings? vercel/next.js#473
After switching to React routes, I'm getting the following error in the console:
warning.js?c5303db:36 Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) r" id="react-select-2--value" data-react
(server) r" id="react-select-10--value" data-reac
This is the page that is rendering: https://github.com/runemadsen/artefact-next/blob/updateWorks/next/pages/work.js
This is my server setup: https://github.com/runemadsen/artefact-next/blob/updateWorks/next/server.js
Is this a problem with my config of next-routes?
Reproduction case: https://github.com/jesstelford/next-routes-issue-56
next
: 3.0.0-beta16
next-routes
: 1.0.27
git clone https://github.com/jesstelford/next-routes-issue-56.git next-routes-issue-56
cd next-routes-issue-56
yarn
yarn dev
http://localhost:3000/abc123
/abc123
page loads fine/about
/abc123
/abc123
works as expectedIt looks like under the hood, next.js's client-side routing is requesting the url http://localhost:3000/_next/1498079290131/page/abc123
instead of http://localhost:3000/abc123
. This wont match any routes I've setup, so it falls through to next.js, which throws the 404.
Server side rendering appears to work fine, because it's just a regular HTTP request being handled by express, which correctly matches one of the routes setup.
I tried adding some hacks such as path.replace(/^_next\/\d+\/page/, '')
, but that didn't appear to improve anything.
This happens in both development and production mode (initially I was led astray by Webpack HMR call stacks, but they don't appear in production mode, while the error persists)
Replacing Router.replace('/abc123');
with window.location = '/abc123';
in pages/about.js
will get it working client side again (by forcing a hard server refresh).
Kinda sorta maybe related(?): vercel/next.js#257
Just wondering where it is on the road map...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.