Gatsby.js (React) - graphql query in gatsby-browser.js - reactjs

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.

Related

How do I use GraphQL to query an image from Contentful?

I am building a basic site with Gatsby and have connected it to Contentful. I uploaded 2 assets to Contentful:
First asset looks like:
The second asset is 100% identical other than the title which is test-two.
If I use the about query and pass in the URL into an img tag, my image will display. However, I am trying to use GatsbyImage and can't seem to figure out the problem.
I've been trying to follow this tutorial and using but I am unable to get anything to render. How does my query need to change in order to use gatsby-image?
In this case, you are querying for the url, filename and contentType. To be able to use GatsbyImage you need to query the node created from Gatsby (which is gatsbyImageData) it should be contained in the name of the Contentful asset node. Something like:
{
allContentfulAsset {
edges {
node {
test {
title
gatsbyImageData(layout: CONSTRAINED)
}
}
}
}
}
Check for the created nodes in the GraphiQL playground (localhost:8000/___graphql).
Once done, in your component, you should be able to do something like:
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
function SomePage({ data }) {
const image = getImage(data.allContentfulAsset.test)
return (
<section>
<GatsbyImage image={image} alt={`Some alt text`} />
</section>
)
}
export const pageQuery = graphql`
query {
allContentfulAsset {
edges {
node {
test {
title
gatsbyImageData(layout: CONSTRAINED)
}
}
}
}
}
`
If the node doesn't appear, check your configurations in the gatsby-config.js file.
⚠️ Disclaimer
Watch out, the tutorial you are trying to use is using gatsby-image (from Gatsby v2 backward), where the rendered component is Img, imported from gatsby-image while you are using GatsbyImage (from Gatsby v3 onwards), imported from gatsby-plugin-image. The first one is deprecated and the query structure is slightly different. As you can see at the top of the guide you shared:
The gatsby-image package is now deprecated. The new Gatsby image
plugin has better performance, cool new features and a simpler
API. See the migration guide to learn how to upgrade.

How to progamatically create pages in gatsby with a CMS backend?

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.

Make graphql query outside a JSX component in Gatsby

I have a .ts(not .tsx) file which just exports a json object like
const obj = {
img1: gql_img1,
img2: gql_img2
}
I want gq1_img1 and gq1_img2 to be the results of a graphql query
I found a solution which uses Apollo Client, but it doesn't look like they're using Gatsby and I don't think Gatsby uses a client.
The problem with using useStaticQuery is that it's a hook, if I try to use it like in the snippet below, I get "Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:"
const gql = () => {
const gql = useStaticQuery(graphql
`query adQuery {
invoiceNinja300x250: file(
extension: {regex: "/(jpg)|(jpeg)|(png)/"},
name: {eq: "IN-300x250-2"}
){
childImageSharp {
fluid(maxWidth: 250) {
...GatsbyImageSharpFluid_withWebp_noBase64
}
}
},
invoiceNinja600x300: file(
extension: {regex: "/(jpg)|(jpeg)|(png)/"},
name: {eq: "IN-600x300-2"}
){
childImageSharp {
fluid(maxWidth: 250) {
...GatsbyImageSharpFluid_withWebp_noBase64
}
}
}
}`
)
return gql
}
const GQL = gql()
Like I mentioned in your reddit post, if you're not using a page query or static query, you'll need Apollo Client or some other gql client.
I found a solution which uses Apollo Client, but it doesn't look like they're using Gatsby and I don't think Gatsby uses a client.
Gatsby and GraphQL clients are different things. Gatsby is a React framework for building static websites and uses graphQL to fetch data in various ways.
A GraphQL client is much like fetch or axios, they are libraries used to request, post, update, delete data from a REST API.
Can you explain your use case a bit? Maybe there is a more Gatsby way of doing it.
Have you considered the React Context API? On the production Gatsby app I work on that's what we use for global variables like some JSON/object data. It allows you in some sort of high level/layout/data layer component to stuff some values you get from a different file into your app to use with other components.

Integration testing a fetch calls in a node module

