Skip to content

Commit

Permalink
Feat: add dynamic sitemap
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-sumi-k committed Feb 21, 2024
1 parent c0dceb6 commit c942015
Show file tree
Hide file tree
Showing 13 changed files with 804 additions and 204 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/deploy-frontend-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ jobs:
sed -i "s|VITE_RECAPTCHA_SITE_KEY_VALUE|${{ secrets.RECAPTCHA_SITE_KEY }}|g" config.js
sed -i "s|RESOURCES_URL|${{ secrets.RESOURCES_URL }}|g" config.js
sed -i "s|CLOUDFRONT_URL_VALUE|${{ secrets.CLOUDFRONT_URL_VALUE_DEV }}|g" config.js
sh ./../deploy/generate-sitemap.sh https://dev-stack.canopas.com https://dev-stack-api.canopas.com
yarn install --frozen-lockfile && yarn build
cd .output/server && zip canopas_website_SSR_dev_${{ github.sha }}-${{ github.run_attempt }}.zip -r . && aws s3 cp canopas_website_SSR_dev_${{ github.sha }}-${{ github.run_attempt }}.zip s3://canopas-lambda-handlers && cd ../..
aws s3 rm s3://canopas-website-ssr-dev --recursive
aws s3 sync --cache-control 'max-age=604800' --exclude *.html ./.output/public s3://canopas-website-ssr-dev
aws s3 sync ./.output/public s3://canopas-website-ssr-dev
aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID_DEV }} --paths "/sitemap.xml"
- name: Deploy cloudformation stack
id: canopas-website-dev-lambda-stack-frontend
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/deploy-frontend-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
workflows: ["DeployBackendProd"]
types:
- completed
branches:
branches:
- "master"

