I'm having a problem with Nuxt 2 (v2.15) and server side rendering mode. I want to create an universal project that can be used as basis for other projects. Therefore, I have separated all of the logic and settings in 2 parts - core part and site-specific. I want to split settings that should be used in nuxt.config.js also so there are core settings that are used always and site specific settings that should be coded specifically for the site.
Idea is to create spearate files that will hold specific parts of core settings that would be imported into the nuxt.config.js and then merged with site specific parts that should be writen directly in nuxt.config.js.
The problem I have is that when I use import statement to import core settings (in the beginning of the nuxt.config.js) that will be then added in the Nuxt settings object everything works fine when I'm making the first request and everything renders on the server. When I want to navigate to some other page after hydration, application depends on server middleware that handles headless API and it simply doesn't work anymore. Call that should be handled by server middleware hangs. The moment I return those settings directly written into the Nuxt config object and not imported, everything works fine.
lets say, if I have something like this:
nuxt.config.js:
export default {
...
serverMiddleware: [
{
'path': '/headless',
'handler': '~/core/server-middleware/headless.js'
},
]
...
everything works fine.
If I have server-middleware.js file that I import into nuxt.config.js it works only on server side and not on client side.
server-middleware.js:
export default [
{
'path': '/headless',
'handler': '~/core/server-middleware/headless.js'
},
];
nuxt.config.js:
import serverMiddleware from 'path/to/server-middleware.js';
export default {
...
serverMiddleware: serverMiddleware
...
This works only on the server side. When page renders and get hydrated on the client side, every request to the address that begins with /headless simply hangs until promise fails. It never enters the server middleware code.
The only difference is that in second example I import JSON with middlewares config instead of simply putting that JSON directly in nuxt.config.js.
Thanks in advance,
Goran
Related
I'm using Vue Router with Vue 3 in a web application I'm working on, and have a 'catch all' route defined as the last route:
{
path: "/:catchAll(.*)*",
component: () => import("pages/Error404.vue")
},
This is picking up everything, though, including calls to the /api/ back end (although not via Ajax), and even things like '/test.csv', which is a link to a CSV file in the root directory.
How can I bypass the router for certain URLs, allowing them to be treated as regular requests?
Incidentally, I don't know whether this is relevant, but the application in question is a PWA built using Quasar. When I make the call to e.g '/test.csv', I see a request for 'service-worker.js' with a 304 response code in my nginx access log, confirming that the request is being handled by the router rather than nginx.
I have files that are not stored in a CDN and would like to serve them with Next.js. These files are not intended to be integrated into Next.js and should not be placed in the public folder. More files will be added and I want to avoid using a custom Next.js server to do simple file serving for images that are not available during building. Additionally, this application will only be deployed locally and using a CDN is overkill for this situation.
Currently, I use Express.js and a Next.js custom server to use express.static to serve files, but this ends up slowing down Next.js and adds lots of unnecessary complexity to my stack. I'd rather just use the Next.js CLI to run my app instead of reinventing the wheel.
Is there a simple way I can serve static files within Next.js and outside the public directory?
I posted this question and my own answer here on StackOverflow because I was unable to find a good tutorial on how to do this. Nearly every google search says to use a custom server or to just put your files in the public folder, which is not what I was looking for. Hopefully, others who are looking for the same thing may find it here.
Disclaimer: I do not use Vercel to publish my applications, and I do not know if this answer will be applicable to Next.js on Vercel.
Next.js allows API routes to be customized to support Node.js HTTP handlers, which means express can also be used within Next.js API routes.
Here is some code to utilize express.static on a Next.js API route.
// pages/api/images/[name].js
// Tell Next.js to pass in Node.js HTTP
export const config = {
api: { externalResolver: true }
}
import express from 'express';
const handler = express();
const serveFiles = express.static('./path/to/files');
handler.use(['/api/images', '/images'], serveFiles);
// ^ ^
// Multiple endpoints are passed. The first one is used when visiting /api/images.
// The second one is used when visiting /images using the middleware rewrite I mention below.
// express is just a function that takes (http.IncomingMessage, http.ServerResponse),
// which Next.js supports when externalResolver is enabled.
export default handler;
However to get around visiting this endpoint via /api/images/filename, you can use Next.js's new middleware to rewrite the request!
// pages/images/_middleware.js
import { NextResponse } from 'next/server';
export function middleware(req) {
// Rewrite /images/... to /api/images/...
return NextResponse.rewrite('/api' + req.nextUrl.pathname);
}
With both these in use, visiting /images/photo.png will internally rewrite to /api/images/photo.png and in turn be handled by express.static, allowing you to serve files outside an API route and without using a custom server!
This code can surely be simplified and get rid of the need of initializing a express.js app just to handle a request, but its incredibly simple to integrate express.js into next.js without using a custom server!
I posted this question and my own answer here on StackOverflow because I was unable to find a good tutorial on how to do this. Nearly every google search says to use a custom server or to just put your files in the public folder, which is not what I was looking for. Hopefully, others who are looking for the same thing may find it here.
The public folder can only serve those files that were included at build time.
But we can do some workaround that can serve files that were not included at build time.
Solution starts here
We can create an api endpoint. For example /api/images-endpoint/[...slug].js
import fs from "fs";
import path from "path";
export default function handler(req, res) {
const imagePath = req.query.slug.join("/");
const filePath = path.resolve(".", `images-directory/${imagePath}`);
const imageBuffer = fs.readFileSync(filePath);
res.setHeader("Content-Type", "image/jpg");
return res.send(imageBuffer);
}
By this, our endpoint will read the image from the image directory and send it as a response.
Benifit/Note: This solution works for images that were added after Next project is build i-e npm run build or next build
Drawback: Using this, We can not build optimized images in Next JS Image component i-e next/image
I'm trying to return data as JSON from the express server for a route. The data returns fine but when i open the NUXT page on the browser than the JSON data gets outputted instead of the page HTML.
Note the express route is the same as the page route. I know the routes are conflicting with each other. Do i need to have the server and front-end on different ports? Is there anything wrong i'm doing here?
Thanks
To avoid conflicts such as that you should use a prefix like /api/ or /api/v1/ something like that
In nuxt.config.js you need to define your server middleware
serverMiddleware: ["~/api/index.js"]
That file is your server. At the bottom you need to export it like this:
module.exports = {
path: "/api",
handler: app
}
Note here: app is your express app if you use express.js.
This here: const app = express();
If everything worked your root of your API should be available under host:port/api/
you cant do this if the routes for backend and frontend exactly same. this is route rules that they have to be unique and its not backend or frontend issue for e.x. you can have two routes with same url in express(api), nuxt too.
if we say the application for example is post office, the route are path to a house address (controller or action) so we can have two path to get the a house but its confusion have a same path(url or route) and different houses.
simple solutions:
as you said make the api and front separate with different ports or different domains or even have a prefix for your express routes
in express handle all of them, means return view or page with data needed instead of json data
I created a website with several pages on Vue.js.
Everything is working fine locally, but when I deploy to Heroku, all pages are only working when I click on an internal link in my menu that redirects to the corresponding page (using router push).
When I try to access directly /any-page from the browser I get a 404 with a message saying "Cannot GET /any-page" whereas the same page is displayed correctly via a click on a link.
As I mentioned when I locally serve my app I don't have this problem.
I really can't see where this can come from, thanks in advance for your help.
There's a deployment guide specifically for Heroku in the official Vue CLI documentation.
You'll quickly notice the relevant information:
static.json
{
"root": "dist",
"clean_urls": true,
"routes": {
"/**": "index.html"
}
}
For SPA's (Single Page Applications), you'll want to point every route to the index. Vue router will take care of navigating to the proper page.
Heroku is serving the contents of your Vue build folder. Since Vue builds the app as a single index.html file, only the main route works.
Vue doesn't actually navigate to the route, it rather rewrites the the browser url using the history API and handles the loading of the new route.
You could use one of these options:
OPTION 1
You could use mode: "hash" to fix routes when reloading the page. However this will add a # before every route.
const router = new VueRouter({
mode: "hash",
routes: [...]
})
OPTION 2
Write an Node.JS (eg Express) app that routes every request to your index.html file. This is called a middleware
Reference: https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations
I deployed my site on AWS using nuxt generate with dynamic route. There is no problem on the pages. Now I want to add new route without the whole deployment process.
Here's an example:
/post/1
/post/2
/post/3
------- already deployed and works fine ------
/post/4 <- want to add after deployment
I manually upload generated index.html on S3 so I can access the file like /post/4/index.html but if I tried to /post/4 it shows a page that is created with /post/_id.vue.
I think routing is not updated. ( I do not know what is the routing rule on /dist folder )
Is there any way upload new dynamic route without the whole deployment process?
I think you need to generate each page before deploy. By default, dynamic routes are ignored by the generate command.
Go to nuxt.config.js and find generate key. This is simple example for generate specific site.
export default {
...
generate: {
routes: [
'/post/1',
'/post/2',
'/post/3',
'/post/4'
]
}
}
If you need to generate dynamic routes programmaticaly, you need to write a function.
Check the docs for more information: https://nuxtjs.org/api/configuration-generate/
And lastly, simple example:
import BlogService from './services/BlogService.js'
...
export default {
...
generate: {
routes: () => {
return BlogService.getPosts().then(response => {
return response.data.map(post => {
return '/post/' + post.id
})
})
}
}
}
There is a mistake on publish.
amplify publish // it publish vue application. it means that the target is SPA not Static page webiste
I deployed the files on S3 and it works fine.
I tried regarding to below site. I also failed.
https://aws.amazon.com/ko/blogs/mobile/deploy-files-s3-dropbox-amplify-console/
I want to use amplify with nuxt generate together.
Wrong question, there are no right answer anyway.