I want to build a templating engine for user profiles. After picking a design, which might consist of HTML, CSS, and JS, I would like to be able to server-side/static render a users profile page using their chosen template.
I'm looking for a good place to start / for someone to point me in the right direction. Assuming there are templates already stored in a database, or saved as files to AWS, how might I dynamically load and render the template along with the users profile data using Next.js? What might be an optimal way of storing the templates?
Thank you,
Try use nextjs GetStaticProps or GetStaticPatch
https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
https://nextjs.org/docs/basic-features/data-fetching/get-static-props
write this function in some NextPage file
export async function getStaticProps(context) {
//all logic done here will be rendered server-side.
return {
props: {}, // will be passed to the page component as props
}
}
It can consume a database within this layer, do not want to use an external API, in some projects I use the ORM Prisma to facilitate the process.
https://www.prisma.io/nextjs
// Fetch all posts (in /pages/index.tsx)
export async function getStaticProps() {
const prisma = new PrismaClient()
const posts = await prisma.post.findMany()
return {
props : { posts }
}
}
I am using this code in my webpart to insert into the sharepoint list with list name, but moving this code into production environment is creating an issue since its forming the wrong url for inserting into the list, The url in production is
https://abcportal.sharepoint.com/sites/SolutionBook/SitePages/_api/web/lists/getByTitle('Smart%20City%20IAQ%20Demo%20Requests')?$select=ListItemEntityTypeFullName
But in local environment is working fine it forms this url
https://abcportal.sharepoint.com/sites/solutionbooktest/_api/web/lists/getByTitle('Smart City IAQ Demo Requests')/items
In the production environment URL SitePages is coming automatically, how to remove it?
-------Code---------
public insertEmailToList() {
pnp.sp.web.lists.getByTitle("Smart City IAQ Demo Requests").items.add({
Title: this.state.Email
}).then(r => {
this.setState({ ButtonActive: false });
});
}
or Is there any way to insert into sharepoint list using URL of the list?
You need to establish the SPFx context for PnPJs. This can be done in the onInit() method of your web part through the setup() method imported from #pnp/core or #pnp/sp.
Using #pnp/core setup
import { setup as pnpSetup } from "#pnp/core";
// ...
protected onInit(): Promise<void> {
return super.onInit().then(_ => {
// other init code may be present
pnpSetup({
spfxContext: this.context
});
});
}
// ...
Using #pnp/sp setup
import { sp } from "#pnp/sp/presets/all";
// ...
protected onInit(): Promise<void> {
return super.onInit().then(_ => {
// other init code may be present
sp.setup({
spfxContext: this.context
});
});
}
// ...
Refer to this link for more details.
I built a blog with React that fetches the data for each blog entry dynamically from an api.
The page's content obviously looks different depending on the route, e.g. mysite.com/blog/1, mysite.com/blog/2, ...
What I want to achieve is to dynamically change the meta descriptions depending on the data that is fetched from the api based on the url. In particular the og:title, og:description and og:image. Is something like that even possible?
I read about SSR/Next.JS or Gatsby but I am not sure if this is working if the data is received from api calls.
I understand that SSR would render the content on the server, hence it allows Google to crawl the pages but wouldn't that exclude api calls?
I also understand that Gatsby builds static sites but for me that wouldn't work because the api calls are dynamic and cannot be built into a static site.
I would highly appreciate some hints to point me in the right direction.
I understand that SSR would render the content on the server, hence it
allows Google to crawl the pages but wouldn't that exclude api calls?
I also understand that Gatsby builds static sites but for me that
wouldn't work because the api calls are dynamic and cannot be built
into a static site.
I think you've misunderstood how Gatsby works.
To summarize, Gatsby generates static pages from dynamic data (API calls) so, when you run the gatsby develop or gatsby build command, Gatsby fetches the data from the sources (in this case from your API) and generates dynamic pages (mysite.com/blog/1, mysite.com/blog/2, etc).
This data is static, meaning that each change of those sources, will force you to re-fetch the data to display the changes (in production means a new deployment) but, as soon as your pages are built statically, you can build your SEO data on the fly.
This is an old Gatsby's workflow that they used to have on their old website but I find it quite self-explanatory:
In the build-time, your site is being statically generated so, you can fully customize your SEO requirements with a custom SEO component or whatever your want. Most of the starters come with a SEO component ready to be used:
function Seo({ description, lang, meta, title }) {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
author
}
}
}
`
)
const metaDescription = description || site.siteMetadata.description
const defaultTitle = site.siteMetadata?.title
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : null}
meta={[
{
name: `description`,
content: metaDescription,
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:card`,
content: `summary`,
},
{
name: `twitter:creator`,
content: site.siteMetadata?.author || ``,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: metaDescription,
},
].concat(meta)}
/>
)
}
Since the component is taking description, lang, meta and title as a props respectively, you can add it in your blog template to take dynamic data that will be built statically, meaning that, when your site will be deployed, that data will be already built, so Google crawlers will get it instantly.
const YourBlogPostTemplate = ({ data }) =>{
return <article>
<SEO title={data.allAPIData.frontmatter.title} />
<h1>I'm the title: {data.allAPIData.frontmatter.title}</h1>
</article>
}
Note: I won't fully customize it to avoid extending the answer, but get the idea.
The SEO component will be taking the title and the rest of the fields in the build-time.
Your API calls are fetched before the page is built so, at the time your page is being built your data is already static.
There is a pretty good article here that describes how to work around this issue the easiest way.
Basically, I needed to put a simple NodeJS server on top of my current React application. The server is now serving the files from the build directory. For some routes, I am simply replacing the __PAGE_META__ placeholder with the meta tags needed for Google, Facebook, Twitter, etc.
Here is a simple picture to describe the flow:
And a simple code snippet of the NodeJS part:
const path = require("path")
const express = require("express")
const app = express()
const fs = require("fs")
//
const pathToIndex = path.join(__dirname, "build/index.html")
app.get("/", (req, res) => {
const raw = fs.readFileSync(pathToIndex)
const pageTitle = "Homepage - Welcome to my page"
const updated = raw.replace("__PAGE_META__", `<title>${pageTitle}</title>`)
res.send(updated)
})
//
app.use(express.static(path.join(__dirname, "build")))
app.get("*", (req, res) =>
res.sendFile(path.join(__dirname, "build/index.html"))
)
const port = process.env.PORT || 5000
app.listen(port, () => {
console.log(`Server started on port ${port}`)
})
For the dynamic site, an api can be called and the page meta can be replaced with the information appropriately.
I'm currently working on a React app that should load a set of (non-public) files from a user's Google Drive and display thumbnails using the CSS background-image: url(...) property. I can load all of the file metadata using the Gapi Files:get method, and an OAuth token is set ahead of time using gapi.client.setToken. I'm hoping to load the thumbnail as follows:
function CollectionArtifact(props){
const [thumbnail, setThumbnail] = useState(null);
async function loadThumbnail(){
try {
const res = await window.gapi.client.request(props.artifact.thumbnailLink);
const data = await res.blob();
const localURL = URL.createObjectUrl(data);
setThumbnail(localURL);
catch(e){ console.log('Failed to load thumbnail', e); }
}
useEffect(() => {
if(props.apisLoaded){
loadThumbnail();
}
}, [props.apisLoaded]);
return (
...
<div style={{backgroundImage: `url(${thumbnail})`}}>
...
</div>
...
);
}
The client is initialized in a wrapper component like so:
window.gapi.load('client:auth2', () => {
window.gapi.client.init({
apiKey: developerKey,
clientId: clientId,
scope: 'https://www.googleapis.com/auth/drive'
}).then(() => {
window.gapi.client.load('drive', 'v3', () => {
if(props.onGapisLoad) props.onGapisLoad();
setInitialized(true);
});
});
});
However, the window.gapi.client.request call gives Failed to load resource: the server responded with a status of 404, and the URL that's actually giving this error is the proxy request https://docs.google.com/static/proxy.html?usegapi=1&.... Using fetch also doesn't work, as it gives a CORS error. Meanwhile, if I try to access the thumbnailLink in the browser while signed in to the correct Google account (and no other accounts), I can see the image without a problem.
What would be the proper way to load thumbnails through an authorized request? I've seen other answers that recommend generating a PDF and using it to create a public thumbnail, but I'd like to avoid creating extra files in the user's drive or making file data publicly accessible. And since the image can be loaded directly from the browser, I would assume there's a way to access it with an authorized client.
I am learning React and want to create an application with Symfony4 as my backend and React frontend. I am stuck now when I need to pass some kind of data to the frontend from my backend. I don't really know what is the right way to do it? Following some tutorials I am doing it like this:
From the controller I send some data to the twig file:
/**
* #Route("/")
*/
public function homepage()
{
$date = new DateTime();
$curr_date = $date->format('Y-m-d H:i:s');
return $this->render('base.html.twig', [
'gameDate' => $curr_date
]);
}
In the twig file, I set it as a data-attribute
base.html.twig:
<div id="root" data-event-date="{{ gameDate }}">
Then I can get the variable as a dataset in my JavaScript
App.js:
const root = document.getElementById('root');
ReactDOM.render(<Homepage {...(root.dataset)}/>, root);
And render it from props.
Homepage.js:
class Homepage extends Component {
constructor(props) {
super(props)
this.state = {
prizePool: '',
gameDate: '',
numberOfPlayers: ''
}
}
onParticipateClick = (event) => {
this.setState({prizePool: Math.random()})
}
render()
{
return (
<div className="mt-c-10">
<GameInfoBox gameDate={this.props.eventDate}/>
</div>
)
}
}
This actually works, but I am concerned with showing all the information in data variables because anyone can see it. What if I want to pass user ID or something secret? There should be another way to do it right?
It depend on what you attemps, if you are working on big project, you can use API to serve backend data. Take a look here: https://www.modernjsforphpdevs.com/react-symfony-4-starter-repo/. There is a simple example.
But if you want something more use api-platform or FOSRestBundle.
"Best and safest" is a little ambiguous - do you need strict security, or safe as in code stability etc?
Instead of passing your data from controller to view (twig) and then into HTML elements or global, another way is this:
Controller loads the view file with your nav and other stuff
Controller loads React (however you do this, Webpack etc)
React calls another controller (i.e. fetch()). This controller is probably somewhere like src/Api/Controller/ as it wont render a view so keep it separate to the other controllers which do render a view
The API controller calls your DB or remote API (etc) and gets the data and sends it back as JsonResponse back to React.
React can then show the data, or an error message depending on the response status
The API controller in your MW can also handle errors and do some logging, so React just gets a 200 and the data or a 400 (or whatever) and it can show a nice message to the user as normal.