In head.tsx (I am using AppDir) of each page of my site, I pass canonicalPath (among others) to a server component that renders all <meta> tags.
I want to make a simple development only validation that the canonicalPath supplied is actually the same as the actual current path in the browser and throw an Error if it isn't. I cannot figure out how to do this:
Serverside, the only thing I found is headers() which for some reason contains the hostname but not the path. And besides, it's a dynamic function and will force dynamic rendering.
So I created a client component:
"use client";
import { usePathname } from "next/navigation";
import { LayoutHeadProps } from "./layout-head";
export default function LayoutHeadClient(props: LayoutHeadProps): React.ReactNode {
const path = usePathname();
if (process.env.NODE_ENV === "development") {
if (props.canonicalPath !== path) {
throw new Error(`Actual path does not correspond to canonical path: "${path}" != "${props.canonicalPath}"`);
}
}
return <></>;
}
But this does not work either:
Warning: Cannot update a component (`HotReload`) while rendering a different component (`LayoutHeadClient`). To locate the bad setState() call inside `LayoutHeadClient`
and then it throws the Error because at the time it is evaluated, canonicalPath still evaluates to the previous page. When I later look it up in the source code, it is correct.
Related
So far I have been using the following to execute a request against the Graph API.
import { MSGraphClient } from '#microsoft/sp-http';
const graphClient: MSGraphClient = await context.msGraphClientFactory.getClient();
const uriGetAccessPackageAssignmentRequests = `/identityGovernance/entitlementManagement/accessPackageAssignments/filterByCurrentUser(on='target')?$select=id&$expand=accessPackageAssignmentResourceRoles&$filter=assignmentState ne 'Expired'`;
graphClient.api(uriGetAccessPackageAssignmentRequests).version('beta').get();
This has been working without any problems until I decided to change to #pnp/graph in the newest version (3.4.1).
I can use all the preset calls, but I cannot find a way to execute a generic graph call with a custom endpoint.
In all the tutorials they talk about
import { graph } from "#pnp/graph";
But if I do so, I get the following error -> Module '"#pnp/graph"' has no exported member 'graph'.
As I said, the described way in the documentation of using
import { graphfi, GraphFI, SPFx as graphSPFx } from '#pnp/graph'
export const getGraph = (context?: WebPartContext): GraphFI => {
if (_graph === null && context != null) {
//You must add the #pnp/logging package to include the PnPLogging behavior it is no longer a peer dependency
// The LogLevel set's at what level a message will be written to the console
_graph = graphfi().using(graphSPFx(context)).using(PnPLogging(LogLevel.Warning))
}
return _graph
}
is working fine.
I just cannot find anything on how to do a custom endpoint (like the one above) with pnp v3.
Can anyone help here or do I have to stick to the MSGraphClient for that purpose?
Hello and thank you for your help.
Sadly support over at CF does not think they need to help me.
I am learning to use workers, and have written a simple HTML injector just to see it working on my site.
this is the full worker code i have:
async function handleRequest(req) {
const res = await fetch(req)
const contentType = res.headers.get("Content-Type")
console.log('contentType: ', contentType)
// If the response is HTML, it can be transformed with
// HTMLRewriter -- otherwise, it should pass through
if (contentType.startsWith("text/html")) {
return rewriter.transform(res)
} else {
return res
}
}
class UserElementHandler {
async element(element) {
element.before("<div class='contbox'><img src='https://coverme.co.il/wp-content/uploads/2020/01/covermeLOGO-01-1024x183.png' style='width:200px;margin:20px;'><h1>testing inserting</h1></div>", {html: true});
// fill in user info using response
}
}
const rewriter = new HTMLRewriter()
.on("h1", new UserElementHandler())
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
it just uses element.before to inject some HTML.
in the worker preview pane i can see it!
but on the live site = nothing.
this is the active URL: [https://coverme.co.il/product/%D7%A0%D7%A8-%D7%91%D7%99%D7%A0%D7%95%D7%A0%D7%99-tuberosejasmine/]
these are the 4 routes i have set up to try to catch this, with and without encoding the letters:
coverme.co.il/product/נר-בינוני-tuberosejasmine/
*.coverme.co.il/product/נר-בינוני-tuberosejasmine/*
https://coverme.co.il/product/%D7%A0%D7%A8-%D7%91%D7%99%D7%A0%D7%95%D7%A0%D7%99-tuberosejasmine/
*.coverme.co.il/product/%D7%A0%D7%A8-%D7%91%D7%99%D7%A0%D7%95%D7%A0%D7%99-tuberosejasmine/*
thanks in advance!
I believe the problem here is that you've configured your routes to match "נר-בינוני" unescaped, but the browser will actually percent-encode the URL before sending to the server, therefore the route matching actually operates on percent-escaped URLs. So the actual URL is https://coverme.co.il/product/%D7%A0%D7%A8-%D7%91%D7%99%D7%A0%D7%95%D7%A0%D7%99-tuberosejasmine/, and this does not match your route because %D7%A0%D7%A8-%D7%91%D7%99%D7%A0%D7%95%D7%A0%D7%99 is not considered to be the same as נר-בינוני.
EDIT: Unfortunately, using percent-encoding in your route pattern won't fix the problem, due to a known bug. Unfortunately, it's just not possible to match non-ASCII characters in a Workers route today. We intend to fix this, but it's hard because some sites are accidentally dependent on the broken behavior, so the fix would break them.
What you can potentially do instead is match against coverme.co.il/product/*, and then, inside your worker, check if the path also has נר-בינוני-tuberosejasmine. If it does not, then your fetch event handler should simply return without calling event.respondWith(). This will trigger "default handling" of the request, meaning it will pass through and be sent to your origin server like normal. (Note that you will still be billed for a Workers request, though.)
So, something like this:
addEventListener("fetch", event => {
if (event.request.url.includes(
"coverme.co.il/product/נר-בינוני-tuberosejasmine/")) {
event.respondWith(handle(event.request));
} else {
return; // not a match, use default pass-through handling
}
})
I'm using the following code in one of my pages:
export async function getServerSideProps(context) {
const session = await getSession(context)
return {
props: { session }
}
}
and the session is returning null. I get the following error:
[next-auth][error][client_fetch_error] [
'http://localhost:3000/api/auth/session',
FetchError: request to http://localhost:3000/api/auth/session failed, reason: read ECONNRESET
if I try to navigate to http://localhost:3000/api/auth/session in my browser I get the session object normally. Also, my co-worker has the same code in his machine and it is working fine for him.
The only difference that I know between my environment and his is that I'm using windows and he is using mac. Not really sure if this can be causing the problem here.
This problem is happening due to not specifying e.preventDefault() on login button.
The working code should look like this :-
async function login(e) {
e.preventDefault(); //Add this to your code.
const getLoginStatus = await signIn("credentials", {
redirect: false,
username,
password,
})
};
Try to delete .next folder in your root directory and try again
I had the same issue and solved it by using straight ip address/domain name.
Try to use 127.0.0.1 instead of localhost, e.g.: NEXTAUTH_URL=http://127.0.0.1:3000
I am trying to use Apollo client-state data with the hooks useQuery and useMutation as a global store inside a NextJS app.
When I follow the example from NextJS called with-apollo (https://github.com/zeit/next.js/tree/canary/examples/with-apollo), which uses a HOC in which it runs all the queries and renders the app on the server first.
Normally, you want to catch the 'loading' state in a component like this:
const { loading, data } = useQuery(GET_NAME_QUERY) // some #client query
if (loading) return <p>Loading...</p>
return <h1>Hello {data.name</h1>
But I want to skip the loading-check and always have a default state available. I think this could be done with setting the cache of the apollo-client to a set of default values, like this:
const cache = new InMemoryCache().restore(initialState);
// This is the part where the initial client-state data is set:
cache.writeData({
data: { name: 'Harry' }
});
const apolloClient = new ApolloClient({
cache, // <-- cache with preset client-state data
typeDefs,
resolvers,
})
With the goal to just do this:
const { data } = useQuery(GET_NAME_QUERY) // some #client query, resolves immediately from cache
return <h1>Hello {data.name</h1>
I created a repo with a robot and its name & status that are cached from the beginning this way. See https://github.com/rnacken/next-with-apollo-client-state-cache
The client works, without any errors, but during SSR, I get an error, since it does not have the data yet (and 'loading' is true) after a useQuery call.
When I log the loading/data state, I see this on the server:
On the client, it's all good:
Does anybody know how this is happening? With the cache set, I shouldn't see a loading:true state ever right? Is the getDataFromTree from #apollo/react-ssr not working correctly?
This might sound like a silly question but I have really tried everything I could to figure it out. I am creating a variable and adding it to my response object in custom Express server file like so:
server.get('*', (req, res) => {
res.locals.user = req.user || null;
handle(req, res);
});
Now I want to access this res.locals.user object from all of my pages, i.e. index.js, about.js, etc., in order to keep a tab on the active session's user credentials. It's got to be possible some way, right?
P.S.: Reading some thread on the NextJS Github page, I tried accessing it from my props object as this.props.user but it keeps returning null even when a server-side console.log shows non-null values.
The res object is available on the server as a parameter to getInitialProps. So, with the server code you have above, you can do
static async getInitialProps({res}) {
return { user: res.locals.user }
}
to make it available as this.props.user.