I have a Vue.js application up and running with Amazon S3 and Cloudflare.
When I open the index and browse to /dashboard, everything works fine. But when I open a route
I'm hosting a static PWA made in Vue on S3 using "Static website hosting" and it works as expected. What I did was quite simple - I've added this:
<RoutingRules>
<RoutingRule>
<Condition>
<HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
<ReplaceKeyWith></ReplaceKeyWith>
</Redirect>
</RoutingRule>
</RoutingRules>
To the Properties of the S3 bucket. See image below:
For my S3 bucket, everytime you try to access a file that doesn't exist you will receive a 403 (forbidden) instead of a 404. That is why I've changed the HttpErrorCodeReturnedEquals to 403. I've also replaced the ReplaceKeyWith with an empty string as "index.html" as not triggering the correct route.
I hope it helps.
Cheers, Alex
I know this answer comes late but in case someone else is looking for another way to solve this in cloudfront, there's no need to create custom pages on s3 redirecting users when pages are not found. Instead of doing it, custom error responses can be created in cloudfront for the distribution.
This will always redirect to /index.html
in case a file is not found and that will make the app route trigger.
I think this problem has two components:
1.
If a request is made directly (outside of the Javascript App) to a sub path such as /jobs then S3 returns a 404, because the path/object doesn't exist. The simplest way to fix this is from within S3 itself, where you redirect all error pages back to index.html.
However this doesn't work from a CDN such as Cloudfront, and presumably Cloudflare.
A good trick is to use files inside S3 that redirect users like this:
jobs/ -> /index.html jobs -> /index.html
For example if someone makes a request to site/ they will get the following html file:
"redirect":"<html><head><meta http-equiv=\"refresh\" content=\"0; url=http://example.com/site/index.html\" /></head>
<body>Redirecting to <a href=\"http://example.com/site/index.html\">Home</a></body></html>"
Secondly...
If I do it like that I just get my Header and Footer rendered but nothing more.
This is a problem I've had where the router-view doesn't initialise properly, even though the component that contains the router-view has loaded.
What I have done for now is redirect my router when the main "App" component is created:
created () {
console.log('route', this.$route.path)
this.$router.replace(this.$route.query.redirect || '/')
}
This has the added bonus of removing the index.html from your path (Which was put there by your new redirections) whilst forcing your router-view to render...
My #app component is the parent component, with a navbar, footer, and the router-view that renders all of the sub pages/components.
One way to make this work in with routing in history mode and without using CloudFront is to create the files that your URIs would point to. So let's say you use index.html as your entry point and have only one other page which you give path page2.html.
Then you should adapt your build and deploy process to do the following:
npm run build
)Note that the order of step 1 and 2 is important. This can be easily done in a script that publishes your website. I have just used this approach with the result I wanted; allowing refreshinag a page and opening links in a new tab.
Drawbacks I see is: - overhead of storing the copies of the files - have to make sure if you add a page not to forget to update your build and deploy scripts.
If you use static hosting on AWS S3 and this is SPA app (React, Vue, Angular etc) you should set index.html as error page: