How to client-side routing url that ends with file extension - javascript

Say a user gives the title of a note as 'onboarding.md'.
And the url ends up like this localhost:4000/ecme/onboarding.md.
Now upon a refresh with that url, I want my client-side router to handle it - load a component, calls an api via fetch, then loads the result into the component.
But I get a blank page with an error Cannot GET /ecme/onboarding.md.
No such error if I programmatically navigate to the note.

You can't, at least not really.
If the user is refreshing the page then the browser is asking the server for that URL.
Your client-side router hasn't even been loaded.
When you use client-side routing with "real" URLs (as opposed to hash-routing where all the route data is kept in the fragment identifier) then you must have server-support too.
Good router support would use server-side rendering so the page would be delivered complete from the server instead of being generated client side. This is efficient (no need to serve a bootstrap page and then have the client do all the work and making additional HTTP requests for data), search engine friendly, and means that if JS fails for any reason then the page will still be accessible.
There are frameworks to support this for most common SPA frameworks (e.g. React has Next.js).
The quick and dirty approach if you want to around SSR is to just configure the server to serve up the bootstrap HTML document that runs the client-side code for every URL it is asked for (or at least those not associated with a file). This doesn't have the benefits listed above and also ends up giving clients (including search engines) an HTML document even whey they should get a 404 Not Found error.

Related

I have trouble entering URLs in the address bar when creating routes with vanila javascript

I am trying to create routes with vanilla javascript but every time I type a URL in the address bar I get an error saying, 'Cannot GET /about'. I am requesting a link to a tutorial or an answer to this kind of problem since it is my first time doing it with vanilla javascript and I have no clue.
Taking "Vanilla JavaScript" to mean "JavaScript, running in the browser, without the use of third-party libraries":
What you want is not (reasonably) possible.
When you type a URL into the address bar, the browser makes an HTTP request to that URL, and the HTTP server for the origin of the URL (i.e. the scheme + hostname + port) is responsible for delivering something (typically a webpage) back to the client.
You can't substitute client-side JavaScript for that initial request to the HTTP server.
There is an edge case. I think a progressive web app can use a service worker to intercept the request and generate a response internally. This is no good for handling the initial request though since the PWA wouldn't be installed at the time.
Generally, when you are writing a single page application you will need two parts for your URL handling.
The first part is the History API. This allows you to write JavaScript which tells the browser:
In response to the click the user just performed, I am going to update the DOM. If you were to visit this URL then you would get the same result as the changes I am making to the DOM, so go ahead and update the address bar to represent that.
It also lets you hook into the browser's back navigation so you can undo those changes if the user click's back.
The second part is where you make sure that the server really does deliver the same content for that other URL.
There are three strategies for achieving this:
Have the server return a more-or-less empty HTML document that checks the URL as it loads and then populates itself entirely with JavaScript. This is a poor approach which might as well just use hash bangs.
Generate all the HTML documents in advance. This is a strategy employed by Gatsby and Next.js. This is very efficient, but doesn't work for frequently updated content.
Generate the HTML documents on demand with server side code. Next.js can do this too.
You can do this when you write vanilla JavaScript (kinda), but it takes a lot of work since you need to write all the code to run on Node.js (where you might not count it as vanilla any more) to generate the HTML documents. I strongly recommend using a framework.

How do I correctly deal with 404 HTTP errors when using an SPA and no server-side computation?

I am currently using Vue.js on a website project of mine.
The server that returns this Vue.js SPA will not be capable of computation or checks, and will only serve the static resources required to run the SPA in the browser, where all computation will then take place.
For SEO purposes, I want to ensure error pages are handled correctly. Currently, every URL returns a 200 OK and serves the SPA which can confuse search engines for pages that are actually supposed to be invalid. What would be the correct way of telling both users and search engines that the page is invalid if I cannot change the response the server provides?
For context, the SPA will get data from an API on another domain.
I have looked at other questions that are similar, but they normally recommend server-side checks, a dedicated 404-page redirect or a soft-404 page. Server-side checks and a dedicated 404 page will not be possible, and I have read that soft-404 pages are disliked by search engines.
Is there any proper way to go about this?
I have seen this post, but it is quite old and only suggests a no-index tag, which still makes the page valid in the eyes of search engines, just not indexable.
You can't return a 404 error without any server-side computation/rendering, because the fact that the resource/page wasn't found relies on some logic that only gets executed on the client-side in your case. Hence, your only options are the following:
If the resource wasn't found, redirect the user to a pre-defined 404 page (that returns the correct HTTP status)
Blacklist paths that are invalid inside your proxy, or whitelist those that are valid, and proxy to a 404 page on all other paths
Manually create a sitemap with your valid pages/routes
None of these options are optimal if your project grows or you have dynamic routes, but those are the limitations of client-side rendering. Hence I don't think there's a good answer to your question, since this is a well-known limitation of client-side rendering, and one of the main reasons why projects that care about SEO prefer server-side rendering.
From an SEO perspective: As long as you add all your valid pages to a sitemap, and don't link (anchor tag) to the invalid ones on any of your other pages, no search engine crawler will ever crawl or index these pages.
But if you really care about SEO and have a dynamic app with hundreds/thousands of dynamic links that cannot be added to a sitemap manually, I'd advise you to switch to a production framework like Nuxt.js or Next.js because they offer what you're looking for and much other SEO features out of the box.

Single page web app (SPA) link/refresh routing design considerations and caching