jobs:
Expand Down Expand Up @@ -35,12 +35,11 @@ jobs:
sed -i "s|RESOURCES_URL|${{ secrets.RESOURCES_URL }}|g" config.prod.js
sed -i "s|CLOUDFRONT_URL_VALUE|${{ secrets.CLOUDFRONT_URL_VALUE_PROD }}|g" config.prod.js
mv config.prod.js config.js
sh ./../deploy/generate-sitemap.sh https://canopas.com https://prod-stack-api.canopas.com
yarn install --frozen-lockfile && yarn build
cd .output/server && zip canopas_website_SSR_prod_${{ github.sha }}-${{ github.run_attempt }}.zip -r . && aws s3 cp canopas_website_SSR_prod_${{ github.sha }}-${{ github.run_attempt }}.zip s3://canopas-lambda-handlers && cd ../..
aws s3 rm s3://canopas-website-ssr-dev --recursive
aws s3 sync --cache-control 'max-age=604800' --exclude *.html ./.output/public s3://canopas-website-ssr-prod
aws s3 sync ./.output/public s3://canopas-website-ssr-prod
aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID_PROD }} --paths "/sitemap.xml"
- name: Deploy cloudformation stack
id: canopas-website-prod-lambda-stack-frontend
Expand All @@ -52,5 +51,5 @@ jobs:
timeout-in-minutes: "10"
no-fail-on-empty-changeset: "1"
parameter-overrides: >-
EnvName=prod,
ZipFileName=canopas_website_SSR_prod_${{ github.sha }}-${{ github.run_attempt }}.zip
EnvName=prod,
ZipFileName=canopas_website_SSR_prod_${{ github.sha }}-${{ github.run_attempt }}.zip
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ You can also check out [website](https://canopas.com/) to view a live example of

3. **Server Side Rendering:** We have used Nuxt's different rendering modes for the website. For static pages, its SSG and for dynamic pages, we used SSR/ISR.

4. **SEO-friendly URLs and Metadata:** We prioritize SEO best practices to ensure that canopas website receive the visibility they deserve in search engines. From meta tags to URL structure and sitemaps, canopas website is equipped with all the essential elements for optimal SEO.
4. **SEO-friendly URLs and Metadata:** We prioritize SEO best practices to ensure that canopas website receive the visibility they deserve in search engines. From meta tags to URL structure and dynamic sitemaps, canopas website is equipped with all the essential elements for optimal SEO.

5. **Responsive and Mobile-friendly Design:** We understand the importance of a mobile-friendly design in modern SEO. Canopas website is fully responsive and adapts seamlessly to various screen sizes, providing a positive user experience across devices.

Expand Down
70 changes: 32 additions & 38 deletions api-doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,44 +259,38 @@
- Status Code: 200 Ok
- Headers : none
- Data :
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://canopas.com</loc>
<changefreq>monthly</changefreq>
<lastmod>2022-03-01T00:00:00.000Z</lastmod>
<priority>1</priority>
</url>
<url>
<loc>http://canopas.com/jobs</loc>
<changefreq>monthly</changefreq>
<lastmod>2022-03-01T00:00:00.000Z</lastmod>
<priority>1</priority>
</url>
<url>
<loc>http://canopas.com/contact</loc>
<changefreq>monthly</changefreq>
<lastmod>2022-03-01T00:00:00.000Z</lastmod>
<priority>0.9</priority>
</url>
<url>
<loc>https://blog.canopas.com</loc>
<changefreq>monthly</changefreq>
<lastmod>2022-03-01T00:00:00.000Z</lastmod>
<priority>0.8</priority>
</url>
<url>
<loc>http://canopas.com/jobs/ios-developers-a9b45f34-a1a5-419f-b536-b7c290925d6d</loc>
<changefreq>monthly</changefreq>
<lastmod>2022-03-01T00:00:00.000Z</lastmod>
<priority>0.9</priority>
</url>
<url>
<loc>http://canopas.com/jobs/apply/ios-developers-a9b45f34-a1a5-419f-b536-b7c290925d6d</loc>
<changefreq>monthly</changefreq>
<lastmod>2022-03-01T00:00:00.000Z</lastmod>
<priority>0.9</priority>
</url>
</urlset>
[
{
"loc": "/services",
"changefreq": "monthly",
"lastmod": "2024-02-01T00:00:00.000Z",
"priority": "0.9"
},
{
"loc": "/portfolio",
"changefreq": "monthly",
"lastmod": "2024-02-01T00:00:00.000Z",
"priority": "0.9"
},
{
"loc": "/contributions",
"changefreq": "monthly",
"lastmod": "2024-02-01T00:00:00.000Z",
"priority": "0.9"
},
{
"loc": "/resources",
"changefreq": "monthly",
"lastmod": "2024-02-01T00:00:00.000Z",
"priority": "0.9"
},
{
"loc": "/blog",
"changefreq": "monthly",
"lastmod": "2024-02-01T00:00:00.000Z",
"priority": "0.9"
},
]
```

### 6. Send New Leave Request mail
Expand Down
19 changes: 16 additions & 3 deletions nuxt-frontend/nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,19 @@ export default defineNuxtConfig({
"nuxt-icon",
"@canopassoftware/blog-components",
"nuxt-lazy-hydrate",
"@nuxtjs/sitemap",
],
site: {
url: config.BASE_URL,
},
sitemap: {
defaults: {
lastmod: new Date(),
},
sources: [config.API_BASE + "/api/sitemap"],
xsl: false,
xslTips: false,
},
css: ["~/assets/css/global.css", "~/assets/css/app.css"],
generate: { fallback: true },
imports: {
Expand All @@ -43,15 +55,16 @@ export default defineNuxtConfig({
"/": { prerender: true },
"/services": { prerender: true },
"/portfolio": { prerender: true },
"/portfolio/**": { prerender: true },
"/contributions": { prerender: true },
"/about": { prerender: true },
"/contact": { prerender: true },
"/android-app-development": { prerender: true },
"/ios-app-development": { prerender: true },
"/mobile-app-development": { prerender: true },
"/backend-app-development": { prerender: true },
"/flutter-app-development": { prerender: true },
"/frontend-development": { prerender: true },
"/backend-development": { prerender: true, sitemap: !config.IS_PROD },
"/flutter-app-development": { prerender: true, sitemap: !config.IS_PROD },
"/frontend-development": { prerender: true, sitemap: !config.IS_PROD },
"/thank-you": { prerender: true },
"/unsubscribe": { prerender: true },
},
Expand Down
1 change: 1 addition & 0 deletions nuxt-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@canopassoftware/blog-components": "^1.2.4",
"@ivanv/vue-collapse-transition": "^1.0.2",
"@nuxt/devtools": "latest",
"@nuxtjs/sitemap": "^5.1.0",
"@types/lozad": "^1.16.4",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-eslint": "^5.0.8",
Expand Down
22 changes: 11 additions & 11 deletions nuxt-frontend/pages/author/[slug].vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
<template>
<div>
<Header />
<section v-if="slug !== ''" class="container min-h-[50vh]">
<div class="md:mx-8 xl:mx-20">
<section class="container min-h-[50vh]">
<div
v-if="status == config.NOT_FOUND"
class="h-1/2 flex text-[1.4rem] text-black-900 items-center justify-center"
>
{{ config.POST_NOT_FOUND_MESSAGE }}
</div>
<div v-else class="md:mx-8 xl:mx-20">
<nuxt-link :to="'/author/' + slug" class="flex space-x-4 items-center">
<div class="w-8 h-8 md:w-9 md:h-9">
<Icon
Expand Down Expand Up @@ -50,15 +56,16 @@ const slug = ref(route.params.slug);
const posts = ref([]);
const store = useAuthorListStore();
const resources = computed(() => store.items);
const count = computed(() => store.totalPosts);
const status = computed(() => store.status);
let postLimit = 10;
await useAsyncData("authors", () =>
store.loadAuthorBlogs(config.SHOW_DRAFT_POSTS, slug.value, 0, postLimit),
);
posts.value = resources.value?.slice(0, postLimit);
if (status.value === config.SUCCESS) {
posts.value = resources.value?.slice(0, postLimit);
}
const handleScroll = () => {
if (
Expand All @@ -79,13 +86,6 @@ onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
if (status.value !== config.SUCCESS) {
navigateTo({
name: "Error404Page",
params: { pathMatch: ["author", slug.value] },
});
}
useSeoMeta({
title: "Stories by " + slug.value + " | Canopas",
ogTitle: "Stories by " + slug.value + " | Canopas",
Expand Down
20 changes: 10 additions & 10 deletions nuxt-frontend/pages/tag/[slug].vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
<template>
<div>
<Header />
<div
v-if="slug == '' || status == config.NOT_FOUND"
class="h-1/2 flex text-[1.4rem] text-black-900 items-center justify-center"
>
{{ config.POST_NOT_FOUND_MESSAGE }}
</div>
<section
v-if="slug !== ''"
v-else
class="container min-h-[50vh] my-10 md:my-16 sm:mx-auto 3xl:px-24"
>
<div class="md:mx-8 xl:mx-20">
Expand Down Expand Up @@ -42,13 +48,14 @@ const slug = ref(route.params.slug);
const posts = ref([]);
const store = useTagListStore();
const resources = computed(() => store.items);
const count = computed(() => store.totalPosts);
const status = computed(() => store.status);
let postLimit = 2;
await useAsyncData("tags", () => store.loadTagBlogs(slug.value, 0, postLimit));
posts.value = resources.value?.slice(0, postLimit);
if (status.value === config.SUCCESS) {
posts.value = resources.value?.slice(0, postLimit);
}
const tagName = posts.value[0].tags.filter((tag) => tag.slug === slug.value)[0]
.name;
Expand All @@ -72,13 +79,6 @@ onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
if (status.value !== config.SUCCESS) {
navigateTo({
name: "Error404Page",
params: { pathMatch: ["tag", slug.value] },
});
}
useSeoMeta({
title: "Stories on " + slug.value + " | Canopas",
ogTitle: "Stories on " + slug.value + " | Canopas",
Expand Down
36 changes: 23 additions & 13 deletions nuxt-frontend/stores/author/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const useAuthorListStore = defineStore("authors", {
},
actions: {
async loadAuthorBlogs(showDrafts, slug, start, limit) {
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
this.isLoading = true;
this.error = null;

Expand All @@ -36,22 +36,32 @@ export const useAuthorListStore = defineStore("authors", {
limitQuery;

axios
.get(url)
.then((response) => {
let posts = [];
response.data.data.forEach((post) => {
posts.push(setPostFields(post));
});
this.items = posts;
this.isLoading = false;
this.status = posts.length > 0 ? response.status : config.NOT_FOUND;
resolve();
.get(config.STRAPI_URL + "/favicon.ico")
.then(() => {
axios
.get(url)
.then((response) => {
let posts = [];
response.data.data.forEach((post) => {
posts.push(setPostFields(post));
});
this.items = posts;
this.isLoading = false;
this.status =
posts.length > 0 ? response.status : config.NOT_FOUND;
resolve();
})
.catch((error) => {
this.error = error;
this.isLoading = false;
this.status = config.NOT_FOUND;
resolve();
});
})
.catch((error) => {
this.error = error;
this.isLoading = false;
this.status = config.NOT_FOUND;
resolve();
reject(error);
});
});
},
Expand Down
38 changes: 23 additions & 15 deletions nuxt-frontend/stores/tags/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const useTagListStore = defineStore("tag-list", {
},
actions: {
async loadTagBlogs(slug) {
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
this.isLoading = true;
this.error = null;

Expand All @@ -23,24 +23,32 @@ export const useTagListStore = defineStore("tag-list", {
"/v1/tag/" +
slug +
"?populate=deep&publicationState=live";

axios
.get(url)
.then((response) => {
let posts = [];
response.data.data.forEach((post) => {
posts.push(setPostFields(post, slug));
});
this.items = posts;
this.isLoading = false;
this.status = posts.length > 0 ? response.status : config.NOT_FOUND;
resolve();
.get(config.STRAPI_URL + "/favicon.ico")
.then(() => {
axios
.get(url)
.then((response) => {
let posts = [];
response.data.data.forEach((post) => {
posts.push(setPostFields(post, slug));
});
this.items = posts;
this.isLoading = false;
this.status =
posts.length > 0 ? response.status : config.NOT_FOUND;
resolve();
})
.catch((error) => {
this.error = error;
this.isLoading = false;
this.status = config.NOT_FOUND;
resolve();
});
})
.catch((error) => {
this.error = error;
this.isLoading = false;
this.status = config.NOT_FOUND;
resolve();
reject(error);
});
});
},
Expand Down
Loading

0 comments on commit c942015

Please sign in to comment.