What is nextJS getStaticPaths performance? - next.js

I want to create a bunch of static pages, but I am not sure that next.js is up to it. Gatsby, with default settings, drops dead.
I have 3 types of data I want to show respectively generating 15 / 50 / 150 k of pages
Later one (150k), I expect,to be rebuild each day.
Will nextJS handle that? Are there any time estimates I can take a look?
If I understand correctly
export async function getStaticPaths() {
// Call an external API endpoint to get cities
const res = await fetch('https://.../cities')
const cities = await res.json()
// Get the paths we want to pre-render based on cities
const paths = cities.map((post) => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false }
}
instead of doing one call, I will have to call fetch repeatedly until I will have all the data in one variable, but I am a bit afraid that everything will crash.
What are your thoughts, guys?
UPD
https://static-tweet.now.sh/ that should be my answer

Related

NuxtJS store returning local storage values as undefined

I have a nuxt application. One of the components in it's mounted lifecycle hook is requesting a value from the state store, this value is retrieved from local storage. The values exist in local storage however the store returns it as undefined. If I render the values in the ui with {{value}}
they show. So it appears that in the moment that the code runs, the value is undefined.
index.js (store):
export const state = () => ({
token: process.browser ? localStorage.getItem("token") : undefined,
user_id: process.browser ? localStorage.getItem("user_id") : undefined,
...
Component.vue
mounted hook:
I'm using UserSerivce.getFromStorage to get the value directly from localStorage as otherwise this code block won't run. It's a temporary thing to illustrate the problem.
async mounted() {
// check again with new code.
if (UserService.getFromStorage("token")) {
console.log("user service found a token but what about store?")
console.log(this.$store.state.token, this.$store.state.user_id);
const values = await ["token", "user_id"].map(key => {return UserService.getFromStorage(key)});
console.log({values});
SocketService.trackSession(this, socket, "connect")
}
}
BeforeMount hook:
isLoggedIn just checks that the "token" property is set in the store state.
return !!this.$store.state.token
beforeMount () {
if (this.isLoggedIn) {
// This runs sometimes??? 80% of the time.
console.log("IS THIS CLAUSE RUNNING?");
}
}
video explanation: https://www.loom.com/share/541ed2f77d3f46eeb5c2436f761442f4
OP's app is quite big from what it looks, so finding the exact reason is kinda difficult.
Meanwhile, setting ssr: false fixed the errors.
It raised more, but they should probably be asked into another question nonetheless.

Where should I store JSON file and fetch data in Next.JS whenever I need?

Project:
I am working on an E-commerce application and it has more than 1,600 products and 156 categories.
Problem:
Initially, on the first product page, 30 products will be fetched (due to the page limitation), but on the left sidebar, I need filters that will be decided on the basis of tags of all 1,600 products. So that's why I need all the products in the first fetch and then I will extract common tags by looping over all the products and immediately show them on the sidebar.
What do I want?
I am not sure but I think it would be the best solution if I generate a JSON file containing all the products and store it somewhere, where I can fetch just hitting the URL using REST API in Next JS (either in getServerSideProps or getStaticProps).
Caveat:
I tried by storing JSON file in ./public directory in next js application, it worked in localhost but not in vercel.
Here is the code I wrote for storing JSON file in ./public directory:
fs.writeFileSync("./public/products.json", JSON.stringify(products, null, 2)); //all 1,600 products
One solution it to fetch it directly from front-end (if the file is not too big) otherwise, for reading the file in getServerSideProps you will need a custom webpack configuration.
//next.config.js
const path = require("path")
const CopyPlugin = require("copy-webpack-plugin")
module.exports = {
target: "serverless",
future: {
webpack5: true,
},
webpack: function (config, { dev, isServer }) {
// Fixes npm packages that depend on `fs` module
if (!isServer) {
config.resolve.fallback.fs = false
}
// copy files you're interested in
if (!dev) {
config.plugins.push(
new CopyPlugin({
patterns: [{ from: "content", to: "content" }],
})
)
}
return config
},
}
Then you can create a utility function to get the file:
export async function getStaticFile(file) {
let basePath = process.cwd()
if (process.env.NODE_ENV === "production") {
basePath = path.join(process.cwd(), ".next/server/chunks")
}
const filePath = path.join(basePath, `file`)
const fileContent = await fs.readFile(filePath, "utf8")
return fileContent
}
There is an open issue regarding this:
Next.js API routes (and pages) should support reading files

getStaticProps in dynamic routes in Next.js

I use getStaticProps in a Next.js page.
export const getStaticProps = wrapper.getStaticProps(async ({ store }) => {
store.dispatch(getInfoRequest());
store.dispatch(END);
await store.sagaTask.toPromise()
});
This is a dynamic route.
An when I refresh the page I get:
Error: getStaticPaths is required for dynamic SSG pages and is missing for '/dates/[[...info]]'.
Read more: https://err.sh/next.js/invalid-getstaticpaths-value
Why does this error happen?
It looks like you've forgotten to add getStaticPaths function to your page. Both are required when statically-generating pages for dynamic routes.
Since dynamic routes include parameters that could be anything, Next.js needs to know what concrete paths to generate at build time. This is why you need to export getStaticPaths which should include in its return value a list of string paths with the placeholders replaced with real values.
So, for instance, if your dynamic route is /user/[id], then getStaticPaths might return:
{
paths: [
'/user/1',
'/user/2',
'/user/3'
],
fallback: true
}
You may want to generate these paths dynamically at build time, which you can totally do within getStaticPaths. So, given you've elsewhere created a function called getUsers, it might look like this:
export async function getStaticPaths() {
const users = getUsers();
return {
paths: users.map((u) => `/user/${u.id}`),
fallback: true
}
}
For more information see the documentation.

Is There Any Way to Pass Both ID and Slug from getStaticPaths to getStaticProps [nextjs]

I want to set my URL's as slugs in my next.js app, but also need to pass the itemID to getStaticProps in order to get the data I need from my API.
How can I pass both ID and slug from getStaticPaths to getStaticProps rather than one or the other?
export async function getStaticPaths() {
const paths = items.map(item => (
{ params: { id: item.itemID }}
))
return {paths, fallback: false}
}
I was hoping to do something like this:
const paths = items.map(item => ({
params: {
id: item.itemID,
title: item.description
}
}))
I believe you can find the answer to your question in this blog example from Next.js. They call getStaticPaths() first to get a list of all paths, and then pass that information over to getStaticProps() to get data for each of the paths. Since the data is generated at build time, I believe Nextjs gets all your pages built and ready to serve in one go.

Nextjs export clear "out" folder

I'm working with nextjs and this example https://github.com/zeit/next.js/tree/master/examples/with-static-export
in next.config.js i have code:
module.exports = {
async exportPathMap(defaultPathMap, { dev, dir, outDir, distDir, buildId, incremental }) {
// we fetch our list of posts, this allow us to dynamically generate the exported pages
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts?_limit=3'
)
const postList = await response.json()
// tranform the list of posts into a map of pages with the pathname `/post/:id`
const pages = postList.reduce(
(pages, post) =>
Object.assign({}, pages, {
[`/post/${post.id}`]: { page: '/post/[id]' },
}),
{}
)
// combine the map of post pages with the home
return Object.assign({}, pages, {
'/': { page: '/' },
})
},
}
Its fetch 3 posts and generate files - [id].html - its great!
But now i need to fetch new post and build page only for this new post but commad next export remove all files from out and create only one post.
What i need to do to keep old post and add new one on next export?
Example:
First next export with request for 3 posts from api
generate 3 post in folder "out"
change api url and run next export for 1 new post
summary i have 3 old post pages and 1 new in my "out" directory
How to do that?
Next can't do this out of the box, but you can set it up to do so. First, you'll need a system (database) of which pages have already been built. Second, you'll need some method of communicating with that database (api) to ask which pages should be built (eg, send over a list of pages and the api responds telling you which ones have not yet bene built). Then, tell your exportPathMap which pages to build. And finally, move your built pages out of out and into a new final/public directory.
By default, Next will build/export anything in the pages directory plus anything you set in exportPathMap, and put all of those in the out directory. You can override what it builds by passing a custom exportPathMap, and how you handle what goes into the out directory is up to you, so you can move those files to a different actual public directory and merge them with the old files.

Resources