Goal: Call a function that invokes a fetch call to validate it works with my backend rest-api (end to end testing basically).
Project: node module built to be imported into several react web application. The module contains only fetch calls and minimal logic. Its basically a glorified wrapper for URLs and settings. Created to cut down work required to implement common end points used in applications.
Setup: I have a docker compose building a docker test container and pulling in my rest-api docker image (built in a different system). The test container pulls in the packed module and installs it with dependencies. Then it brings up the tests alongside the backend + other images needed for the backend (DB, login system, etc).
Problem: How to implement the tests to handle the calls.
Currently I've tried calling the fetch methods directly. This works for my login fetch but any additional call fails to send the cookie. As far as I understand the code I have depends on the browser for the cookie. I've tried several solutions to get said cookie but i've been unable to get fetch of node-fetch to send it properly. My best guess is each test was creating a new cookie but I lack the knowledge to full debug this solution path.
my send solution path was to attempt to use puppeteer to load a fake page and then evaluate the function in page following examples like:
https://github.com/puppeteer/puppeteer/issues/2579
How to use imported function inside page.evaluate in Puppeteer with Jest?
Problem with this is the tests kept failing to load libraries required or some other problem.
Code:
Here is the call I'm trying to test for the most part. Each function I have wraps around this providing {url: "api/endpoint/path", method: "GET"}. With some passing in a body for larger data posts.
export function request(options) {
//Build options
options = {
headers: {
'Content-Type': 'application/json'
},
...options
};
return fetch(options.url, options)
.then(response => {
//...
//Handle errors
if (!response.ok) {
return Promise.reject(`${response.status} - ${response.statusText}`);
}
try {
return response.json();
} catch (e) {
if (e.name === 'SyntaxError') {
return Promise.reject(response.text());
}
}
});
}
Test example i've tried:
import puppeteer from "puppeteer";
import {myCall} from "my-rest-bridge";
it('Check response', async () => {
//Load browser
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox']
});
const page = await browser.newPage();
//Load page
await page.goto('http://docker:8888/index.html');
//Do login
expect(await page.evaluate(() => login('user', 'password')).toBe(expectedUserResponseJson);
//Make call
expect(await page.evaluate(() => myCall(input1, input2)).toBe(expectedCallResponseJson);
//Close page
await page.close();
})
Took me a while but I built a solution to my own question. Its not perfect so if anyone has a better idea please answer.
So my solution works as follows. I built an addition git project to create a shell reactjs application inside a docker image. This application pulls in my node module, iterates through all the exports, and then generates a component per function.
import React from 'react';
import * as magicNodeModule from "magic-node-module"; //obviously not the real name
import CallRest from "./CallRest";
/** Core component for the application */
export default class App extends React.Component {
/** Renders the core application */
render() {
const restCalls = Object.keys(magicNodeModule);
return (
<div id={"App"}>
<div>
Functions found:
<ul id={"function-list"}>
{restCalls.map(restCall => <li>{restCall}</li>)}
</ul>
<hr/>
</div>
{
restCalls.map(restCall => {
return (
<CallRest restName={restCall} restCall={magicNodeModule[restCall]}/>
);
})
}
</div>
)
}
}
This component (CallRest) contains an input box, submit button, and output div. A user, or in my use case puppeteer, can input data into the input. Then by clicking submit it will run the fetch call and insert the resulting output into the div. Works very much like swagger 2 for those that are familiar with the system.
The solution is still built up as a series of docker images inside of a compose. Though it did require setting up a reverse proxy to allow the react app to communicate with backend API. As well it pulls in a fresh copy of the node module as a pack zip and installs it into the docker. This way I only have to build the shell react docker once in a blue moon.

Gatsby + Markdown: How to get data from a specific markdown file into a single page?

I'm new to Gatsby, and making my best to learn it (along with React, in which I have no prior knowledge either). I'd like to create a single page getting data from one or several markdown files.
For now I'm testing it out with just Gatsby, in order to later reproduce that technique with Netlify CMS markdown files (and be able to update the page texts with Netlify CMS admin panel).
So far, I've managed to add markdown pages to Gatsby, thanks to this tutorial. But this method only creates dynamic pages, which is far more complex than what I need.
Is there a simple way to import one specific markdown file, let's say src/markdowns/hero-texts.md, in (let's also say) pages/index.js, and then call data with their frontmatter tags, in the cleanest way as possible?
I've tried countless researches on Google just to find which plugin or coding term would handle that, without success. I totally get some of the explanations above may be full of technical misunderstandings, sorry for that...
You have a markdown file called hero-texts.md and you want to be able to query its frontmatter content.
Install the plugins gatsby-transformer-remark and gatsby-source-filesystem and setup the gatsby-source-filesystem options to find your markdown files.
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `markdown`,
path: `${__dirname}/src/markdowns/`
}
},
`gatsby-transformer-remark`
]
}
You could make a graphql page query like this inside index.js (then the result of the query is automatically added to your index component under props.data)
// src/pages/index.js
import React from "react"
import { graphql } from "gatsby"
const IndexPage = ({data}) => {
return (
<>
<p>{data.markdownRemark.frontmatter.author}</p>
<p>{data.markdownRemark.frontmatter.date}</p>
<p>{data.markdownRemark.frontmatter.title}</p>
</>
)}
export default IndexPage
export const pageQuery = graphql`
query IndexPageQuery {
markdownRemark(fileAbsolutePath: { regex: "/hero-texts.md/" }) {
frontmatter {
author
date
title
}
}
}
`
It will perform the graphql query at build time, and add the result of the query to the data prop of the IndexPage page component.
So in effect, pulling in all the frontmatter fields from a markdown file that looked like this.
// src/markdowns/hero-texts.md
---
title: "Gatsby + Markdown: How to simply get data from a specific markdown in a single page?"
author: Florent Despinoy
date: 2019-08-06
---
# This is my markdown post
The content of this markdown file would not be queried by pageQuery (only the frontmatter would)

Resources