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.
Related
I'm looking to use the full-featured PDF.js in a React component in a Next.js project, as seen in Firefox and as on this online demo. Some important features here are being able to navigate to a certain page number by typing it in, and searching for text in the PDF. Is there a React component available for that?
The library react-pdf is nice for rendering a single page, but doesn't provide a toolbar or a convenient way of lazily loading pages in a scrollable view.
Similar to the questions How to use full PDF.js viewer with toolbar in webpack and Vuejs? (where the accepted answer provides a Vue component) and Embed Full Mozilla pdf.js viewer in vue.js ( using webpack via vue-cli ), but for React.js.
I tried including including /web/viewer.html as part of the inner HTML of a React component by doing the following, but it didn't work out.
Download the latest release and extract it to a folder part of my Next.js project (which I called pdfjs). I tried several folders, such as /client, /client/components, /pages, /node_modules, and /.
Run npm install --save-dev html-loader
Use this Webpack loader that parses HTML files, by changing next.config.js to the following:
module.exports = {
// …
webpack: (config, options) => {
config.module.rules.push({
test: /\.html$/,
exclude: /node_modules/,
use: { loader: 'html-loader' }
});
return config;
},
}
Create a simple page under /pages as follows:
import React from 'react';
import PdfViewer from '../pdfjs/web/viewer.html'
export default function () {
return (
<div className="content" dangerouslySetInnerHTML={{ __html: PdfViewer }} />
);
};
After running next in terminal to start a dev server and navigating to that page in the browser, I get an error about the JavaScript heap running out of memory.
Even if my computer had enough memory, I'm not sure that this would actually result in the PDF rendering – not to mention the danger of using dangerouslySetInnerHTML. It looks like a better solution would probably be to have an actual React component rather than trying to embed an HTML file.
I think this might be more of what your after. I wrapped it in a component for you already but this is a document viewer which can view PDF documents with out much work.
import React,{ Component } from 'react';
import ReactDOM from 'react-dom';
class DocView extends React.Component{
constructor(props){
super(props);
}
render(){
var url = "https://docs.google.com/viewerng/viewer?url="+this.props.src+"&embedded=true";
return(
<iframe style={this.props.style} src={url}></iframe>
);
}
}
export default DocView;
CloudPDF offers a React PDF viewer. It is basically pdf.js but then pre-rendered on the server. This gives the possibility for lazy loading of large pdf files and still keeping performance. And by default has a nice layout for the viewer.
import CloudPdfViewer from '#openbook/cloudpdf-viewer';
export default function () {
return (
<CloudPdfViewer documentId="346467a6-fa61-43ad-b45a-d1fdc3da0007" width="100%" height="500px" />
);
};
Disclamer: I am working for CloudPDF and it is still a beta version.
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.
I have a Reactjs (v.16.6.3) page which its SEO is important to be indexed by Google. Therefore, I checked it with Fetch as Google tool to know what Google-bot renders from this page.
However, google shows nothing and only depicts a blank page to me!
I have added 'babel-polyfill' to fulfill es6-es7-es8 requirement and make google-bot happy since I have used async-await (es8) approach in ComponentDidMount (to load async data in this lifecycle method) and other methods. Also popular arrow functions have been used though and result is nothing in Fetch as Google again!
I even get no result while importing some flat data (like the following I have written) which are only imported from another module and put directly to render method (not in componentDidMount). I have checked and found that they exist to main.chunk.js and Google should read and render them adequately but nothing happened!
export const sampleData01= [
{name: sampleName01,
lastName: sampleLastName01,
image: sampleImage01
},
{name: sampleName02,
lastName: sampleLastName02,
image: sampleImage02
}
]
export const anotherData02= [
{name: anotherName01,
lastName: anotherLastName01,
image: anotherImage01
},
{name: anotherName02,
lastName: anotherLastName02,
image: anotherImage02
}
]
-----------
import React, {Component} from 'react'
import {sampleData01} from './tempData'
import Helmet from "react-helmet";
class SampleClass extends Component {
state = {...something , loading:false}
async componentDidMount = ()=> {
this.setState({loading:true})
...await fetch something
this.setState({loading:false})
}
}
render(){
const data = sampleData01.map(item => {
<li>
{item.name}
</li>
}
return (
<div className="...">
<Loading loading={this.state.loading}/>
<div className="...">
<Helmet link={....} title={....} meta={....} />
<ul>
{data}
</ul>
</div>
</div>
)
}
export default SampleClass
eveything is working fine on both dev and production mode. I have checked every possible ways such as importimg es6-shim, isomorphic-fetch, url-search-params-polyfill, whatwg-fetch and got no result! I have read in some article that google might use phantomjs for rendering page. I have checked out page with phantomjs by myself in the web (not local) and it shows and renders perfectly fine. I have read lots of articles say there is no issue with Google search and SPAs while I am seeing something else! It seems I should shift to SSR for more convenient way to ensure having SEO friendly page.
I have tried so many dirty hacks to improve SEO for Client Side rendering website but in the end SSR was the only option. Either make your own SSR project using or using Razzle (https://github.com/jaredpalmer/razzle) or Next.js (https://github.com/zeit/next.js/)
I created a React/Typescript project with dotnet new "ASP.NET Core with React.js".
index.cshtml:
<div id="react-app"></div>
#section scripts {
<script src="~/dist/main.js" asp-append-version="true">
</script>
}
boot.tsx(shortened):
function renderApp() {
ReactDOM.render(
<AppContainer>
<BrowserRouter children={ routes } />
</AppContainer>,
document.getElementById('react-app')
);
}
renderApp();
if (module.hot) {
module.hot.accept('./routes', () => {
routes = require<typeof RoutesModule>('./routes').routes;
renderApp();
});
}
How can I pass ASP.Core generated information(the routes from the controllers) to my react/typescript code?
To use server-side rendering in your application, follow the following steps:
1 - Modify App_Start\ReactConfig.cs (for ASP.NET MVC 4 or 5) or Startup.cs (for ASP.NET Core) to reference your components:
namespace MyApp
{
public static class ReactConfig
{
public static void Configure()
{
ReactSiteConfiguration.Configuration = new ReactSiteConfiguration()
.AddScript("~/Scripts/HelloWorld.jsx");
}
}
}
This tells ReactJS.NET to load all the relevant JavaScript files server-side. The JavaScript files of all the components you want to load and all their dependencies should be included here.
2 - In your ASP.NET MVC view, call Html.React to render a component server-side, passing it the name of the component, and any required props.
#Html.React("HelloWorld", new
{
name = "Daniel"
})
3 - Call Html.ReactInitJavaScript at the bottom of the page (just above the ) to render initialisation scripts. Note that this does not load the JavaScript files for your components, it only renders the initialisation code.
<!-- Load all your scripts normally before calling ReactInitJavaScript -->
<!-- Assumes minification/combination is configured as per previous section -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.js"></script>
#Scripts.Render("~/bundles/main")
#Html.ReactInitJavaScript()
4 - Hit the page and admire the server-rendered beauty:
<div id="react1">
<div data-reactid=".2aubxk2hwsu" data-react-checksum="-1025167618">
<span data-reactid=".2aubxk2hwsu.0">Hello </span>
<span data-reactid=".2aubxk2hwsu.1">Daniel</span>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.js"></script>
<script src="/Scripts/HelloWorld.js"></script>
<script>ReactDOM.render(HelloWorld({"name":"Daniel"}), document.getElementById("react1"));</script>
The server-rendered HTML will automatically be reused by React client-side, meaning your initial render will be super fast.
If you encounter any errors with the JavaScript, you may want to temporarily disable server-side rendering in order to debug your components in your browser. You can do this by calling DisableServerSideRendering() in your ReactJS.NET config.
For a more in-depth example, take a look at the included sample application (React.Samples.Mvc4).
5 - Server-side only rendering
If there is no need to have a React application client side and you just want to use the server side rendering but without the React specific data attributes, call Html.React and pass serverOnly parameter as true.
#Html.React("HelloWorld", new
{
name = "Daniel"
}, serverOnly: true)
And the HTML will look like the one following which is a lot cleaner. In this case there is no need to load the React script or call the Html.ReactInitJavaScript() method.
<div id="react1">
<div>
<span>Hello </span>
<span>Daniel</span>
</div>
</div>
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