Next.js version: 8
Now version: 2
As a user, this problem occurs when I'm using next/link
to navigate to a page that is using .getInitialProps
, in which data is being fetched from a Now deployment URL. To get the absolute URL for my data fetch and SSR, I check req.headers.host
, which is fine for SSR. However, next/link
makes, .getInitialProps
run in the client, so there is no req
object and I have to check window.location.hostname
instead.
This makes getting the absolute URL for my Now deployment look a bit messy, and I think this could be handled by the framework rather than the user. It looks like this:
Page.getInitialProps = async ({ req }) => {
let protocol = 'https:'
let host = req ? req.headers.host : window.location.hostname
if (host.indexOf('localhost') > -1) {
protocol = 'http:'
}
const jobs = await (
await fetch(`${protocol}//${host}/api/allJobs.js`)
).json()
return {
jobs
}
}
An additional origin
prop passed to .getInitialProps
which contains the protocol + hostname, regardless if on the server or client:
Page.getInitialProps = async ({ origin }) => {
const job = await (
await fetch(`${origin}/api/job.js`)
).json()
return {
jobs
}
}
My current solution is to an additional function to check if req
is an object, and if not, get the hostname from window.location.hostname
, which looks like this:
import absoluteUrl from 'next-absolute-url'
Page.getInitialProps = ({ req }) => {
const { protocol, host } = absoluteUrl(req)
const apiURL = `${protocol}//${host}`
}
Where next-absolute-url
is a function that does this:
function absoluteUrl (req, setLocalhost) {
var protocol = 'https:'
var host = req ? req.headers.host : window.location.hostname
if (host.indexOf('localhost') > -1) {
if (setLocalhost) host = setLocalhost
protocol = 'http:'
}
return {
protocol: protocol,
host: host
}
}
module.exports = absoluteUrl
I don't think we should make the Javascript bundle bigger by introducing this feature when it can be handled as-needed in userland 馃
Gotchya, there's probably a nicer way to handle this in userland than what I'm doing right now. I'll put some more thought into it. I wonder if _app.js is a better place to handle passing the URL down to getInitialProps
Sure, you would be able to do that in _app.js
Cool! I'll try that out in the future. Thanks @timneutkens !
Closing the thread as I don't think it needs to stay open.
:100: 馃檹 Thanks for understanding!
@jekrb Did you ever figure out a nicer way to handle?
Hey @scottie-schneider :wave:
I'm not sure if getting the URL origin was ever implemented since closing the issue and I've just been using my userland module, next-absolute-url, and it seems to work enough for me to not look much farther.
Here is an example of how I've used it recently:
Page.getInitialProps = async ({ req, query }) => {
const { protocol, host } = absoluteUrl(req)
const yelp = `${protocol}//${host}/api/yelp.js`
const body = JSON.stringify({
search: query.pid.replace(/-/g, ' ')
})
const payload = await fetch(yelp, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body
})
const data = await payload.json()
return data
}
I do use this module in every Next.js project now, I'm curious about how others handle getting the URL origin.
Additionally, I should probably update (or accept a PR) to make next-absolute-url also return the origin so the weird ${protocol}//${host}/api/job.js
string interpolation thing I documented could instead be ${origin}/api/job.js
.
@jekrb , I really can't thank you enough. Your module has enabled me to breakthrough after a few frustrating hours of trying to get the baseURL nicely in Next.js. Thank you!
Just a note for those who are coming from google, the @jekrb's answer is right but the host
is renamed to hostname
Here is what location has i nit locally for me:
host: "localhost:3000"
hostname: "localhost"
So I needed to use this in the absoluteUrl function:
var host = req ? req.headers.host : window.location.host
Otherwise I don't get the port number in the api url.
I was getting:
http://localhost/api/dbtest
instead of
http://localhost:3000/api/dbtest
@stokescomp what version of next-absolute-url are you using?
I recently merged a pull request that rewrote everything in typescript and added tests. If you haven't yet, an upgrade might help fix the error that you're running into. If you're on the latest version, feel free to open an issue on the project repo and I'll see if I can help!
I was copying an old version of your function. Now I added import absoluteUrl from "next-absolute-url"; and added the npm module to package.json and it works great now. I love your improvements to it. Thanks for sharing!
And it works perfectly with no errors.
absoluteUrl from "next-absolute-url"; would not wotk, if you are accessing with loopback(127.0.0.1) or with local ips. i rather prefer to check wether my environment is development or production. If it is development use "http", otherwise i use "https"
@manan5439 there are a couple issues open about that:
https://github.com/jekrb/next-absolute-url/issues/12
https://github.com/jekrb/next-absolute-url/issues/14
I don't currently have the time to work on an update, but would be more than happy to accept a pull request 馃憤
Most helpful comment
Hey @scottie-schneider :wave:
I'm not sure if getting the URL origin was ever implemented since closing the issue and I've just been using my userland module, next-absolute-url, and it seems to work enough for me to not look much farther.
Here is an example of how I've used it recently:
I do use this module in every Next.js project now, I'm curious about how others handle getting the URL origin.
Additionally, I should probably update (or accept a PR) to make next-absolute-url also return the origin so the weird
${protocol}//${host}/api/job.js
string interpolation thing I documented could instead be${origin}/api/job.js
.