Does anybody know what is the exportPathMap: (next.config.js) for NextJS of a path that has a :pid?
My expotPathMap
exportPathMap: async (defaultPathMap) => {
return {
'/': { page: '/', query: {} },
'/login': { page: '/login', query: { verifySuccess: null } },
'/signup': { page: '/signup', query: {} },
'/search': { page: '/search', query: { s: '', category: '' } },
'/messages': { page: '/messages', query: { t: '' } },
'/messages/:pid': { page: '/messages/:pid', query: { t: '' } },
Issue is that I was tasked to create a page that would look like
/messages/925255252
instead of a page that uses a query param like /message?id=9252552252&t=foo
Now when building & exporting I am getting this error
Cannot find module for page: /messages/:pid
The files.
pages > messages > index.js (/messages), [pid].js (messages/:id)
PS.
Not using SSR, rendering is client sided!
PPS.
All is fine on localhost, needs to work in production.
What you are trying to achieve is not possible, from the spectrum chat of next.js :
You have to return a mapping of every possible route, dynamic matching
wouldn't have any effect even if we did support it, how would you know
what /show/:id is going to be when exporting? We have to know exactly
what is going to be exported at export time
So you have to generate all possibile pages (in your case you need all possible messages ids), example fetching your database.
Or switch to SSR and handle your requests server side.
Related
So, you know when you access a view with django rest api on the browser, you get an html page, and when you send something like an ajax request, you get the json? I'm trying to figure out how to mess with the proxy setting for vite, but I can't find a single decent documentation around it. I want to redirect '/' to 'http://localhost:8000/api', but there's really weird behavior going on.
If I have a route on localhost:8000/api, I can do:
//vite.config.js
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
//Focus here
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
rewrite: (path) => { console.log(path); return path.replace('/^\/api/', '') }
}
}
}
})
//todo-component.vue
export default {
data() {
return {
todos: []
}
},
components: {
TodoElement
},
beforeCreate() {
//Focus here as well
this.axios.get('/api').then((response) => {
this.todos = response.data
})
.catch((e) => {
console.error(e)
})
}
}
This will return the json response as expected. However, if I try to make it so that '/' routes to 'localhost:8000/api/', like this:
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
//change here
'/': {
target: 'http://localhost:8000/api',
changeOrigin: true,
rewrite: (path) => { console.log(path); return path.replace('/^\/api/', '') }
}
}
}
})
import TodoElement from "./todo-element.vue"
export default {
data() {
return {
todos: []
}
},
components: {
TodoElement
},
beforeCreate() {
//change here
this.axios.get('/').then((response) => {
this.todos = response.data
})
.catch((e) => {
console.error(e)
})
}
}
It just spews out the html version of the api view, but with no styling, with a bunch of errors
No idea what to do. If someone could explain how this proxy works, i'd really love it. I don't want to keep writing "api/", and it'd be really valuable if I can manage to understand how this works.
You are a bit confusing things and I will try to show you why.
If you redirect root path / to /api, every request sent to your app running at http://localhost:3000 will be forwarded to http://localhost:8000/api. It mean that you will not be able to serve anything from the running app, but you will get an answer from the configured endpoint (localhost:8000/api) for every request.
To understand easily what is going on, keep in mind that this vite config option (server.proxy) act like a reverse proxy. As example, I take the favicon.ico resource of your app.
With your current configuration, when from your browser you try to access your app, the /favicon.ico (and all other resources) is then loaded from http://localhost:8000/api/favicon.ico and not anymore from your app running at http://localhost:3000/favicon.ico.
This explain all the errors in the console. Again, for example, /static/rest_framework is loaded from http://localhost:8000/api/ and not http://localhost:3000/.
The documentation is quite clear, it's just a matter of understanding what a http-proxy is. To get more information you can head to https://github.com/http-party/node-http-proxy#core-concept
I'm new to Vue / web development, ever since I started i've had a good amount of fun but now i'm stuck.
Currently I am creating an admin dashboard with Firebase authentication. Everything seems to work like it should but there is one thing that I still don't understand.
In the Vue Router I have all the different routes set up and the dashboard is inaccessible (if not logged in to Firebase).
This is my Router Guard:
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/register",
name: "Register",
component: Register,
},
{
path: "/login",
name: "Login",
component: Login,
},
{
path: "/dashboard",
name: "Dashboard",
component: Dashboard,
meta: {
requiresAuth: true,
},
},
];
router.beforeEach((to) => {
//If route requires authentication
if (to.matched.some((rec) => rec.meta.requiresAuth)) {
//Check firebase user
auth.onAuthStateChanged((user) => {
console.log(user);
//If the user object does not exist then redirect to the /Login page
if (!user) {
router.push("/login");
}
});
}
});
If I now try to open localhost:8080/dashboard it shows the dashboard for a split second and then hops to the /login page.
If also tried it with next({name: 'Login'}) but for some reason I keep getting white pages when I use next().
Hope someone can help me.
Thanks :)
The problem is that instead of checking for a logged-in user you are adding an "event listener" auth.onAuthStateChanged.. it fires async when the authentication state changes. However you need a sync check here. The best would be to use vuex and store your user in a global state. Though if you don't use vuex at all and you need your user only here, then probably a "local" user var in the router would also work.. something like this:
let user = null
auth.onAuthStateChanged(u => {
console.log(u)
if (u) {
user = u
} else {
user = null
}
})
router.beforeEach(to => {
if (to.matched.some(rec => rec.meta.requiresAuth)) {
//Check firebase user
if (!user) {
router.push("/login");
}
}
})
It's just a concept, but it should work.. let me know :)
I have been looking for ways to find a way to make a single page application with vanilla javascript only but sadly I could not find one.
I found this code in a tutorial on how to make a SPAs, however the issue is location.pathname returns not the URL path but the file path instead with Electron. This bit of code is integral to make the routing work. And I don't wanna use any frameworks.
const router = async () => {
const routes = [
{ path: "/", view: console.log("Viewing /") },
{ path: "/login", view: console.log("Viewing login") },
{ path: "/dashboard", view: console.log("Viewing dashboard") },
];
const potentialMatches = routes.map((route) => {
return {
route: route,
isMatch: location.pathname === route.path,
};
});
};
window.addEventListener("load", () => {
router();
});
Is there a way I could retrieve the URL path and inject it to my index.js?
Code: http://github.com/dbots-co/website
Directly connecting to a dynamic route (dashboard, bot page), seems to not work. However, directly connecting to docs does work.
This only happens when using Angular 10 Universal SSR.
Not Working: https://dbots.co/bots/774811448576573480
Working: https://dbots.co/docs/get-started
bot-page.component.ts:
async ngOnInit() {
await this.service.init();
this.user = this.service.getBot(this.id);
this.bot = this.service.getSavedBot(this.id);
if (!this.user || !this.bot)
return this.router.navigate(['']);
this.seo.setTags({
description: this.bot.listing.overview,
titlePrefix: this.user.username,
titleSuffix: 'DBots',
url: `bots/${this.id}`
});
this.analytics.botPageView({ botId: this.user.id });
this.themeService.setNavbarBackground('var(--background-secondary)');
document
.querySelector('.navbar')
.setAttribute('style', `margin-bottom: -5px;`);
}
app-routing.module.ts:
const routes: Routes = [
...
{ path: 'bots/:id', component: BotPageComponent },
...
];
I am using apollo with next and recently I noticed that custom routes breaks SSR. Usually if you navigate through pages apollo caches the query and when you are on the page the next time, it serves everything from cache. However with custom routes, the cache is never used.
I also noticed that when I click on these pages, an error flashes in the console. But it goes away very fast and I wasn't able to copy it here.
Server.js
//
server.get('/about-us', (req, res) => app.render(req, res, '/about'));
server.get('/about', (req, res) => res.redirect(301, '/about-us'));
Menu Click Handler
const navigate = link => () => {
Router.push(link);
};
Menu Items
export const menu = [
{
name: 'Home',
url: '/',
},
{
name: 'Catalogs',
url: '/catalogs',
},
{
name: 'Shop',
url: '/shop',
},
{
name: 'Wholesale',
url: '/wholesale',
},
{
name: 'About Us',
url: '/about-us',
prefetch: true,
},
{
name: 'Contact Us',
url: '/contact-us',
prefetch: true,
},
];
Based on a suggestion from nextjs spectrum I tried prefetching custom pages in the TopNav Component but it didn't work.
const prefetch = url => {
if (process.browser) {
console.log('prefetching these urls', url);
Router.prefetch(url);
}
};
useEffect(() => {
menu.forEach(menuItem => {
if (menuItem.prefetch) {
prefetch(menuItem.url);
}
});
}, []);
I was able to figure out the problem. This is not really well documented but you need to prefetch the component. So for my case instead of prefetching /about-us I should have prefetched /about.
That's why there is as prop in the link component. Nextjs 9 just got released which fixes this issue.
https://nextjs.org/blog/next-9#dynamic-route-segments
For nextjs 9 you can save your file as [pid].js and it will catch all paths in a specific route. i.e for /products/test-product you have to create folder products and inside that add [pid].js.
I needed to query for product based on slug so I added this and voila, I have access to the slug inside my component.
Product.getInitialProps = async ({ query }) => {
return { slug: query.pid };
};
These issues were pretty frustrating before next 9 but it's heavily simplified and it helped me fully remove server.js.