Function onLoad in SPA Page - javascript

I have SPA page, all work very good but when user reload page beeing on winners or garage get info :
Cannot GET /Garage. Then have to pick default url. How to set reload function on current page.
https://darogawlik-async-race-api.netlify.app/ (my app)
const navigateTo = url => {
history.pushState(null, null, url)
router()
}
const router = async () => {
const routes = [
{ path: '/Garage', view: garage },
{ path: '/Winners', view: winners },
]
// Test each route for potential match
const potentialMatches = routes.map(route => ({
route,
isMatch: location.pathname === route.path,
}))
let match = potentialMatches.find(potentialMatches => potentialMatches.isMatch)
if (!match) {
match = {
route: routes[0],
isMatch: true,
}
}
const view = new match.route.view(document.querySelector('#main'))
}
window.addEventListener('popstate', router)
document.addEventListener('DOMContentLoaded', () => {
document.body.addEventListener('click', e => {
if (e.target.matches('[data-link]')) {
e.preventDefault()
navigateTo(e.target.href)
}
})
router()
})
window.addEventListener('load', router())

This will be a problem with default document handling in the web host - it is not a page load problem. Eg just click this link to get the problem:
https://darogawlik-async-race-api.netlify.app/Garage
Since you are using path based routing, your web host must serve the default document for all paths, including /Garage and /Winners. As an example, in Node.js Express you write code like this. For other web hosts you either write similar code or there is a configuration option that will do it for you.
// Serve static content for physical files, eg .js and .css files
expressApp.use('/', express.static());
// Serve the index.html for other paths
expressApp.get('*', (request, response) => {
response.sendFile('index.html');
}
According to this post on Netlify, you can add a file something like this. I'm no expert on this platform, but hopefully this gives you the info you need to resolve your issue:
[[redirects]]
from = "/*"
to = "/index.html"
status = 200

Related

Next.js i18n translate URL occurs 404 error?

I'm making a multilingual service using next-i18next.
I wanted some of my routes translate too for instance:
EN: /contact => default language
IT: /fa/ارتباط-با-ما => second language
For this purpose, I used translated URL routes by rewrites in my next.config.js file.
/** #type {import('next').NextConfig} */
const { i18n } = require('./next-i18next.config');
const nextConfig = {
i18n,
async rewrites() {
return [
{
source: '/ارتباط-با-ما',
destination: '/contact-us',
},
];
},
};
module.exports = nextConfig;
I created my navigation with this guide:‌ How to setup i18n translated URL routes in Next.js?
you can check out my code there https://stackblitz.com/edit/nextjs-thwgak
Problem:‌ Go to the home page then change the language to Farsi after that go to the contact page you see so far so good but when you reload the page on the contact page you get a 404 error.
Is this a bug or am I wrong? Where did I go wrong? Any idea?
ps question: what do rewrites affect SEO?
The word ارتباط-با-ما gets URL encoded when it reaches the Next.js server, so you have to also encode your source value accordingly for it to match the rewrite rule.
const nextConfig = {
async rewrites() {
return [
{
source: `/fa/${encodeURIComponent('ارتباط-با-ما')}`,
destination: '/fa/contact-us',
locale: false
}
];
}
};

How to use function of module in none module js file - Vanilla JS

I am new to modules in javascript, I am trying to use function from module in none module js file - function.
I am making Vanilla Js SPA.
In the bottom of - Index.html
<script type="module" src="static/js/index.js"></script>
I want to use this part in another js file in a function:
const navigateTo = url => {
history.pushState(null, null, url); // Add the url to the history APi of Js
router();
};
The module:
// Imports
import Dashboard from "./views/Dashboard.js";
import Posts from "./views/Posts.js";
import Settings from "./views/Settings.js";
import Register from "./views/Register.js";
import Login from "./views/Login.js";
import Profile from "./views/Profile.js";
// Navigator--------------------------------------------------------------------------------->
const navigateTo = url => {
history.pushState(null, null, url); // Add the url to the history APi of Js
router();
};
// Router------------------------------------------------------------------------------------>
const router = async () => {
const routes = [
{path: "/", view: Dashboard}, // On Path "/" use the dashboard class and inject html in the #app div
{path: "/posts", view: Posts },
{path: "/settings", view: Settings },
{path: "/Register", view: Register },
{path: "/Login", view: Login },
{path: "/Profile", view: Profile }
];
// Test each route for potential match ----------------------------------------------------->
// Get the current Url and check if its defined in routes method "Check if its one of our Spa Urls" ----------------------------------------------------->
const potentialMatches = routes.map(route => {
return {
route: route,
isMatch: location.pathname === route.path // true if match else false
};
});
// Check if there is Match------------------------------------------------------------------->
let match = potentialMatches.find(potentialMatch => potentialMatch.isMatch); // Get isMatch from potentialMatches
// If no match return to StartPage
if(!match)
{
match = {
route: routes[0],
isMatch: true
};
}
const view = new match.route.view(); // If match use the routes array of the router and get the view function for the route
document.querySelector("#app").innerHTML = await view.getHtml(); // Get the #app div and use the view function to inject Html in it from the view class ex."Dashboard, Posts, Settings etc."
await view.executeViewScript();
};
// On-Navigating-Back&Forth-Load the Content--Together with the url------------------------------------------------------------------------------------>
window.addEventListener("popstate", router); // On popstate "If back button is pressed" use the router array to load back the previeous SPA View
// Listen to document fully Loaded
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => { //Listen for click in the body
if(e.target.matches("[data-link]")){ // If body item was clicked and its data-link decorated
e.preventDefault(); // Prevent deafult behavior dont follow the link
navigateTo(e.target.href); // Navigate method
}
});
router(); // Load the content if the url is defined in our "Spa Urls"
});
//#### Client Routing END #####
This is working window.navigate('/');
But as #BERGI recommended I did all in modules and its working even better.

