I have a Django CMS that serves as my back-end application. And I'm trying to create pages dynamically in my Gatsby front-end site. My Django application is exposed over GraphQL using Graphene. But I'm not able to query the slugs from backend CMS and create pages using gatsby-node.js. How do I create pages when I create a page in the back-end application?
The idea being
//gatsby-node.js
exports.createPages = ({ graphql, actions }) => {
const pages = graphql`
{
blogPages{
edges{
node{
slug // this slug supposed to come from the backend CMS (Atleast i think)
}
}
}
}
`;
const { createPage } = actions
const blogTemplate = path.resolve(`src/templates/blogTemplate.js`);
pages.blogPages.edges.forEach(edge => { //this should help to create dynamic pages - slug coming from backend CMS
const slug = edge.node.blogpage.slug;
createPage({
path: slug,
component: blogTemplate
})
})
}
It's been said in the comments already, but just to summarize: since Gatsby is a static site generator you cannot dynamically add pages at runtime. Each page corresponds to its own html file that needs to be created on your webserver. That is not something you can do at runtime.
What you can do is to set up a continuous integration workflow where you have a build running in the cloud somewhere. Trigger it when you make a change in Django, or alternatively run it regularly (hourly/daily) to update the site.
If running a rebuild does not work for your use case you need to look at an entirely different architecture.
Related
I have a working website which is developed in react and is hosted as a static site on AWS-S3. Our home page route is /home however when we try to access it, we get the following error:
Message: The specified key does not exist.
Key: home/home
RequestId: 0CJ72YSRVM1VR7DT
HostId: EnusXIGM/BWUeBk2Y+jjW2XFYtKjpFB66wf2n9om5L/+yX52JQUviK5ZLPJW6U0moywqGuIBc5M=
so, in the root folder, we have put a index.html in the root folder with the following content.
import React from "react";
import { useNavigate } from "react-router-dom";
const Coverpage: React.FC = () => {
const navigate = useNavigate();
return (
<>
<div>I am cover page!</div>
<button onClick={() => navigate("/home")}>Click me to navigate to homepage!</button>
</>
);
};
export default Coverpage;
and the navigation works.
I really need help to find a way where when the user access the site http://xxxx, the site directly navigate to http://xxxx/home and the site opens as desired.
Appreciate your help. not sure if we can do it at reactjs level or AWS s3
The solution is to configure AWS to rewrite most URLs to your React's index.html.
Create a CloudFront distribution which distributes the S3 bucket.
Ensure the distribution's Default Root Object is set to index.html.
Create a CloudFront function with the code below. This rewrites all requests to index.html except for requests to /static/*.
function handler(event) {
var request = event.request;
var parts = request.uri.split('/');
if(parts[1] != 'static'){
request.uri = '/index.html';
console.log('Rewriting: ' + request.uri);
} else {
console.log('Not Rewriting: ' + request.uri);
}
return request;
}
Go to the CF distribution then open the default behaviour (or create it if needed) and at the bottom, associate the function as a View Request type
Now you can visit the CF Distribution's URL (or your domain if configured) with any path and the React app will show.
The other option is to simply set the S3 bucket's Error Document to index.html, but this is very hacky and not recommended. Page visits will show the React app but will have undesirable 404 error codes.
I have a doubt with nextjs..
I'm building my site like this
pages
[slug]
index.jsx
index.jsx
so in my slug/index I'm doing this
export async function getStaticPaths() {
const resProducts = await fetch(`${process.env.PRIVATE_ENDPOINT}/products`);
const products = await resProducts.json();
const paths = products.data.map((p) => ({
params: {
slugProduct: p.slug,
},
}));
return {
// this should be dynamic
paths,
fallback: true,
};
}
My question is what happend if I add a new product in my back office?
Do I have to rebuild with next build?
My question is what happend if I add a new product in my back office?
Do I have to rebuild with next build?
The short answer is NO. If the requested page have not been genereted at build time, Next.js will serve a "fallback" version of the page and will statically generate the requested path HTML and JSON on the background. When the statically generation completed, the browser receives the JSON for the generated path. Subsequent requests to the same path will serve the generated page, just like other pages pre-rendered at build time.
Don't forget to use router.isFallback to detect that request is on fallback.
You can see the good document here.
https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation
I am creating an application on React.js, Gatsby.js, and Contentful. My Application is working fine on my local but when I deploy my app to Natilify Cannot query field "allContentfulGallery" on type "Query". And My GraphQl Queries are also working fine. Please help me I am very sticking by this error."allContentfulGallery" is my collection Name
Very thanks in advance
My gatsby-node.js configuration
const galleryResult = await graphql(`
query gallery {
allContentfulGallery {
edges {
node {
title
slug
images {
title
file {
url
}
}
sys {
contentType {
sys {
id
linkType
type
}
}
revision
type
}
}
}
}
}
`)
var galleryArr =
galleryResult &&
galleryResult.data &&
galleryResult.data.allContentfulGallery &&
galleryResult.data.allContentfulGallery.edges
galleryArr.forEach(edge => {
createPage({
path: `/gallery/${edge.node.slug}`,
component: galleryTemplate,
context: {
title: edge.node.title,
slug: edge.node.slug,
sys: {
...edge.node.sys,
},
},
})
})
It seems (according to the comments) that the environment variables are not properly set, since they work locally (under both environments, gatsby develop and gatsby build) but not on GitLab nor Netlify.
Dealing with Gatsby + Netlify requires to prefix all environment variables with GATSBY_ as you can see in Netlify docs:
Any environment variables prefixed with GATSBY_ are processed by
Gatsby and made available in the browser for client-side JavaScript
access. Visit the Gatsby docs about environment variables for more
information.
So, change all variables locally, and in Netlify's and GitLab dashboard prefixing them with GATSBY_.
CONTENTFUL_ENVIRONMENT
CONTENTFUL_API_KEY
CONTENTFUL_SPACE_ID
Will become:
GATSBY_CONTENTFUL_ENVIRONMENT
GATSBY_CONTENTFUL_API_KEY
GATSBY_CONTENTFUL_SPACE_ID
Keep in mind that this approach applies to all environment variables, not only for the Contentful ones.
Normally I'm pretty sure about the resolutions but in your case, if you haven't set the environment variables properly, the plugin configuration should fail, breaking the compilation before your issue prompts and it's not the case.
I have a plugin TypeWriting in Gatsby.js (React). It looks like this:
/* file: gatsby-browser.js */
const typeWriting = () => {
new Typewriter('#intro-typing', {
strings: ['Drupal', 'WordPress', 'OpenCart'],
});
}
export const onInitialClientRender = () => {
typeWriting();
}
I want to set for "string" - own array from graphql query
How I can work with graphql query in gatsby-browser.js?
gatsby-browser.js is a file that lets you respond to actions within the browser, and wrap your site in additional components. The Gatsby Browser API gives you many options for interacting with the client-side of Gatsby. So I don't think that you can trigger, outside any API or method, any kind of GraphQL query.
If you want that strings array to be "automated" you can use environment variables and get place it as values of the array.
I'm using Gatsby and I want build a single page site, so without create pages. For achieve this I edited gatsby-node.js with the following code:
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
if (page.path === "/") {
page.matchPath = "/*"
createPage(page)
}
}
in that case, each request is re-routed to the index.js page, which is the only one.
Then, in the index.js page I have:
const IndexPage = () => {
const intl = useIntl()
const locale = intl.locale
return (
<BGTState>
<BlogState>
<Layout>
<Router>
<Home path={`${locale}/`} />
<Section path={`${locale}/:sectionSlug`} />
<Collection path={`${locale}/:sectionSlug/:collectionSlug`} />
<Season
path={`${locale}/:categorySlug/:collectionSlug/:seasonSlug`}
/>
<Product
path={`${locale}/:categorySlug/:collectionSlug/:seasonSlug/:prodSlug`}
/>
<Blog path={`${locale}/blog`} />
<Article path={`${locale}/blog/:articleSlug`} />
<NotFound default />
</Router>
</Layout>
</BlogState>
</BGTState>
)
}
as you can see, I have different routers that load a specific component based on the url.
I have prefixed each path with the current locale to match the correct path.
This mechanism is working fine for the home page only, but for the other links doesn't work. Infact, if I visit something like:
http://localhost:3001/en/category-home/prod-foo
which must load the Collection component, the site simply redirect to:
http://localhost:3001/en
and display the Home component again.
What I did wrong?
UPDATE
Page Structure:
As you can see I have just the index.js which handle all requests as I configured in the gatby-node.js.
If I remove the localization plugin, at least using this configuration:
{
resolve: `gatsby-plugin-intl`,
options: {
// Directory with the strings JSON
path: `${__dirname}/src/languages`,
// Supported languages
languages: ["it", "en", "ci", "fr"],
// Default site language
defaultLanguage: `it`,
// Redirects to `it` in the route `/`
//redirect: true,
// Redirect SEO component
redirectComponent: require.resolve(
`${__dirname}/src/components/redirect.js`
),
},
},
and I don't prefix the url with intl.locale, everything is working fine. But adding redirect: true in the plugin configuration, and prefixing the link with the locale, the site redirect me to the home component.
If you are creating a SPA (Single Page Application, notice the single) you won't have any created pages but index. You are trying yo access to a /category page that's not created because of:
if (page.path === "/") {
page.matchPath = "/*"
createPage(page)
}
That's why your routes don't work (or in other words, only the home page works).
Adapt the previous condition to your needs to allow creating more pages based on your requirements.
I'm using Gatsby and I want build a single page site, so without
create pages. For achieve this I edited gatsby-node.js with the
following code:
It's a non-sense trying to build a SPA application with Gatsby (without creating pages) but then complaining because there's not collection page created.
Make sure that you understand what you are doing, it seems clearly that you need to create dynamically pages for each collection, season, and product so your approach to create SPA won't work for your use-case.
It's possible to keep just index.js without overcomplicating thing? I
just want to understand why my code isn't working 'cause I've passed
the correct url... Removing the localization Gatsby works, so I
suspect there is a localization problem
The only way that http://localhost:3001/category-home/prod-foo (removing the localization) could be resolved is by creating a folder structure such /pages/category-home/prod-foo.js (since Gatsby extrapolates the folder structure as URLs), so, if you want to use localization using your approach, add a structure such en/pages/category-home/prod-foo.js and es/pages/category-home/prod-foo.js (or the whatever locale), and so on. In my opinion, this is overcomplexitying stuff since, for every category, you'll need to create 2 (even more depending on the locales) files.
Gatsby allows you to create dynamic pages and interpolate the locale automatically using built-in plugins on the process, creating each file for the specifically defined locales.