meta tag server side rendering - reactjs

I am using react helmet and am a bit lost with regards to the server side rendering. If I view elements in google console I can see the title and meta description but when viewing the page source they are not there.
I am using a Node.js backend with express to create an API. The React app is just a frontend application which gets data from the Node.js API.
In React I simply have:
import { Helmet } from "react-helmet";
render() {
return(
<>
<Helmet>
<title>My site title</title>
<meta name="description" content="Helmet application" />
</Helmet>
</>
)
}
The direct link to the server side example shows some code which I don't really know what to do with. I think the word 'server' is throwing me off because I am thinking that I need to put some code on my Node.js server but perhaps that is not the case?

Indeed, Helmet.renderStatic() method will collect all tags corresponding to the page you are requesting.
If you want to see those tags on the server side as well (source code), you need to, in your server file:
Call const helmet = Helmet.renderStatic()
From helmet get helmet.title.toString() and helmet.meta.toString()
Append those to your HTML just like https://github.com/nfl/react-helmet#server-usage As string input describes.

Change index.html to index.php and use PHP in index.php after build. and create a file myMata.php move all old meta tags to myMata.php and make dynamic meta tags using PHP.
view-source:https://www.heinsoe.com
index.php
<html>
<head>
<?php include './myMata.php';?>
//more code
myMata.php
<?php
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$paths = (explode("/", $path));
if (isset($paths[1])) {
switch ($paths[1]) {
case 'blog':
?>
<title>dynamic title</title>
//..... other tag
<?php
break;
case 'contact':
?>
<title>contact</title>
//..... other tag
<?php
break;
default:
http_response_code(404);
break;
}
}
else{
?>
<title>Home</title>
//..... other tag
<?php
}
?>

Related

Why Rich-Results doesn't catch generate structured data with javascript

Generate structured data with javascript. But structured data testing tool doesn't catch any data.
Why Rich-Results doesn't catch generate structured data with javascript.
Google Doc Said:
Google can read JSON-LD data when it is dynamically injected into the page's contents, such as by JavaScript code or embedded widgets in your content management system.
from this doc
and how to do reference here.
But Testing tool doesn't catch the data.
Test Page:
Page A, Page B
Page's JSON-LD data is correct, I copy to Testing tool, it can found.
Web page is build by Next.js^10.2.3.
I used server-side render structured-data before.
Encountered page large than 1M, can't load page.
So I changed it to client-side dynamically injected into the page's contents.
import React from 'react';
import Head from 'next/head';
import { map, keys } from 'ramda';
function SeoSchema({ schema }: { schema: Object }) {
// client side render only
if (!process.browser) return null;
return (
<Head>
{/* schema */}
{map((key) => (
schema[key] && (
<script
type="application/ld+json"
key={`schema-${key}`}
// eslint-disable-next-line
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema[key]) }}
/>
)
), keys(schema))}
</Head>
);
}
export default SeoSchema;
What I'm missing?
If there no answer, I will change back to server-side render structured-data.

Wrong og:image is appearing on page metadata

In my [id].tsx page I have the following meta tag structure
<Head>
<meta property="og:title" content={'품고 - ' + archive.title} key="title" />
<meta property="og:type" content="article" key="type" />
{imageUrl && <meta property="og:image" content={imageUrl} key="image" />}
</Head>
However in my production server, when I scrape an article using the Facebook debugger I get the following error
But when I check for an article in my development server, the proper image shows even though the code is the same as production
I also do have the following line in my _app.tsx file that I think may be causing the error but am not sure
<link rel="canonical" href="https://poomgo.com/" />
And the truly strange thing is that if I share my production article links on kakao, the thumbnail image shows up fine, but on Facebook and LinkedIn, the thumbnail image does not show up properly.
Does anyone know why my meta tags are scraped differently on my production and development servers when the code applied is exactly the same?
How my imageUrl is generated
I get archive data from a third party API (strapi) using useSWR
const { data: archive, error } = useSWR('/archives/' + router.query.id, (url) => {
return axios.get(url).then(res => res.data)
}, {
initialData: props.data
})
I then get my images from the archives and if images exist, I get my imageUrl
const images = archive.images
let imageUrl = ''
if (images && images.length > 0) {
imageUrl = getCloundFrontUrl(images[0].url)
}
I then use the getCloundFrontUrl function to replace the url with my cdn
export const getCloundFrontUrl = (url) => {
return url ? url.replace('poomgo-homepage.s3.ap-northeast-2.amazonaws.com', 'cdn-hp.poomgo.com') : ''
}
Below is the shape of my data
I removed the
<link rel="canonical" href="https://poomgo.com/" />
from my _app.tsx and the issue was resolved. Pretty sure that the code above signalled redirects to my home page from every page on production which caused the wrong og:image

How to read Spring Boot application.properties in ReactJs app?