Next.js build process: static pages not generated - deployment fails

I'm trying to deploy my first next.js project on vercel. Locally everything is working.
My problem: When deploying (command: next build) the web app I get the message "Generating static sites (0/2000)" and then nothing happens. The deployment is cancelled after 1h (time expiration).
The problem is somewhere in the (simplified) code below. Here's why: when I deploy the project without the part that follows after const content the deployment is successful - so basically instead of having singleProductResponse AND contentResponse as props, I only have singleProductResponse..
I'm a little stuck and don't know how to solve this. Can someone tell me what I'm doing wrong? Thanks a lot!!
const Item = ({ singleProductResponse, contentResponse }) => {
const router = useRouter();
if (router.isFallback) {
return <div>Loading...</div>;
}
return (
<div className={styles.section}>
<Overview
singleProductResponse={singleProductResponse}
contentResponse={contentResponse}
/>
</div>
);
};
export async function getStaticPaths() {
const itemResponse = await knex("Items");
const paths = itemResponse.map((product) => ({
params: {
brand: product.brand,
item: product.item,
},
}));
return {
paths,
fallback: true,
};
}
export async function getStaticProps({ params }) {
try {
const itemData = await knex("Items").where(
"item",
"like",
`${params.item}`
);
const singleProductResponse = itemData[0];
//!!!!!!!!!when leaving the following part out: deployment is successful!!!!!!!!!!!!
const content = itemData[0].contentList;
const splitContent = content.split(", ");
const contentArray =
typeof splitContent === "string"
? [splitContent]
: splitContent;
const result = await knex("Cos")
.leftJoin("Actives", "Cos.content", "ilike", "Actives.content")
.leftJoin("Alcohol", "Cos.content", "ilike", "Alcohol.content")
.column([
"Cos.content",
"function",
"translationPlant",
"categoryAlcohol",
])
.where((qb) => {
contentArray.forEach((word) => {
qb.orWhere("Cos.content", word);
});
return qb;
});
return {
props: { singleProductResponse, contentResponse },
revalidate: 1,
};
} catch (err) {
console.log(err);
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
}
UPDATE
After digging deeper: I think the problem is that the part after const content is too slow in building process.
When running next build, as well as when deploying on vercel the building process stops after approx. 1h. I suppose this is because of the limit of 45min for building process.
The last message I get is "Generating static pages (1000/2000)" (in vercel and locally) and "Build failed" (vercel). I don't get any other error-messages (also not in the catch block).
I've already tried to optimize the part after const content (each table has an index (clustered indexes -> primary keys), I've redesigned the tables (only 4 tables to join, instead of 6), eliminated everything unnecessary in the query and checked that the database (postgres hosted on heroku - hobby-basic) is also in the US). The performance is better, but still not enough. Does anyone have some suggestions for improvement? TTFB might be a somehow slow.

How to make an SPA work with Electron with Vanilla JS, HTML, and CSS

I'm trying to make an Electron app with Vanilla, Javascript, CSS for the front end and I've read most Q&A's online that SPA is the way to go to have multiple pages in the app.
I have some ideas to implement it but don't really know if it's correct:
Create buttons that would hide/show some sections of the HTML. (Not entirely sure if this is SPA)
Use the router implementation in this video: https://www.youtube.com/watch?v=6BozpmSjk-Y
Here's a snippet of that implementation:
const router = async () => {
const routes = [
{ path: "/", view: Dashboard },
{ path: "/posts", view: Posts },
{ path: "/posts/:id", view: PostView },
{ path: "/settings", view: Settings }
];
// Test each route for potential match
const potentialMatches = routes.map(route => {
return {
route: route,
result: location.pathname.match(pathToRegex(route.path))
};
});
let match = potentialMatches.find(potentialMatch => potentialMatch.result !== null);
if (!match) {
match = {
route: routes[0],
result: [location.pathname]
};
}
const view = new match.route.view(getParams(match));
document.querySelector("#app").innerHTML = await view.getHtml();};
Although the only problem is when I type location.pathname in the console, Electron gives out the file path of the html and not the route exactly.
I'd appreciate if someone would share an example code or app the has been built with the same tech stack I'm using.

Generate new page after slug

I am building a NextJS application, currently I am using getStaticPaths and getStaticProps to build the static pages, doing the necessary requests for them.
So I want to build all the pages following this url: challenge/[slug]/ and for each slug that corresponds to an id I want to have a applications page like this: challenge/[slug]/applications to archive this I builded a file [...slug] inside /pages/challenge
Inside that file I have the following code to handle the static generation:
export async function getStaticPaths() {
const response: any = await getPrograms()
const paths = response.results.map(result => {
return { params: { slug: [result.id.toString()] } }
})
return { paths, fallback: true }
}
export async function getStaticProps({ params }) {
const res = await getProgram(params.slug[0])
const stages = await getStages(params.slug[0])
return { props: { program: res, stages: stages }, revalidate: 1 }
}
this solution works for /challenge/[slug], but the /challenge/[slug]/applications receives a 404, how can I render a specific application page for the slug?
I tried to add a second position to the slug array, but if I do it I can just render /challenge/[slug]/applications and not /challenge/[slug]
Any advice?
Thanks!
Firstly, You need to create a FOLDER named [slug]. Then, Create a FILE named applications.js. Lastly, copy and paste that code into this page.
__ challenge
|__ [slug]
|__ applications
In this page you can get or set slug as your desired parameter.

Categories