What is the recommended practice of sending the SPA code to the client with routing considerations? How to send the SPA code to the client when they go directly to a link (e.g. website.com/users/user1) rather than the root path first.
An example best illustrates the question:
The path website.com/users/user1 responds with some application/JSON so that the SPA can fill in the layout with the information.
Let's say that you have a basic SPA and you are making a request on website.com/users/user1 (assume no auth is required) without having first visited the root path where it is clear that we can send the SPA code (html, css, javascript) to the client and then they can make their requests to the different routes through the web app. So the user visits websitename.com/users/user1 and the server doesn't know whether the client needs all of the SPA code first or just the JSON (maybe the most recent version is cached, or they are visiting website.com/users/user1 after having first visited website.com/ which knows to make a specific request to the server and ask for the JSON).
How is this typically handled? Is a flag, date, or something else sent to the webserver with the SPA so that the server knows the client has the SPA code? This could be done via the SPA requesting a content type of application/json on the route rather than a standard GET request? Or setting a header that the SPA sends back denoting its most recent version (this way we can use caching and if it isn't the most recent, or there is no SPA yet, a new version may be sent).
How is it recommended that the SPA handle this? Does the SPA check the URI and note that it has only just received the SPA code from the server and not the actual content from the server (e.g., user1's information). And how is it recommended that we check this? The server sends back the SPA code and sets a header denoting that the SPA needs to make another request to website.com/user/user1 to actually retrieve the actual JSON of user1's info rather than the SPA code.
EDIT: I have eventually come across this SO question and the answer more or less addresses all of my questions: How to make a SPA SEO crawlable? There are obviously many ways to handle this on both client and server side and I wanted to see the different ways people addressed the issue. (I like the way that the aforementioned question/answer deals with the issue and will likely use a similar scheme.)
I don't know what your stack is, and I can't really speak to recommended practices, but I use webpack for this. In webpack, you accomplish this by defining multiple entry points. This splits your code into different self-contained packs, so you can have different .html files that produce different code bundles.
Adapting your situation to the appropriate webpack config:
{
entry: {
main: "./index
user1: "./users/user1",
},
output: {
path: path.join(__dirname, "dist"),
filename: "[name].entry.js"
}
}
Then, in the appropriate html, you'd load user1.entry.js
I am not sure how extensible this is for a situation where each of your users has their own dedicated URL (obviously you can't name a unique entry point for hundreds of users), but at that point I'm not sure what you have is technically an SPA.
You can also consider using a routing solution similar to react-router, which allows you to grab data from the URL. eg, w/ a webpack config like above, navigating to example.com/users/user1:
users.html/users.js:
loadJSONFromServer({url-user-id})
I believe what you are asking is, how does a user visit a page that is not the home page (maybe through a link that was shared) and the app get the data it is supposed to display on that page.
They way I typically accomplish this is to initiate a data fetch in the lifecycle method componentDidMount that evaluates what data is already present, and fills in the missing pieces. You could accomplish something similar through react-router's onEnter hook (which is how I handle user auth in an SPA).

Disable Angular routing, just for first request (when sending pre-rendered html)?

I'm trying to make my angular app/website as SEO-friendly as possible.
It's based on the angular-fullstack generator (Yeoman) and I'd like the initial request to serve completely pre-rendered HTML for two reasons.
Search engines will see the page as end-users would once rendered.
It saves making extra requests to the server('s API's) for data, which can just be sent in that initial request.
I've seen the services that can detect and send crawlers a different URL (which only renders static HTML), but was wondering if there was a simpler/more DRY way of doing what I want before going down that route.
If I serve the pre-rendered HTML with the rest of my angular code, it works fine, but the page is instantly reloaded as angular's router parses the route and loads it's templates. Some way to disable the angular router from initializing until a route is requested would work (rather than immediately parsing the URL on app initialization). Is that possible?

Precomputing Client-side Javascript Execution

Suppose you were to build a highly functional single-page client-side application that listens to URL changes in order to navigate around the application.
Suppose then, that when a user (or search engine bot) loads a page by its url, instead of delivering the static javascript file and hits the api as normal, we'd like to precompute everything server-side and delivery the DOM along with the js state.
I am wondering if there are existing tools or techniques for persisting such an execution of state to the client.
I know that I could execute the script in something like phantom JS and output the DOM elements, but then event handlers, controllers and the js memory state would not be attached properly. I could sniff our user agent and only send the precomputed content to bots, but I am afraid google would punish for this, and we also lose the speed benefits of having sent everything precomputed in the first place.
So you want to compile, server-side and send to the client the results of requesting a resource at a specific URL? What is your backend written in?
We have an API running on GAE in Java. Our app is a single-page app, and we use the HTML5 history object so we have to have "real responses" for actual URLs on the front-end.
To handle this we use JSP to pre-cache the data in the page as it's loaded from the server and sent to the client.
On the front end we use Backbone, so we modified Backbone.sync to look for a copy of the data it's looking for locally on the page and if it's not there, only then to request it from the server as an AJAX call.
So, yes, this is pretty much what every site did before you had ajax. The trick is writing your app so that the data can be local in the page (or in localStorage even) and if not only then to request the data. Then make sure your page is "built" on the server end (so we actually populate the data in the HTML elements on the server end so the page doesn't require JS on the client end).
If you go somewhere else the data is dynamic and the page doesn't reload.

Categories

Resources