We have 2 configuration files: one is in our Spring Boot application (application.properties) and another in our ReactJs app (we use .env in create-react-app). It was decided to use Spring Boot application.properties also in ReactJs app. Can anyone please guide me how can I achieve this?
I have read about "properties-reader" and tried to use it, but I don't have webpack.config.js file in our ReactJs app.
Thymeleaf provides the easiest way to pass data from application.properties file to Javascript via the template (index.html) file.
Alternatively, it can be done using normal JSP also.
Here are the working examples:
Option 1: Thymeleaf
Step 1: Define the interesting data attributes as hidden elements in the index.html file
<div id="root"></div> ---> Div to be updated by react
....
<span id="myData" hidden></span>
<!-- Script to set variables through Thymeleaf -->
<script th:inline="javascript">
var myData = "[${myData}]]";
document.getElementById("myData").innerHTML = myData;
</script>
Important note:
Make sure that the same index.html file exists in the '/public' folder of Reactjs project as well as in the /src/main/resources/templates/ folder of the spring boot project.
Step 2: Use model.addAttribute() method in Spring Boot to invoke Thymeleaf for setting data in the index.html file
#GetMapping("/")
public String index(Model model) {
// Get the value of my.data from application.properties file
#Value("${my.data}")
private String myData;
// Call Thymeleaf to set the data value in the .html file
model.addAttribute("myData", myData);
return "index";
}
Step 3: Update the ReactJS code to read the interesting attribute using document.getElementById
let myData = document.getElementById("myData").innerHTML
More information:
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#javascript-inlining
https://attacomsian.com/blog/thymeleaf-set-javascript-variable
Option 2: JSP
Step 1: Define the interesting data attributes as hidden elements in the index.jsp file
Location of index.jsp: src/main/webapp/WEB-INF/jsp/index.jsp
<!DOCTYPE html>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html lang="en">
<head>
<!-- Head section here -->
</head>
<body>
<!-- Div to be updated by react -->
<div id="root">
</div>
<!-- Include the interesting attribute as a hidden field -->
<span id="myData" hidden>${myData}</span>
</body>
</html>
Important note:
Make sure that the /public/index.html file of reactjs project has the same content (<body>...</body>) as that of the src/main/webapp/WEB-INF/jsp/index.jsp file of spring boot project)
Step 2: Use map.put() in Spring Boot controller to update data in JSP
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
#Controller
public class HomePageController{
// Read data from application.properties
#Value("${my.data}")
private String myData;
// Update data attributes of JSP using map.put
#GetMapping("/")
public String index( Map<String, Object> map ) {
map.put("myData", myData);
return "index";
}
}
Step 3: Update the ReactJS code to read the interesting attribute using document.getElementById
let myData = document.getElementById("myData").innerHTML
More information:
https://mkyong.com/spring-boot/spring-boot-hello-world-example-jsp/

Pass data from `index.html` to react components

