I've just released my nextjs app to production using Vercel.
I'm loving the whole experience except for one tiny part: I would have loved to be able to put my app in maintenance mode, but this option does not seem available on Vercel.
My question is: Has anyone achieved this before and could share some details here?
I'm guessing it could be done at 2 levels:
Modifying my app so that if an environment variable (i.e MAINTENANCE_MODE=true) is detected, every page redirects to a maintenance screen. However, this is not ideal, because adding an environment variable on Vercel requires a deployment for it to be taken into account.
Having a simple per-project toggle to enable/disable maintenance mode from Vercel. That would be mind-blowing.
"Maintenance Mode" can be achieved with an Environment Variable and redirects property in your next.config.js (requires Next.js 9.5.0 or newer).
module.exports = {
redirects() {
return [
process.env.MAINTENANCE_MODE === "1"
? { source: "/((?!maintenance).*)", destination: "/maintenance.html", permanent: false }
: null,
].filter(Boolean);
}
};
This adds a wildcard route that matches incoming requests and then issues a temporary redirect the /maintenance.html location.
Note that you cannot make changes to a deployment (config or environment variables) without deploying again.
Old Answer
If you're not using Next.js or using an old version of Next.js, "Maintenance Mode" can be achieved with the redirects property in vercel.json.
{
"redirects": [
{ "source": "/((?!maintenance).*)", "destination": "/maintenance.html", "permanent": false }
]
}
A different solution I am currently using would be to create a separate maintenance page and then conditionally intercept the rendering of the actual component based on an environment variable.
I achieve this by adjusting the _app.js code to:
function MyApp({ Component, pageProps }) {
if (process.env.NEXT_PUBLIC_MAINTENANCE_MODE === 'false') {
return <Component {...pageProps} />
} else {
return <Maintenance />
}
Note that as mentioned in earlier answers, this relies on the Vercel env variables, per their website: "A new Deployment is required for your changes to take effect."
To add on to comment by #ptrkcsk, if you are going the route of putting a maintenance page in pages directory and are rendering images with the <Image> component from next/image you will also want to include your static folder to the redirects regex.
This is the source pattern that is working for me: /((?!maintenance)(?!_next)(?!static).*)
Related
middleware.ts
export { default } from 'next-auth/middleware';
export const config = { matcher: ['/my/:path*'] };
https://next-auth.js.org/configuration/nextjs#middleware
now im using like this, but code is not working
I hope middleware works when accessing pages related to 'my'.
how can i fix it?
"next": "^12.0.8",
"next-auth": "^4.10.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
this is my packages version
I think the issue might be the way in which you are creating the middleware file, since everything else looks good to me.
Since Next.js 12.2, now you have to create a single middleware.ts file in your root directory (same level as pages folder). But on earlier versions like the one you are using, you need to create a _middleware.ts (notice the underscore) file inside your pages folder.
Reference: https://nextjs.org/docs/messages/middleware-upgrade-guide#breaking-changes
I created the middleware but somehow on the page it can detect if it is signed in but after redirecting to the page middleware thought I didn't signin which is bizarre, looks like server side middleware uses different session than frontend stuff
I am proxying part of my site to a 'new' nextjs page, as such all my assets, images etc... are messing up because the pathing is wrong.
So, I used "assetPrefix" for the css/js files, BUT all my images and api's are wrong, so I am trying to do a rewrite and its not working...
Is there a way to have next be able to ignore the host (that is proxing) and just use its own domain.. for instance, all the assets are: https://preview.mysite.com (current site), but I want it to use its "real domain" -- https://previewnext.mysite.com
async rewrites() {
return [
{
source: 'https://preview.mysite.com/_next/image*',
destination: 'https://previewnext.mysite.com/_next/image*'
},
basically, if the path is: https://preview.mysite.com/_next/image?, which is my current domain that proxies the nextjs site, SO I need the nextjs site to actually rewrite those image assets to: https://previewnext.mysite.com/_next/image*
Seems a huge limitation to not be able to use absolute paths for rewrites.
I'm looking to build a static Next.js Single Page App that has dynamic routes, for example: /posts/123. I'd like to do this to:
Be able to host the site anywhere (e.g. S3)
Not need to know the routes at build time (so our APIs can change whenever independently of the Frontend/without requiring a rebuild of the Frontend)
From what I can tell, this should work with:
next build && next export
fallback: true
But the docs suggest that's only for loading/intermediate states.
Can I use some combination of fallback pages/catchall dynamic routes/static generation to get a static single-page app with dynamic routes at runtime? I'm okay with faking the routes using nginx (e.g. /posts/123 -> /index.html).
Edit: the above paragraph doesn't seem possible. From the docs, when using a required catchall route, e.g. [...post].js):
fallback: true is not supported when using next export.
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.sendFile('main.html', { root : __dirname})
});
app.listen(9000, function(){
console.log('Listening on port 9000');
});
This current block of code works fine. Express is required and assigned to the variable app.
A HTML file is then sent (from the same directory) using res.sendFile as part of the app.get method.
Within the HTML file I am referencing a css file in the same directory, yet nothing is happening.
<link rel='stylesheet' type='text/css' href='mainstyle.css'>
How am I able to send the CSS file to the browser for use? res.sendFile does not work.
Thanks.
You need to define a static files directory. Create a folder called public and then include this line:
app.use(express.static('public'));
Don't include public in the file path when you include the css file though. All of your static files can go in that folder. Or, better still, create sub-folders for styles, images, fonts etc.
You can read more about it here: https://expressjs.com/en/starter/static-files.html
I think the problem you're having is that you're trying to create a web application from scratch using Express without any of the surrounding functionality. Your app sends a file when you navigate to the URL. It does not listen for specific requests for files and respond to them, it does not handle missing files, server errors etc.
You could do all that from scratch but in fact Express have created an application generator which creates a skeleton app for you with the web server, public folder, routes etc. It's called Express Generator and you can find it here: https://expressjs.com/en/starter/generator.html
That's a brilliant starting point for an MVC application. You get the package.json file for additional node modules, a template engine called Jade (although I prefer Hogan) for dynamic content and once it's created your app, you can fire it up by typing "npm start" in a console window.
try this
var express = require('express');
var app = express();
app.get('/', function(req, res) {
if(req.url == "/" || req.url == "/main.html"){
res.sendFile('/main.html', { root : __dirname})
}else if(req.url == "/mainstyle.css"){
res.sendFile('mainstyle.css', { root : __dirname})
}
});
app.listen(9000, function(){
console.log('Listening on port 9000');
});
I'm now aware of what was going wrong.
From the instance I started, I was experimenting with different code. The browser than created cache based on the incorrect code my server was providing, so no matter what I changed, the browser was reffering to it's cache to load, in this case, erroneous code.
For everyone who may be experiancing with similar issues when entering the correct code, clear cache history or use a incognito/private browser for developing.
I am using Meteor 1.0.2.1 and iron:router 1.0.7. I have managed to set up a route for '/' which works fine locally however when I deploy on meteor I get the iron:router splash.
Here is my route:
Router.route('/', {name: 'landing.index'});
and I have a controller called LandingIndex and a template called LandingIndex as well.
Any help is greatly appreciated.
edit:
The controllers looks as follows:
LandingIndexController = RouteController.extend({
waitOn: function () {
},
data: function () {
},
action: function () {
this.render();
}
});
In my case I had duplicate templates. A quick look at the console pointed out the problem.
Are you by any chance using Twitter Bootstrap? I ran into this same problem today, non-reproducible on localhost as well. After way too many hours of trying to reproduce this on a remote env with meteor deploy xxxxx.meteor.com, I figured out that it was because of a file contained within Twitter Bootstrap. If you straight up download the .zip file of bootstrap and indiscriminately copy its 3 directories into your project (css/ fonts/ js/), js/npm.js will be copied along with it.
I think js/npm.js is only needed during the build process with Grunt, so I just deleted it. It solved the issue for me, although I'm not sure why...
For me the problem was some files that came from another branch and stayed "untracked" in Git, so I overlook them.
But it looks like mup deploys everything, so it deployed this incorrect files too. In addition to that, Iron Router must be catching exceptions from other stuff, so it showed its splash page.
Just removed the untracked files and the problem was solved with another deploy!