Skip to content

Commit

Permalink
Merge pull request #425 from seth2810/next-amp
Browse files Browse the repository at this point in the history
  • Loading branch information
ashikov committed Sep 29, 2022
2 parents 72ec736 + 16d1558 commit 72e9f32
Show file tree
Hide file tree
Showing 16 changed files with 6,553 additions and 26 deletions.
22 changes: 11 additions & 11 deletions next-app/api/index.js
Expand Up @@ -15,7 +15,7 @@ import { parseISO, endOfDay } from 'date-fns';

import RSSFeedPostContent from '../components/RSSFeedPostContent.jsx';
import { i18n } from '../next-i18next.config.js';
import config from '../data/config.js';
import cfg from '../data/config.js';

const makeHref = (pathname, locale) => {
const parts = ['/'];
Expand Down Expand Up @@ -43,7 +43,7 @@ const readPost = async (filePath, basePath, locale) => {
const { data, content } = matter(fileContent);
const { name } = path.parse(filePath);
const { title = null, header = title, description = null, summary = description, ...props } = data;
const sourceUrl = `${config.repositoryUrl}/tree/main/${filePath}`;
const sourceUrl = `${cfg.repositoryUrl}/tree/main/${filePath}`;
const shortName = name.slice(11); // remove DD_MM_YYYY prefix from post file name
const date = endOfDay(parseISO(name.slice(0, 10)));

Expand Down Expand Up @@ -76,12 +76,12 @@ const compilePostContent = async (content) => {
};

const makePostRSSItem = async (post, locale) => {
const postUrl = new URL(post.href, config.siteURL)
const postUrl = new URL(post.href, cfg.siteURL)
const content = await compilePostContent(post.content);
const breadcrumbs = [
{
link: config.siteURL,
text: config.title,
link: cfg.siteURL,
text: cfg.title,
},
{
link: postUrl.toString(),
Expand Down Expand Up @@ -170,9 +170,9 @@ export const generateRssFeed = async (locale) => {

const feedItems = await Promise.all(promises);
const feed = new Feed({
title: config.title,
link: config.siteURL,
description: config.description,
title: cfg.title,
link: cfg.siteURL,
description: cfg.description,
language: locale,
});

Expand All @@ -185,16 +185,16 @@ export const generateSitemap = async (locale) => {
const posts = await getPublishedPosts(locale);
const visiblePosts = posts.filter(({ hidden = false }) => !hidden);
const fields = visiblePosts.map((post) => ({
loc: new URL(post.href, config.siteURL),
loc: new URL(post.href, cfg.siteURL),
lastmod: post.date,
}));

fields.push({
loc: new URL(makeHref(null, locale), config.siteURL)
loc: new URL(makeHref(null, locale), cfg.siteURL)
});

fields.push({
loc: new URL(makeHref('about', locale), config.siteURL)
loc: new URL(makeHref('about', locale), cfg.siteURL)
});

return fields;
Expand Down
14 changes: 14 additions & 0 deletions next-app/components/AmpAnalytics.jsx
@@ -0,0 +1,14 @@
import React from 'react';

const AmpAnalytics = ({ type, config }) => (
<amp-analytics type={type}>
<script
type="application/json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(config),
}}
/>
</amp-analytics>
);

export default AmpAnalytics;
26 changes: 26 additions & 0 deletions next-app/components/AmpBoilerplate.jsx
@@ -0,0 +1,26 @@
import React from 'react';

// inject AMP directly because Next.js supports only css-in-js from AMP
import ampCSS from '!!raw-loader!sass-loader!../styles/amp.scss';
import boilerplaceCSS from '!!raw-loader!../styles/amp-boilerplate.css';
import boilerplaceNoScriptCSS from '!!raw-loader!../styles/amp-boilerplate-noscript.css';

// Add some render delaying extension to disable removing amp-boilerplate by apm-html-optimizer
// @see https://github.com/ampproject/amp-toolbox/blob/678c0e2e5c850f0de538d5e642558a1e678054c9/packages/optimizer/lib/transformers/ServerSideRendering.js#L125-L131
const AmpBoilerplate = () => (
<>
<script async custom-element="amp-analytics" src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script>
<script
async
custom-element="amp-dynamic-css-classes"
src="https://cdn.ampproject.org/v0/amp-dynamic-css-classes-0.1.js"
></script>
<style amp-boilerplate="true" dangerouslySetInnerHTML={{ __html: boilerplaceCSS }}></style>
<noscript>
<style amp-boilerplate="true" dangerouslySetInnerHTML={{ __html: boilerplaceNoScriptCSS }}></style>
</noscript>
<style amp-custom="true" dangerouslySetInnerHTML={{ __html: ampCSS }}></style>
</>
);

export default AmpBoilerplate;
52 changes: 52 additions & 0 deletions next-app/components/AmpLayout.jsx
@@ -0,0 +1,52 @@
import React from 'react';
import Head from 'next/head';

import cfg from '../data/config.js';
import AmpAnalytics from './AmpAnalytics.jsx';
import AmpBoilerplate from './AmpBoilerplate.jsx';

const gtagConfig = {
vars: {
gtag_id: cfg.amp.analytics.googleTrackingId,
config: {
[cfg.amp.analytics.googleTrackingId]: {
groups: 'default',
},
},
},
};

const metrikaConfig = {
vars: {
counterId: cfg.amp.analytics.metrikaCounterId,
},
triggers: {
notBounce: {
on: 'timer',
timerSpec: {
immediate: false,
interval: 15,
maxTimerLength: 14,
},
request: 'notBounce',
},
},
};

const AmpLayout = ({ title, children }) => {
const fullTitle = title ? `${title} | ${cfg.title}` : cfg.title;

return (
<>
<Head>
<title>{fullTitle}</title>
<AmpBoilerplate />
</Head>
<AmpAnalytics type="gtag" config={gtagConfig} />
<AmpAnalytics type="metrika" config={metrikaConfig} />
<div className="markdown md:markdown-lg lg:markdown-xl">{children}</div>
</>
);
};

export default AmpLayout;
35 changes: 35 additions & 0 deletions next-app/components/AmpPostPageInfo.jsx
@@ -0,0 +1,35 @@
/* eslint-disable @next/next/no-img-element */
import React from 'react';
import Link from 'next/link';
import { MDXRemote } from 'next-mdx-remote';
import { useTranslation } from 'next-i18next';

import Banner from './Banner.jsx';

const components = {
Banner,
img: ({ src }) => <amp-img src={src} layout="responsive" height="0.6" width="1" />,
};

const AmpPostPageInfo = ({ post }) => {
const href = {
pathname: '/[name]',
query: {
name: post.name,
},
};

const { t } = useTranslation('post');

return (
<>
<h1>{post.header}</h1>
<Link href={href}>
<a className="full_post_link">{t('page.full_post_link')}</a>
</Link>
<MDXRemote compiledSource={post.content} components={components} />
</>
);
};

export default AmpPostPageInfo;
12 changes: 6 additions & 6 deletions next-app/components/DefaultLayout.jsx
Expand Up @@ -3,27 +3,27 @@ import Head from 'next/head';
import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router';

import config from '../data/config.js';
import cfg from '../data/config.js';

import Navbar from '../components/Navbar.jsx';
import Footer from '../components/Footer.jsx';

const DefaultLayout = ({ title, description, author, image, type = 'website', children }) => {
const { t } = useTranslation('common');
const { asPath, locale } = useRouter();
const fullTitle = title ? `${title} | ${config.title}` : config.title;
const fullTitle = title ? `${title} | ${cfg.title}` : cfg.title;
const metaDescription = description || t('description');
const metaAuthor = author || t('author');
const [path] = asPath.split('?');
const prefix = locale === 'ru' ? `/${locale}` : '';
const url = `${config.siteUrl}${prefix}${path}`;
const imageUrl = `${config.siteUrl}${image}`;
const url = `${cfg.siteUrl}${prefix}${path}`;
const imageUrl = `${cfg.siteUrl}${image}`;

return (
<>
<Head>
<title>{fullTitle}</title>
<link rel="icon" href={config.favicon} />
<link rel="icon" href={cfg.favicon} />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="author" content={metaAuthor} />
<meta name="description" content={metaDescription} />
Expand All @@ -32,7 +32,7 @@ const DefaultLayout = ({ title, description, author, image, type = 'website', ch
<meta property="og:locale" content={t('locale')} />
<meta property="og:description" content={metaDescription} />
<meta property="og:url" content={url} />
<meta property="og:site_name" content={config.title} />
<meta property="og:site_name" content={cfg.title} />
<meta property="og:type" content={type} />
{image && <meta property="og:image" content={imageUrl} />}
<meta property="twitter:title" content={title} />
Expand Down
6 changes: 3 additions & 3 deletions next-app/components/Navbar.jsx
Expand Up @@ -4,7 +4,7 @@ import Link from 'next/link';
import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';

import config from '../data/config.js';
import cfg from '../data/config.js';

const Navbar = () => {
const { t } = useTranslation('common');
Expand All @@ -26,12 +26,12 @@ const Navbar = () => {
<div className="d-flex flex-wrap justify-content-center py-3">
<Link href="/">
<a className="navbar-brand me-auto">
<Image width="30" height="30" alt="Hexlet logo" src={config.logo} />
<Image width="30" height="30" alt="Hexlet logo" src={cfg.logo} />
</a>
</Link>
<ul className="nav nav-pills">
<li className="nav-item">
<Link href={config.repositoryUrl}>
<Link href={cfg.repositoryUrl}>
<a className="nav-link" target="_blank">
{t('navbar.source_code.title')}
</a>
Expand Down
6 changes: 6 additions & 0 deletions next-app/data/config.js
Expand Up @@ -17,6 +17,12 @@ const config = {
ru: 'hexlet-guides',
en: 'hexlet-guides-en',
},
amp: {
analytics: {
metrikaCounterId: '65474386',
googleTrackingId: 'UA-1360700-62',
}
}
};

export default config;
5 changes: 5 additions & 0 deletions next-app/next.config.js
Expand Up @@ -3,4 +3,9 @@ const { i18n } = require('./next-i18next.config.js');
module.exports = {
i18n,
trailingSlash: true,
experimental: {
amp: {
skipValidation: true,
},
},
};

0 comments on commit 72e9f32

Please sign in to comment.