I recently got started with web development. And I am stuck with sth that's probably a trivial problem. I am trying to figure out how I can pass data from my dynamically created index.html to my (typescript) react frontend (created via create-react-app).
Suppose we have a flask web server that, when the '/' resource is requested, gathers some initial user data, instantiates a page template with it and returns that page:
# flask webserver
from flask import Flask
from flask import render_template
app = Flask(__name__)
#app.route('/')
def index():
initial_user_data = {"foo":"bar",
"baz":"biz"}
return render_template('index.html', initial_data=initial_user_data)
if __name__ == '__main__':
app.run(debug=True)
For the sake of simplicity initial_user_data stores hard-coded data here. In my actual use case the dictionary gets populated with various user-specific data items that are read from files etc.
Next, let's assume index.html uses the initial_data.
<!DOCTYPE html>
<html lang="en">
<head>
...
<title>React App</title>
</head>
<body>
<script>
initial_data = {{initial_data | tojson}}
console.log(initial_data)
</script>
<div id="root"></div>
...
</body>
</html>
When we now start the webserver and open a browser to navigate to the page when can see the initial_data being logged to the browser's console output. So far, so good.
Now my problem: how can I pass initial_data to my (typescript) react components? Conceptually I want to do sth like this:
// App.tsx
import React from 'react';
const App: React.FC = () => {
// make use of 'initial_data'
const init_data = initial_data;
return (
<div ...
</div>
);
}
But yarn build will give me
Cannot find name 'initial_data'. TS2304
4 |
5 | const App: React.FC = () => {
> 6 | const init_data = initial_data;
| ^
7 | return (
8 | <div className="App">
9 | <header className="App-header">
How can I make initial_data accessible to my react components?
Edit: If this pattern of passing something from the index.html (that gets created on the backend when a clients connects) to my typescript react components is flawed then I'd also accept an answer that points me to the correct pattern in this case.
Something along the lines of (obviously just making sth up, just trying to illustrate what I mean)
Define a typescript data type that stores the user data that can be accessed from all your components
in your main react component use a life-cycle method like 'componendDidMount' to send a request to the backend to fetch the initial_data
When the response comes back store it in 1)
I'd accept an answer that adds shows some sample code for 1) 2) 3)
Many thanks for your help!
When you pass global variables inside a react component, it's always a better way to pass it using the window object.
In this case, you need to pass it as window.initial_data. This informs the linter and react that it's a global variable. As it is not defined inside the file.

How to use meta tags with dynamic value in react js?

Can anyone help me regarding how to use meta tags with dynamic value in react js?
Please see the image for my requirement,
I am using the extra metatag html tag here(because react require wrap complete html inside the single tag else it raise error). I can also use div/p any html tag, but is this right way to render the react component? having extra html tag than inside that meta tags. Will this work for SEO?
Please suggested me any other good way to use meta tags manually.
I can see few issues regarding the code which you shared.
Meta tags come under head, but your react components would be rendered in your body tag.
Considering SEO part, google can parse JS now so your tags would be read but bing and if you consider yahoo still cannot still do that( Google also is really not that efficient still, faced too many issues regarding while handling SEO's with single page app)
If your reacts components uses Link to navigate to other components which I am assuming it would it case of SPA it would not work, because crawlers try to reach you page directly.
Now,if you have a single page app with a single component you can try react-helmet , but if it involves multiple components and navigations I would suggest you to go for pre-rendering,maybe using phatom-js or pre-render.io(which indirectly uses phantomjs).
If your only concern is meta tags, then you can embed you meta tags directly into your html code and not in the components. This would really help the crawlers to see the meta tags.
But,if you also want crawlers to see your content, pre-rendering is best solution which I can think of now.
If you are serving your React bundle from a server, you can dynamically generate meta tags on the server.
Essentially, in your public/index.html file you want to replace the metadata with an identifiable string:
<!-- in public/index.html -->
<title>$OG_TITLE</title>
<meta name="description" content="$OG_DESCRIPTION" />
<meta property="og:title" content="$OG_TITLE" />
<meta property="og:description" content="$OG_DESCRIPTION" />
<meta property="og:image" content="$OG_IMAGE" />
And then on the server, you want to replace these strings with the dynamically generated information. Here is an example route with Node and Express:
app.get('/about', function(request, response) {
console.log('About page visited!');
const filePath = path.resolve(__dirname, './build', 'index.html')
fs.readFile(filePath, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
data = data.replace(/\$OG_TITLE/g, 'About Page');
data = data.replace(/\$OG_DESCRIPTION/g, "About page description");
result = data.replace(/\$OG_IMAGE/g, 'https://i.imgur.com/V7irMl8.png');
response.send(result);
});
});
Taken from this tutorial here: https://www.kapwing.com/blog/how-to-add-dynamic-meta-tags-server-side-with-create-react-app/
Create React App produces a static bundle with HTML, JS, and CSS. It can’t possibly give you a dynamic <meta> tag because the result HTML is created ahead of time.
While changing document.title with something like React Helmet makes sense, changing <meta> tags doesn’t make sense unless your app is server rendered. Server rendering is not a supported feature of Create React App so if you want to use it, you might want to check out some alternatives such as Next.js.
That said, if you don’t want full server rendering and only need to change <meta> tags, you could do this by hand as described here.
I hope this helps!
** no need to install express node and all..
** just add react-helmat & must add Helmat-meta tag all routing container. (otherwise its still show home page meta tag)
** react return single element, so you must add into parent element like (div, form)
import { Helmet } from "react-helmet";
import MetaDataJSON from "./MetaDataJSON_File";
constructor(){
this.metaDetails = {};
}
UNSAFE_componentWillMount(){
let curPath = window.location.pathname
this.metaDetails = getMetaData(curPath);
}
export const getMetaData = (pathname) =>{
const metaObj = MetaDataJSON; // import meta json and check the route path is in equal to your meta json file
let metaPath = Object.keys(metaObj);
if (metaPath.indexOf(pathname) >= 0) {
return metaObj[pathname];
}else{
return metaObj["/"];
}
}
// you must add in all component (where routing container)
render(){
return(
<div>
<Helmet>
<title>{this.metaDetails.title}</title>
<meta name="description" content= {this.metaDetails.description}/>
<meta name="keywords" content= {this.metaDetails.keywords} />
</Helmet>
<div>
)
}
There Is a Package Named React-Helmet available it helps to take control over Your Head tags on each route.
Helmet takes plain HTML tags and outputs plain HTML tags. It’s dead simple, and React beginner friendly.
<Helmet>
<title>{context.StoreName}</title>
<meta name="theme-color" content={`${context.ThemeColor}`}/>
</Helmet>
reference - https://codeburst.io/how-to-control-head-tags-in-react-seo-friendly-8264e1194880

Resources