From b03b585088c83604c18e1059a12d97fb469e0ccf Mon Sep 17 00:00:00 2001
From: Furkan MT <49978011+furcan@users.noreply.github.com>
Date: Thu, 22 Jul 2021 06:14:12 +0300
Subject: [PATCH] Sitemap generator has added.
- Routes has added.
- Constants has added.
- NextJS Config: exportPathMap by Routes.
---
.gitignore | 7 +-
next.config.js | 33 +++--
package.json | 13 +-
public/sitemap.xml | 27 ++++
public/sitemap.xsl | 212 +++++++++++++++++++++++++++++++
src/_database/database.i.ts | 1 +
src/_database/pages/about.md | 1 +
src/_database/pages/home.md | 1 +
src/components/meta/MetaTags.tsx | 6 +-
src/components/meta/Schema.tsx | 4 +-
src/constants/Constants.ts | 19 +++
src/helpers/Sitemap.ts | 175 +++++++++++++++++++++++++
src/pages/about/index.tsx | 4 +-
src/pages/home/index.tsx | 2 +-
src/routes/Routes.ts | 62 +++++++++
tsconfig.json | 9 ++
yarn.lock | 7 +
17 files changed, 557 insertions(+), 26 deletions(-)
create mode 100644 public/sitemap.xml
create mode 100644 public/sitemap.xsl
create mode 100644 src/constants/Constants.ts
create mode 100644 src/helpers/Sitemap.ts
create mode 100644 src/routes/Routes.ts
diff --git a/.gitignore b/.gitignore
index c42c3f7..48339b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,8 +14,13 @@
# production
/build
-/dist
/.build
+/dist
+/.dist
+
+# development
+/dev
+/.dev
# misc
.DS_Store
diff --git a/next.config.js b/next.config.js
index 86533bc..ada4d18 100644
--- a/next.config.js
+++ b/next.config.js
@@ -9,15 +9,16 @@
// Dependencies
const path = require('path');
const StylelintPlugin = require('stylelint-webpack-plugin');
-const package = require('./package.json');
+const { Constants } = require('./.dev/src/constants/Constants');
+const { Routes } = require('./.dev/src/routes/Routes');
-// Contstants: begin
-const appName = 'Notiflix';
-const appVersion = (JSON.stringify((package || {}).version) || '').replace(/"/gm, '') || 'v1.0.0';
+// Constants: begin
const isDev = process.env.NODE_ENV === 'development';
const isProd = process.env.NODE_ENV === 'production';
-const publicUrl = isProd ? (JSON.stringify((package || {}).homepage) || '').replace(/"/gm, '') : '';
-// Contstants: end
+const appUrl = isProd ? Constants.appUrl : '';
+const appName = Constants.appName;
+const appVersion = Constants.appVersion;
+// Constants: end
// Next Config: begin
const nextConfig = {
@@ -40,13 +41,13 @@ const nextConfig = {
env: {
isDev,
isProd,
- publicUrl,
+ appUrl,
appName,
appVersion,
},
// assets prefix
- assetPrefix: publicUrl,
+ assetPrefix: appUrl,
// extensions
pageExtensions: ['jsx', 'js', 'ts', 'tsx'],
@@ -75,15 +76,23 @@ const nextConfig = {
]
},
- // TODO:
exportPathMap: async (
defaultPathMap,
{ dev, dir, outDir, distDir, buildId }
) => {
- return {
+
+ let defaultPaths = {
'/': { page: '/home' },
- '/about': { page: '/about' },
- }
+ };
+
+ Routes?.filter(route => route.isActive && route.addToNextJSConfig)?.map(route => {
+ const routePath = {
+ [route.pathAs]: { page: route.pathPage },
+ };
+ defaultPaths = { ...defaultPaths, ...routePath };
+ });
+
+ return defaultPaths;
},
// Build ID
diff --git a/package.json b/package.json
index 52362c4..66ff0f1 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,16 @@
{
"name": "notiflix-documentation",
"homepage": "https://notiflix.github.io",
- "version": "3.0.1-beta.01",
+ "version": "1.0.0-beta.01",
"private": true,
"scripts": {
+ "sitemap:dev": "eslint src/constants/Constants.ts src/routes/Routes.ts src/helpers/Sitemap.ts",
+ "sitemap": "yarn sitemap:dev && tsc --resolveJsonModule --outDir .dev src/helpers/Sitemap.ts && node .dev/src/helpers/Sitemap.js",
"lint": "next lint",
- "dev": "next lint && next dev",
- "build": "next build",
- "start": "next start",
- "deploy": "next build && next export -o dist"
+ "dev": "yarn sitemap && next lint && next dev",
+ "build": "yarn sitemap && next build",
+ "start": "yarn sitemap && next start",
+ "deploy": "yarn build && next export -o dist"
},
"dependencies": {
"next": "11.0.1",
@@ -27,6 +29,7 @@
"stylelint-config-standard": "^22.0.0",
"stylelint-scss": "^3.19.0",
"stylelint-webpack-plugin": "^2.2.2",
+ "parse-md": "^2.0.4",
"typescript": "4.3.5"
},
"browserslist": {
diff --git a/public/sitemap.xml b/public/sitemap.xml
new file mode 100644
index 0000000..b094dea
--- /dev/null
+++ b/public/sitemap.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+ https://notiflix.github.io
+ 2021-07-22
+ daily
+ 1.0
+
+ https://notiflix.github.io/webapp/notiflix-og.jpg
+ Notiflix
+
+
+
+
+ https://notiflix.github.io/about
+ 2021-07-22
+ daily
+ 1.0
+
+ https://notiflix.github.io/webapp/notiflix-og.jpg
+ Notiflix
+
+
+
+
\ No newline at end of file
diff --git a/public/sitemap.xsl b/public/sitemap.xsl
new file mode 100644
index 0000000..b648853
--- /dev/null
+++ b/public/sitemap.xsl
@@ -0,0 +1,212 @@
+
+
+
+
+
+
+ Sitemap
+ SitemapIndex
+
+
+
+
+
+
+ Sitemap - Notiflix
+ Sitemap Index - Notiflix
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ URL |
+ LastChange |
+
+
+
+
+
+
+
+
+ second
+
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+ URL |
+ Images |
+ Priority |
+ Change Frequency |
+ Last Change |
+
+
+
+
+
+
+
+
+ second
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+
diff --git a/src/_database/database.i.ts b/src/_database/database.i.ts
index 9d3d1c5..e575757 100644
--- a/src/_database/database.i.ts
+++ b/src/_database/database.i.ts
@@ -21,6 +21,7 @@ interface IDatabaseSocialMedia {
}
interface IDatabaseMeta {
+ lastModifiedDate: string;
title: string;
description: string;
robots?: string | null;
diff --git a/src/_database/pages/about.md b/src/_database/pages/about.md
index 8e67af5..e95e854 100644
--- a/src/_database/pages/about.md
+++ b/src/_database/pages/about.md
@@ -1,5 +1,6 @@
---
_dbMeta:
+ lastModifiedDate: "2021-07-22" # YYYY-MM-DD
title: About Us | Notiflix
description: About Us Description
robots: noindex, nofollow, noodp, noydir
diff --git a/src/_database/pages/home.md b/src/_database/pages/home.md
index 52aab23..6b6d440 100644
--- a/src/_database/pages/home.md
+++ b/src/_database/pages/home.md
@@ -1,5 +1,6 @@
---
_dbMeta:
+ lastModifiedDate: "2021-07-22" # YYYY-MM-DD
title: Notiflix | a JavaScript library for client-side non-blocking notifications.
description: Notiflix is a pure JavaScript library for client-side non-blocking notifications, popup boxes, loading indicators, and more to that makes your web projects much better.
robots: noindex, nofollow, noodp, noydir
diff --git a/src/components/meta/MetaTags.tsx b/src/components/meta/MetaTags.tsx
index 1fe27c0..96b94ab 100644
--- a/src/components/meta/MetaTags.tsx
+++ b/src/components/meta/MetaTags.tsx
@@ -13,8 +13,8 @@ function MetaTags({ meta }: IMetaTags): JSX.Element {
const router = useRouter();
const appName = process.env.appName;
- const publicUrl = process.env.publicUrl;
- const canonicalUrl = `${publicUrl || ''}${(router?.asPath?.length > 1 ? router.asPath : '')}` || '';
+ const appUrl = process.env.appUrl;
+ const canonicalUrl = `${appUrl || ''}${(router?.asPath?.length > 1 ? router.asPath : '')}` || '';
const yearInit = _dbSettings.metaYearInit;
const yearCurrent = new Date().getFullYear() || '';
@@ -39,7 +39,7 @@ function MetaTags({ meta }: IMetaTags): JSX.Element {
-
+
diff --git a/src/components/meta/Schema.tsx b/src/components/meta/Schema.tsx
index cc30989..adfc8bc 100644
--- a/src/components/meta/Schema.tsx
+++ b/src/components/meta/Schema.tsx
@@ -10,8 +10,8 @@ function Schema(): JSX.Element {
'@context': 'https://schema.org',
'@type': 'Organization',
'name': process.env.appName,
- 'url': process.env.publicUrl,
- 'logo': `${process.env.publicUrl}${_dbSettings.metaOgImage}`,
+ 'url': process.env.appUrl,
+ 'logo': `${process.env.appUrl}${_dbSettings.metaOgImage}`,
'sameAs': _dbSocialMedia?.filter(x => x.isActive)?.map(x => x.url) || [],
};
diff --git a/src/constants/Constants.ts b/src/constants/Constants.ts
new file mode 100644
index 0000000..84544c6
--- /dev/null
+++ b/src/constants/Constants.ts
@@ -0,0 +1,19 @@
+import * as packageJSON from '../../package.json';
+
+interface IConstants {
+ appUrl: string;
+ appVersion: string;
+ appName: string;
+ appOgImageSrc: string;
+}
+
+const Constants: IConstants = {
+ appUrl: (JSON.stringify((packageJSON || {}).homepage) || '').replace(/"/gm, ''),
+ appVersion: (JSON.stringify((packageJSON || {}).version) || '').replace(/"/gm, ''),
+ appName: 'Notiflix',
+ appOgImageSrc: '/webapp/notiflix-og.jpg',
+};
+
+export type { IConstants };
+
+export { Constants };
diff --git a/src/helpers/Sitemap.ts b/src/helpers/Sitemap.ts
new file mode 100644
index 0000000..ac7bb36
--- /dev/null
+++ b/src/helpers/Sitemap.ts
@@ -0,0 +1,175 @@
+import { existsSync, readFileSync, writeFileSync } from 'fs';
+import { Constants } from '../constants/Constants';
+import { Routes } from '../routes/Routes';
+
+// Constants: begin
+const appUrl = Constants.appUrl;
+const appName = Constants.appName;
+const appOgImageSrc = `${Constants.appUrl}${Constants.appOgImageSrc}`;
+const sitemapStyleUrl = `${Constants.appUrl}/sitemap.xsl`;
+const pathOutput = 'public/sitemap.xml';
+const pathDatabase = 'src/_database';
+const pathPages = 'src/pages';
+// Constants: end
+
+
+// Helper: Format Date as YYYY-MM-DD: begin
+const sitemapFormatDate = (date: string): string => {
+ const d = new Date(date);
+ const year = d.getFullYear();
+ let month = '' + (d.getMonth() + 1);
+ let day = '' + d.getDate();
+ if (month.length < 2) { month = '0' + month; }
+ if (day.length < 2) { day = '0' + day; }
+ return [year, month, day].join('-');
+};
+// Helper: Format Date as YYYY-MM-DD: end
+
+// Helper: Create "changefreq" and "priority": begin
+interface ISitemapCreateFrequencyAndPriority {
+ frequency: string;
+ priority: string;
+}
+
+const sitemapCreateFrequencyAndPriority = (date: string): ISitemapCreateFrequencyAndPriority => {
+ const today = new Date().valueOf();
+ const pageDate = new Date(date).valueOf();
+ const differenceAsDays = Math.round((today - pageDate) / (1000 * 3600 * 24));
+ let frequency = 'daily';
+ let priority = '1.0';
+ if (differenceAsDays > 7) {
+ frequency = 'weekly';
+ priority = '0.9';
+ }
+ if (differenceAsDays > 93) {
+ frequency = 'monthly';
+ priority = '0.8';
+ }
+ if (differenceAsDays > 365) {
+ frequency = 'yearly';
+ priority = '0.7';
+ }
+ return {
+ frequency,
+ priority,
+ };
+};
+// Helper: Create "changefreq" and "priority": end
+
+// Helper: Get Pages Last Modified Date via DB file: begin
+const sitemapGetPagesLastModifiedDate = (path: string): string => {
+ const newDateAsString = new Date().toString();
+
+ // check the file is exist
+ if (!existsSync(path)) {
+ return newDateAsString;
+ }
+
+ // read the file and return "pageMeta.lastModifiedDate"
+ const fileAsText = readFileSync(path, 'utf-8');
+ if (fileAsText) {
+ // TODO: require!!!
+ // @typescript-eslint/no-var-requires
+ // eslint-disable-next-line
+ const parseMD = require('parse-md').default;
+ const fileTextAsObj = parseMD(fileAsText);
+ return fileTextAsObj?.metadata?.pageMeta?.lastModifiedDate || newDateAsString;
+ }
+
+ // else
+ return newDateAsString;
+};
+// Helper: Get Pages Last Modified Date via DB file: end
+
+
+// Sitemap: Create Url: begin
+interface ISitemapCreateUrl {
+ loc: string;
+ lastMod: string;
+ image?: string;
+ caption?: string;
+}
+
+const sitemapCreateUrl = ({ loc, lastMod, image, caption }: ISitemapCreateUrl): string => {
+ // image src
+ let imageSrc = appOgImageSrc;
+ if (image) {
+ imageSrc = image;
+ }
+
+ // image caption
+ let imageCaption = appName;
+ if (caption) {
+ imageCaption = caption.length > 50 ? caption.substring(0, 50) + '...' : caption;
+ }
+
+ return `
+
+ ${loc}
+ ${sitemapFormatDate(lastMod)}
+ ${sitemapCreateFrequencyAndPriority(lastMod).frequency}
+ ${sitemapCreateFrequencyAndPriority(lastMod).priority}
+
+ ${imageSrc}
+ ${imageCaption}
+
+
+ `;
+};
+// Sitemap: Create Url: end
+
+// Sitemap: Create Urls from Pages: begin
+const sitemapCreateUrlsFromPages = (): string => {
+ let sitemapPagesUrls = '';
+
+ // if DB and Pages folders exist
+ if (existsSync(pathDatabase) && existsSync(pathPages)) {
+ Routes?.filter(route => route.isActive && route.addToSitemap)?.map(route => {
+ // page path
+ let pagePath = route.pathAs || '';
+
+ // if home page
+ if (pagePath === '/') { pagePath = ''; }
+
+ // page full url
+ const pageFullUrl = `${appUrl}${pagePath}`;
+
+ // page db file
+ const pageDbFile = route.pathDBFile;
+
+ // page db path
+ const pageDbFullPath = `${pathDatabase}${pageDbFile}`;
+
+ // page last mod date
+ const pageLastModifiedDate = sitemapGetPagesLastModifiedDate(pageDbFullPath);
+
+ // create a sitemap url for this page
+ sitemapPagesUrls += sitemapCreateUrl({
+ loc: pageFullUrl,
+ lastMod: pageLastModifiedDate,
+ });
+ });
+ }
+
+ // Return Urls
+ return sitemapPagesUrls;
+};
+// Sitemap: Create Urls from Pages: end
+
+
+// Sitemap: Create XML Content: begin
+const sitemapCreateXmlPageContent = (): string => {
+ return `
+
+
+ ${sitemapCreateUrlsFromPages()}
+ `;
+};
+// Sitemap: Create XML Content: end
+
+// Sitemap: Write XML Content: begin
+const sitemapWriteXMLFile = (pathOutput: string): void => {
+ writeFileSync(pathOutput, sitemapCreateXmlPageContent());
+};
+sitemapWriteXMLFile(pathOutput);
+// Sitemap: Write XML Content: end
diff --git a/src/pages/about/index.tsx b/src/pages/about/index.tsx
index 8e7a844..4cea7e1 100644
--- a/src/pages/about/index.tsx
+++ b/src/pages/about/index.tsx
@@ -52,7 +52,7 @@ function About(): JSX.Element {
ABOUT
-
+
Go to Home
@@ -65,7 +65,7 @@ function About(): JSX.Element {
-
+
);
}
diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx
index a66f7b6..b256017 100644
--- a/src/pages/home/index.tsx
+++ b/src/pages/home/index.tsx
@@ -13,7 +13,7 @@ function Home(): JSX.Element {
HOME
-
+
Go to ABOUT
diff --git a/src/routes/Routes.ts b/src/routes/Routes.ts
new file mode 100644
index 0000000..41f17dd
--- /dev/null
+++ b/src/routes/Routes.ts
@@ -0,0 +1,62 @@
+interface IRoutes {
+ id: number;
+ sortOrder: number;
+ isActive: boolean;
+ addToNextJSConfig: boolean;
+ addToSitemap: boolean;
+ addToNavMenu: boolean;
+ name: string;
+ pathAs: string;
+ pathPage: string;
+ pathDBFile: string;
+ targetBlank: boolean;
+ icon: {
+ use: boolean;
+ className: string;
+ };
+}
+
+const Routes: Array = [
+ // Home Page
+ {
+ id: 1,
+ sortOrder: 1,
+ isActive: true,
+ addToNextJSConfig: true,
+ addToSitemap: true,
+ addToNavMenu: true,
+ name: 'Home',
+ pathAs: '/',
+ pathPage: '/home',
+ pathDBFile: '/pages/about.md',
+ targetBlank: false,
+ icon: {
+ use: false,
+ className: 'fab fa-github',
+ },
+ },
+
+ // About Page
+ {
+ id: 2,
+ sortOrder: 2,
+ isActive: true,
+ addToNextJSConfig: true,
+ addToSitemap: true,
+ addToNavMenu: true,
+ name: 'About',
+ pathAs: '/about',
+ pathPage: '/about',
+ pathDBFile: '/pages/about.md',
+ targetBlank: false,
+ icon: {
+ use: false,
+ className: 'fab fa-github',
+ },
+ },
+
+];
+
+export type { IRoutes };
+
+export { Routes };
diff --git a/tsconfig.json b/tsconfig.json
index 97d97fe..489a081 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -11,9 +11,18 @@
"@components/*": [
"components/*"
],
+ "@constants/*": [
+ "constants/*"
+ ],
+ "@helpers/*": [
+ "helpers/*"
+ ],
"@pages/*": [
"pages/*"
],
+ "@routes/*": [
+ "routes/*"
+ ],
"@styles/*": [
"styles/*"
],
diff --git a/yarn.lock b/yarn.lock
index 9de3dfa..3698d51 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3059,6 +3059,13 @@ parse-json@^5.0.0:
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
+parse-md@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/parse-md/-/parse-md-2.0.4.tgz#0aeb75fca8dca270f232340c02aabe33ea846165"
+ integrity sha512-P45VmpnIo2QGErCa+YnpndzKXcu2v5qpFX31pOyGY+Ub9KuCAm6qKXCbR3sRsoESuy6XeY81hEIVnn6xz+0YcA==
+ dependencies:
+ js-yaml "^3.13.1"
+
path-browserify@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"