I've tried to check through the official documentation, various issues, and inside SO previous questions, but I can't find confirmation if it's possible to create a dynamic route in Next.js that contains a constant or a string combined with a slug. For example?
pages/
something-[slug].jsx
Is it possible or not? I'm inclined to think not because of the examples I've tried to build, but possibly I'm missing something.
While Next.js doesn't provide built-in support for partial dynamic routes (like something-[slug]), you can work around it by setting up an actual dynamic route and use rewrites to map the incoming URL (in the format you want) to that route.
For instance, you could setup a dynamic route under /pages/something/[slug].jsx, then configure a rewrites rule in next.config.js as follows.
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/something-:slug',
destination: '/something/:slug'
}
];
}
}
Related
How to generate pages in gatsby that will allow you to add parameters to the routing like https://page1?someParam=param or https://page1/param
What I mean? When we navigate to page page1 in gatsby it work's fine, but what if I just want add uniq params for page for google analitics? so for this I want to have ability
add some additional params for the page from where I made redirect, but when I add
for page1 some params like https://page1?someParam=param or https://page1/param, it updated and show me just https://page1 instead.
I suppose that it's related to way how I created pages. Here is my code:
createPage({
path: `${localePrefix}/${slug}`, // so should I change it here in order to work as needed?
component: PageTemplate,
context: {
...context,
localizedPaths,
},
})
Can it be fixed with?
matchPath: path: ${localePrefix}/${slug}?*,
matchPath: path: ${localePrefix}/${slug}/*,
Recap:
My question is about why gatsby remove query params from pages?
https://some_site/some_page?some_param=323
translates into
https://some_site/some_page
https://page1?someParam=param or https://page1/param are not the same. While a query parameter (first case: ?someParam=param) is an optional value that doesn't change the rendered page (it doesn't point to any specific route hence it's not requesting any file). The second one (https://page1/param) is accessing a /pages/param route.
Since they are URL parameters, you don't need to change anything in your project, you just need to catch them using JavaScript. They are handled in thee:
const urlParams = new URLSearchParams(window?.location?.search);
Note: you can access directly location prop in Gatsby
If your project is replacing https://some_site/some_page?some_param=323 to https://some_site/some_page it's because some server-side configuration or a CDN, not because of Gatsby's behavior, like any other React project.
I'm using remix to serve my react application.
All my pages have dynamic slugs, therefore I need to find a way to resolve the following type of URL:
eg. mywebsite.com/dynamic_slug
If I create an $index.jsx file in the routes folder it works in that all the dynamic URLs resolve to that file, BUT, I can't seem to find a way to then read the slug in the compontent so that I serve the right data.
Many thanks to any responders.
You access the dynamic params via the params object passed to your loaders and actions.
// routes/$index.jsx
export async function loader({request, params, context}) {
const slug = params.index // whatever $name is
//...
}
https://remix.run/docs/en/v1/guides/data-loading#route-params
I'm migrating a website developed with Gatsby to NextJS, but something I could achieve using Gatsby's createPage API is localizing the app's routes, but until now I couldn't achieve this with NextJS APIs.
I'm using Next v10.0.1 for this.
As I see in other threads regarding this type of resource, this is actually kinda confusing of what it actually means, so here goes an example of what is the desired result:
User access route /my-data/1234 (where the NextJS equivalent routing would be: /my-data/[dataId].js)
User must be able to access the same page but translated in the URL /pt/meus-dados/1234 (using, for example, portuguese translation).
Some guesses on how to achieve that keeping Next's static optimizations (Static rendering and Incrementing Static Rendering)?
I actually found an answer which is pretty useful for my use case, I'm using NextJS rewrites for that, maybe not the best solution, but fits my needs well.
I use a single file for each route, so the directory structure should be something like this:
pages
-- my-data
-- [id].js
then I'll have some kind of internationalization, in my case I'm using react-i18next, won't think about the aspects of implementations for the library here, it could also be achieved with any other.
Next step is to set a translation somewhere for the pages routes, for example, add an entry for the i18next messages named routes containing a key-value pair for the routes translations. e.g (intl/pt.json):
{
...
"routes": {
"/my-data/:id": "/meus-dados/:id"
}
...
}
and then use NextJS rewrites, so you will have to import the intl messages (e.g: from intl/pt.json) and map them as rewrites in next.config.js:
# next.config.js
...
async rewrites() {
// languages here is a key-value pair object containing the structure { [language]: { routes: {...} } }
// in my case, imported from `intl/pt.json`
const intlRewrites = Object.entries(languages).reduce((rewrites, [ language, { routes } ]) => {
return [
...rewrites,
...Object.entries(pages).map(([ path, translatedPath ]) => {
const source = translatedPath
const destination = path // here you can write a logic to add a language prefix if needed
return { source, destination }
})
]
}, [])
return intlRewrites
}
From my experience, optimizations like ISG work fine. Should work with SSG too, but I haven't tested it.
I've been tackling this exact problem, and whilst I don't yet have a solution that integrates directly into NextJS, this can be achieved fairly simply before your project is compiled.
If you were to organise your pages directory as follows, it should work as you expect:
// Before
pages
-- my-data
-- [id].js
// After
pages
-- pt
-- meus-dados
-- [id].js
-- en
-- my-data
-- [id].js
However the developer experience here isn't nice. So what I have done to solve this currently is written a simple build step that runs before next build. It takes a regular pages directory and converts it to the above format, allowing next build to run against a version that works as intended for the translated paths. This allows SSG and ISG to work as expected.
Ideally I'd like to hook into the Next ecosystem so this works seamlessly for dev and build, but I haven't yet gotten that far
I carefully read the docs of next routing system.
It only mentions that I could achieve dynamic routing like this:
http://localhost:3000/level1/dynamicSlug
But I am trying to achive something like this:
http://localhost:3000/level1/level2/dynamicSlug
And I want level2 to be created dynamic too
Thanks so much !
It is possible to do nested scenarios according to your request in this way.
for example:
pages/
level1/
[dynamicSlug]/
- index.js // will match for /level1/1234
level2/
- index.js // will match for /level1/level2
- [dynamicSlug].js // will match for /level1/level2/1234
Or
pages/
level1/
[dynamicSlug]/
- index.js // will match for /level1/1234
level2/
- index.js // will match for /level1/level2
[dynamicSlug]/
- index.js // will match for /level1/level2/1234
You have 2 choices:
Using v9 Dynamic Routing by calling the folder as [dynSlag] and putting your page file inside.
Using custom server and routing, you will need to define a custom server, map your path to a specific next page.
I know this is a bit of an old post, but I'd just like to share my working response with NextJS v11.
I want dynamic routing at two levels. E.g.:
{siteroot}/dynamicPage
{siteroot}/dynamicUrlSection/dynamicPage
My folder structure is:
/pages/[section]/[page].tsx
/pages/[section]/index.tsx
This way, the "dynamicPage" path at the root is handled by index.tsx, and nested routes are handled by [page].tsx
BONUS INFO: I am working with Contentful as a CMS. I use a single content model for all the pages at both levels.
The model has "section" and "page" properties.
The entries that serve the root dynamic pages (i.e. /pages/[section]/index) have a compound value in the "page" property of {section}-index. I then have to be a bit smart in my client code:
if (!page) {
page = `${section}-index`;
}
await fetchData(section, page);
Using the example right from the NextJs documentation, I use this hack, maybe you could use it.
<Link href="/posts/[id]" as={`/posts/${subFolder}${id}`}>
"as" will have a value like /posts/nested_subfolder_file.md
And in the getPostData function, just do this little change:
const nestedPaths = id.split('_')
const fileName = `${nestedPaths.pop()}.md`
const fullPath = path.join(postsDirectory, ...nestedPaths, fileName)
Is there a way to pre-generate the HTML structure of a (single route) React application directly in the HTML entry point?
Then the page will be able to display HTML (based on React initial state) before any JS is loaded.
I'm actually using webpack-html-loader but any other loader or plugin is welcome ;)
PS: May static-site-generator-webpack-plugin be of any help?
PS: I'm not using React Router
If you want to use static-site-generator-webpack-plugin you first need to build a bundle with webpack bundle.js that exports a render function that takes following arguments.
locals an object with various page metadata e.g. title that go into component parameters (traditionally thought of as template variables).
callback a nodejs style (err, result) callback that you will call with your rendered html as the value for result
e.g.
// entry.js, compiled to bundle.js by webpack
module.exports = function render(locals, callback) {
callback(null,
'<html>' + locals.greet + ' from ' + locals.path + '</html>');
};
It is in this function that you will instantiate your components (possibly via React Router if you want) and render them with ReactDOMServer.renderToString().
You will then specify the compiled bundle.js as bundle in your instantiation of StaticSiteGeneratorPlugin as well as your concrete routes in paths and in locals an object containing the above mentioned metadata values.
var paths, locals; // compute paths from metadata files or frontmatter
module.exports = {
entry: {
bundle: './entry.js' // build bundle.js from entry.js source
},
...,
plugins: [
new StaticSiteGeneratorPlugin('bundle', paths, locals)
]
}
The keys you specify for locals in webpack.config.js in will be present in the locals parameter of every call to render(locals, callback). They will be merged with path, assets and webpackStats keys provided by the plugin.
If you want to load javascript code into your pages after rendering you could compile an additional page.js entry to your webpack config that calls ReactDOM.render() in the typical manner and then load that bundle in a script tag emitted by in your render(locals, callback) function in your bundle.js (above). Ensure that page.js mounts components to the same location in the DOM as they are when rendered by entry.js (you will probably set an id attribute on the parent element). You will also need to ensure that any location (i.e. route path) dependent variables align in both environments.
Check out the source code of Gatsby which also uses this plugin. You can also have a look at the source code for Phenomic for an alternative approach.
You should try server side rendering, it will let react render the first view of your app in a backend and deliver a static HTML. This boilerplate already comes with server rendering set up and you can learn more about it here
Jekyll is great static site generator which can be extended with custom ruby plugins. You need to enable WebPack to make Jekyll calls. See Plugging Webpack to Jekyll Powered Pages
Here you have a working example https://github.com/aganglada/preact-minimal/blob/master/config/webpack.config.js, if you like you can fork it and take a look at how this work all together.
Hope it helps :)