mirror of
https://github.com/sergeyyarkov/devthread.ru.git
synced 2026-10-11 02:09:04 +03:00
format
This commit is contained in:
parent
f0b960eb22
commit
5778d12166
@ -25,14 +25,14 @@ tags:
|
||||
|
||||
## Содержание
|
||||
|
||||
* [Описание списка зависимостей](#Описание-списка-зависимостей)
|
||||
* [Структура проекта](#Структура-проекта)
|
||||
* [Предварительная настройка](#Предварительная-настройка)
|
||||
* [Создание Type Definitions](#Создание-Type-Definitions)
|
||||
* [Создание Resolvers](#Создание-Resolvers)
|
||||
* [Создание схемы](#Создание-схемы)
|
||||
* [Использование Apollo Server Express](#Использование-Apollo-Server-Express)
|
||||
* [Заключение](#Заключение)
|
||||
- [Описание списка зависимостей](#Описание-списка-зависимостей)
|
||||
- [Структура проекта](#Структура-проекта)
|
||||
- [Предварительная настройка](#Предварительная-настройка)
|
||||
- [Создание Type Definitions](#Создание-Type-Definitions)
|
||||
- [Создание Resolvers](#Создание-Resolvers)
|
||||
- [Создание схемы](#Создание-схемы)
|
||||
- [Использование Apollo Server Express](#Использование-Apollo-Server-Express)
|
||||
- [Заключение](#Заключение)
|
||||
|
||||
💡 Данное руководство расчитано на тех разработчиков, кто уже имел небольшой опыт с использованием технологий **Apollo Server** и **TypeScript**.
|
||||
|
||||
@ -56,9 +56,11 @@ npm install @types/graphql-depth-limit apollo-server-express cors dotenv express
|
||||
// инициализировать файл с настройками typescript
|
||||
npx tsc --init
|
||||
```
|
||||
|
||||
Теперь по порядку узнаем для чего нужны эти пакеты:
|
||||
|
||||
**devDependencies:**
|
||||
|
||||
1. **@typesnode** - устанавливаем type definitions node.js для нашего typescript **~717 kB**
|
||||
2. **prettier** - этот пакет нужен для форматирования вашего кода, вы можете установить его <ins>по желанию</ins> **~9.08 MB**
|
||||
3. **ts-node** - данные пакет предназначен для транспиляции typescript кода в javascript **~377 kB**
|
||||
@ -66,6 +68,7 @@ npx tsc --init
|
||||
5. **typescript** - сам typescript **~56.8 MB**
|
||||
|
||||
**dependencies:**
|
||||
|
||||
1. **apollo-server-express** - GraphQL сервер вместе в веб-фреймворком Express.js **~70.1 kB**
|
||||
2. **express** - веб-фреймворк Express.js **~208 kB**
|
||||
3. **graphql** - среда выполнения запросов к нашей API **~1.92 MB**
|
||||
@ -78,6 +81,7 @@ npx tsc --init
|
||||
## Структура проекта
|
||||
|
||||
Теперь после того как все пакеты установлены, определимся со структурой проекта:
|
||||
|
||||
```text
|
||||
.
|
||||
└── typescript-apollo-server
|
||||
@ -103,13 +107,16 @@ npx tsc --init
|
||||
## Предварительная настройка
|
||||
|
||||
Перед тем как начать разрабатывать наш сервер, зайдем в **package.json** и установим скрипты запуска:
|
||||
|
||||
```text
|
||||
"scripts": {
|
||||
"start": "ts-node index.ts",
|
||||
"server": "ts-node-dev --respawn index.ts"
|
||||
},
|
||||
```
|
||||
|
||||
Теперь необходимо создать схему, создаем папку **graphql** и в ней также создаем еще две папки **resolvers** и **typeDefs**, также не забываем создать файл **schema.ts**:
|
||||
|
||||
```bash
|
||||
mkdir graphql
|
||||
cd ./graphql
|
||||
@ -134,6 +141,7 @@ touch Book.graphql
|
||||
Далее напишем наши типы. Обратите внимание что для удобства и разделения кода мы будем использовать импорты. Возможность использовать импорты нам предоставляет пакет **graphql-tools**. Для того чтобы импортировать файл **.graphql** ставится знак **#** и указывается путь.
|
||||
|
||||
Главный файл **schema.graphql**:
|
||||
|
||||
```graphql
|
||||
# ./graphql/typeDefs/schema.graphql
|
||||
|
||||
@ -147,6 +155,7 @@ type Query {
|
||||
```
|
||||
|
||||
Файл **Book.graphql**:
|
||||
|
||||
```graphql
|
||||
# ./graphql/typeDefs/Book.graphql
|
||||
|
||||
@ -157,6 +166,7 @@ type Book {
|
||||
```
|
||||
|
||||
Файл **User.graphql**:
|
||||
|
||||
```graphql
|
||||
# ./graphql/typeDefs/User.graphql
|
||||
|
||||
@ -191,10 +201,11 @@ cd ..
|
||||
Наконец прописываем обработчики:
|
||||
|
||||
Файл **Books.ts**:
|
||||
|
||||
```js
|
||||
// ./graphql/resolvers/Books/Books.ts
|
||||
|
||||
import { IResolvers } from 'graphql-tools';
|
||||
import { IResolvers } from "graphql-tools"
|
||||
|
||||
interface BookType {
|
||||
id: string;
|
||||
@ -202,17 +213,17 @@ interface BookType {
|
||||
}
|
||||
|
||||
const books = [
|
||||
{ id: '1', title: 'First Book' },
|
||||
{ id: '2', title: 'Second Book' },
|
||||
];
|
||||
{ id: "1", title: "First Book" },
|
||||
{ id: "2", title: "Second Book" },
|
||||
]
|
||||
|
||||
const booksResolver: IResolvers = {
|
||||
Query: {
|
||||
books: (): BookType[] => books,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default booksResolver;
|
||||
export default booksResolver
|
||||
```
|
||||
|
||||
Файл **Users.ts**:
|
||||
@ -220,7 +231,7 @@ export default booksResolver;
|
||||
```js
|
||||
// ./graphql/resolvers/Users/Users.ts
|
||||
|
||||
import { IResolvers } from 'graphql-tools';
|
||||
import { IResolvers } from "graphql-tools"
|
||||
|
||||
interface UserType {
|
||||
id: string;
|
||||
@ -228,17 +239,17 @@ interface UserType {
|
||||
}
|
||||
|
||||
const users = [
|
||||
{ id: '1', name: 'John' },
|
||||
{ id: '2', name: 'Ivan' },
|
||||
];
|
||||
{ id: "1", name: "John" },
|
||||
{ id: "2", name: "Ivan" },
|
||||
]
|
||||
|
||||
const usersResolver: IResolvers = {
|
||||
Query: {
|
||||
users: (): UserType[] => users,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default usersResolver;
|
||||
export default usersResolver
|
||||
```
|
||||
|
||||
Резолверы получились довольно простые и понятные, теперь нужно собрать их в один массив для дальнейшего экспорта. В файле **index.ts** прописываем следующее:
|
||||
@ -246,17 +257,18 @@ export default usersResolver;
|
||||
```js
|
||||
// ./graphql/resolvers/index.ts
|
||||
|
||||
import { IResolvers } from 'graphql-tools';
|
||||
import { IResolvers } from "graphql-tools"
|
||||
|
||||
import booksResolver from './Books/Books';
|
||||
import usersResolver from './Users/Users'
|
||||
import booksResolver from "./Books/Books"
|
||||
import usersResolver from "./Users/Users"
|
||||
|
||||
const resolvers: IResolvers[] = [usersResolver, booksResolver];
|
||||
const resolvers: IResolvers[] = [usersResolver, booksResolver]
|
||||
|
||||
export default resolvers;
|
||||
export default resolvers
|
||||
```
|
||||
|
||||
## Создание схемы
|
||||
|
||||
Как говорилось ранее, пакет **graphql-tools** предназначен для создания схемы. Теперь перейдем в наш файл **schema.ts** и соберем нашу схему.
|
||||
|
||||
Раньше для того чтобы работали наши graphql импорты мы применяли пакет **graphql-import**, но теперь его не нужно устанавливать так как он уже входит в состав **graphql-tools**. Подробнее об этом можно прочитать [здесь](https://www.graphql-tools.com/docs/migration-from-import).
|
||||
@ -265,20 +277,26 @@ export default resolvers;
|
||||
```js
|
||||
// ./graphql/schema.ts
|
||||
|
||||
import { mergeResolvers, loadSchemaSync, loadFilesSync, GraphQLFileLoader, addResolversToSchema } from 'graphql-tools';
|
||||
import { GraphQLSchema } from 'graphql';
|
||||
import {
|
||||
mergeResolvers,
|
||||
loadSchemaSync,
|
||||
loadFilesSync,
|
||||
GraphQLFileLoader,
|
||||
addResolversToSchema,
|
||||
} from "graphql-tools"
|
||||
import { GraphQLSchema } from "graphql"
|
||||
|
||||
const schema = loadSchemaSync(`${__dirname}/typeDefs/schema.graphql`, {
|
||||
loaders: [new GraphQLFileLoader()],
|
||||
});
|
||||
})
|
||||
|
||||
const resolvers = loadFilesSync(`${__dirname}/resolvers`);
|
||||
const resolvers = loadFilesSync(`${__dirname}/resolvers`)
|
||||
const schemaWithResolvers: GraphQLSchema = addResolversToSchema({
|
||||
schema,
|
||||
resolvers: mergeResolvers(resolvers),
|
||||
});
|
||||
})
|
||||
|
||||
export default schemaWithResolvers;
|
||||
export default schemaWithResolvers
|
||||
```
|
||||
|
||||
## Использование Apollo Server Express
|
||||
@ -294,38 +312,38 @@ touch index.ts
|
||||
```js
|
||||
// ./index.ts
|
||||
|
||||
import express, { Application, Request, Response } from 'express';
|
||||
import cors from 'cors';
|
||||
import depthLimit from 'graphql-depth-limit';
|
||||
import { ApolloServer } from 'apollo-server-express';
|
||||
import schema from './graphql/schema';
|
||||
import express, { Application, Request, Response } from "express"
|
||||
import cors from "cors"
|
||||
import depthLimit from "graphql-depth-limit"
|
||||
import { ApolloServer } from "apollo-server-express"
|
||||
import schema from "./graphql/schema"
|
||||
|
||||
const PORT = process.env.PORT || 4000;
|
||||
const PORT = process.env.PORT || 4000
|
||||
|
||||
const startServer = (): void => {
|
||||
try {
|
||||
const app: Application = express();
|
||||
const app: Application = express()
|
||||
|
||||
const server: ApolloServer = new ApolloServer({
|
||||
schema,
|
||||
validationRules: [depthLimit(10)], // выставляем правило deph limit = 10
|
||||
playground: true,
|
||||
});
|
||||
})
|
||||
|
||||
app.use('*', cors());
|
||||
app.get('/', (req: Request, res: Response) => res.send('GraphQL API'));
|
||||
app.use("*", cors())
|
||||
app.get("/", (req: Request, res: Response) => res.send("GraphQL API"))
|
||||
|
||||
server.applyMiddleware({ app });
|
||||
server.applyMiddleware({ app })
|
||||
|
||||
app.listen({ port: PORT }, () =>
|
||||
console.log(`🚀 Server ready on port: ${PORT}`)
|
||||
);
|
||||
)
|
||||
} catch (err) {
|
||||
console.log(`❌ Something went wrong: \n ${err}`);
|
||||
console.log(`❌ Something went wrong: \n ${err}`)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
startServer();
|
||||
startServer()
|
||||
```
|
||||
|
||||
Как видим, ничего сложного нет, просто применяем функцию [applyMiddleware](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#applymiddleware) для того чтобы соедениеть Apollo Server с фрэймворком Express.js. Далее можно протестировать наш сервер, запускаем команду **npm run start** и переходим по адресу **/graphql**. Для тестирования можно выполнить вот такой запрос:
|
||||
@ -372,7 +390,6 @@ startServer();
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Заключение
|
||||
|
||||
Как видим, использование Apollo Server вместе с TypeScript оказалась совсем не сложной задачей, так как и Apollo Server и пакет graphql-import имеют поддержку typescript из коробки.
|
||||
@ -3,7 +3,7 @@ import React from "react"
|
||||
import Layout from "./src/components/Layout/Layout"
|
||||
|
||||
import "prismjs/themes/prism-tomorrow.css"
|
||||
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'
|
||||
import "prismjs/plugins/line-numbers/prism-line-numbers.css"
|
||||
|
||||
import "./src/styles/global.scss"
|
||||
import "./src/components/Header/Header.scss"
|
||||
@ -30,8 +30,12 @@ export const shouldUpdateScroll = ({ routerProps: { location } }) => {
|
||||
}
|
||||
|
||||
export const wrapPageElement = ({ element, props }) => {
|
||||
const { location: { pathname } } = props
|
||||
pathname.includes('/amp/article/') && props.pageContext.slug ? props.amp = true : props.amp = false
|
||||
const {
|
||||
location: { pathname },
|
||||
} = props
|
||||
pathname.includes("/amp/article/") && props.pageContext.slug
|
||||
? (props.amp = true)
|
||||
: (props.amp = false)
|
||||
|
||||
return <Layout {...props}>{element}</Layout>
|
||||
}
|
||||
|
||||
@ -161,12 +161,12 @@ module.exports = {
|
||||
{
|
||||
resolve: `gatsby-plugin-amp`,
|
||||
options: {
|
||||
canonicalBaseUrl: 'https://devthread.ru/',
|
||||
components: ['amp-sidebar', 'amp-accordion', 'amp-form'],
|
||||
excludedPaths: ['/404*', '/'],
|
||||
pathIdentifier: '/amp/',
|
||||
relAmpHtmlPattern: '{{canonicalBaseUrl}}{{pathIdentifier}}{{pathname}}',
|
||||
relCanonicalPattern: '{{canonicalBaseUrl}}{{pathname}}/',
|
||||
canonicalBaseUrl: "https://devthread.ru/",
|
||||
components: ["amp-sidebar", "amp-accordion", "amp-form"],
|
||||
excludedPaths: ["/404*", "/"],
|
||||
pathIdentifier: "/amp/",
|
||||
relAmpHtmlPattern: "{{canonicalBaseUrl}}{{pathIdentifier}}{{pathname}}",
|
||||
relCanonicalPattern: "{{canonicalBaseUrl}}{{pathname}}/",
|
||||
useAmpClientIdApi: false,
|
||||
},
|
||||
},
|
||||
|
||||
@ -40,7 +40,7 @@ const OnDark = () => {
|
||||
}
|
||||
|
||||
export const onRenderBody = ({ pathname, setPreBodyComponents }) => {
|
||||
if (pathname.includes('/amp/article/')) {
|
||||
if (pathname.includes("/amp/article/")) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -48,8 +48,12 @@ export const onRenderBody = ({ pathname, setPreBodyComponents }) => {
|
||||
}
|
||||
|
||||
export const wrapPageElement = ({ element, props }) => {
|
||||
const { location: { pathname } } = props
|
||||
pathname.includes('/amp/article/') && props.pageContext.slug ? props.amp = true : props.amp = false
|
||||
const {
|
||||
location: { pathname },
|
||||
} = props
|
||||
pathname.includes("/amp/article/") && props.pageContext.slug
|
||||
? (props.amp = true)
|
||||
: (props.amp = false)
|
||||
|
||||
return <Layout {...props}>{element}</Layout>
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ import FacebookIcon from "../../images/facebook-icon__large.svg"
|
||||
const Article = ({
|
||||
data: { slug, title, image, description, category, tags, time, date },
|
||||
html,
|
||||
amp
|
||||
amp,
|
||||
}) => {
|
||||
const {
|
||||
siteMetadata: {
|
||||
@ -40,10 +40,12 @@ const Article = ({
|
||||
<div className="article-info__time">
|
||||
<span>~ {time} мин</span>
|
||||
</div>
|
||||
{!amp ? <div className="article-info__views">
|
||||
{!amp ? (
|
||||
<div className="article-info__views">
|
||||
<ViewsIcon />
|
||||
<ViewCounter id={pathname} />
|
||||
</div> : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="right-info">
|
||||
<div className="article-info__date">
|
||||
@ -93,19 +95,20 @@ const Article = ({
|
||||
))}
|
||||
</div>
|
||||
<div className="article-image">
|
||||
{!amp
|
||||
? <Img
|
||||
{!amp ? (
|
||||
<Img
|
||||
loading="eager"
|
||||
fadeIn={false}
|
||||
fluid={image.childImageSharp.fluid}
|
||||
alt={title}
|
||||
/>
|
||||
: <img
|
||||
) : (
|
||||
<img
|
||||
src={image.childImageSharp.fluid.src}
|
||||
height='350'
|
||||
height="350"
|
||||
alt={title}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<div className="article-inner inner">
|
||||
<div dangerouslySetInnerHTML={{ __html: html }}></div>
|
||||
|
||||
@ -6,21 +6,26 @@ import { Link } from "gatsby"
|
||||
|
||||
const ArticleCard = ({
|
||||
data: { slug, title, image, category, description, tags },
|
||||
amp
|
||||
amp,
|
||||
}) => {
|
||||
return (
|
||||
<article className="article-card">
|
||||
<div className="article-card__image">
|
||||
<Link to={`/article/${slug}/`}>
|
||||
{!amp
|
||||
? <Img
|
||||
{!amp ? (
|
||||
<Img
|
||||
loading="eager"
|
||||
fadeIn={false}
|
||||
fluid={image.childImageSharp.fluid}
|
||||
alt={title}
|
||||
/>
|
||||
: <img src={image.childImageSharp.fluid.src} height='380' alt={title} />
|
||||
}
|
||||
) : (
|
||||
<img
|
||||
src={image.childImageSharp.fluid.src}
|
||||
height="380"
|
||||
alt={title}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="article-card__heading">
|
||||
|
||||
@ -90,4 +90,3 @@ export default Footer
|
||||
Footer.propTypes = {
|
||||
amp: PropTypes.bool,
|
||||
}
|
||||
|
||||
|
||||
@ -2,10 +2,9 @@ import React from "react"
|
||||
import Header from "../Header/Header"
|
||||
import Footer from "../Footer/Footer"
|
||||
|
||||
import { HeaderAMP } from '../../lib/amp'
|
||||
import { HeaderAMP } from "../../lib/amp"
|
||||
|
||||
const Layout = ({ children, amp }) => {
|
||||
|
||||
/*
|
||||
amp is accelerated mobile pages
|
||||
*/
|
||||
|
||||
@ -3,17 +3,21 @@ import React from "react"
|
||||
const Newsletter = () => {
|
||||
const submitHandler = e => {
|
||||
e.preventDefault()
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="newsletter">
|
||||
<div className="newsletter-heading"><span role="img" aria-label="hot">📫</span>{" "}Новостная рассылка</div>
|
||||
<div className="newsletter-heading">
|
||||
<span role="img" aria-label="hot">
|
||||
📫
|
||||
</span>{" "}
|
||||
Новостная рассылка
|
||||
</div>
|
||||
<div className="newsletter-content">
|
||||
<p>
|
||||
Подпишитесь на новостную рассылку чтобы не пропустить вышедшие статьи
|
||||
</p>
|
||||
<form onSubmit={submitHandler} action="#" target='_blank'>
|
||||
<form onSubmit={submitHandler} action="#" target="_blank">
|
||||
<div className="email-field">
|
||||
<input placeholder="ваш e-mail" type="email" name="email" />
|
||||
<button>Подписаться</button>
|
||||
|
||||
@ -13,7 +13,7 @@ const SEO = ({
|
||||
type,
|
||||
canonical,
|
||||
url,
|
||||
amp
|
||||
amp,
|
||||
}) => {
|
||||
const { pathname } = useLocation()
|
||||
const { siteMetadata } = useSiteMetadataQuery()
|
||||
@ -71,7 +71,8 @@ const SEO = ({
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#191919" />
|
||||
<meta name="msapplication-TileColor" content="#ffffff" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
{!amp ? <script type="application/ld+json">
|
||||
{!amp ? (
|
||||
<script type="application/ld+json">
|
||||
{JSON.stringify({
|
||||
"@context": "http://schema.org",
|
||||
"@type": "Organization",
|
||||
@ -79,7 +80,8 @@ const SEO = ({
|
||||
url: siteMetadata.siteUrl,
|
||||
sameAs: [siteMetadata.social.twitter],
|
||||
})}
|
||||
</script> : null}
|
||||
</script>
|
||||
) : null}
|
||||
</Helmet>
|
||||
)
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ const useMoreArticlesQuery = () => {
|
||||
title
|
||||
image {
|
||||
childImageSharp {
|
||||
fluid(maxWidth: 650 quality: 100) {
|
||||
fluid(maxWidth: 650, quality: 100) {
|
||||
...GatsbyImageSharpFluid_withWebp
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Helmet } from 'react-helmet'
|
||||
import useSiteMetadataQuery from '../hooks/useSiteMetadataQuery'
|
||||
import React from "react"
|
||||
import { Helmet } from "react-helmet"
|
||||
import useSiteMetadataQuery from "../hooks/useSiteMetadataQuery"
|
||||
|
||||
import LogoIcon from '../images/logo-icon.svg'
|
||||
import LogoIcon from "../images/logo-icon.svg"
|
||||
import TelegramIcon from "../images/telegram-icon.svg"
|
||||
import TwitterIcon from "../images/twitter-icon.svg"
|
||||
import YadzenIcon from "../images/yadzen-icon.svg"
|
||||
@ -25,7 +25,7 @@ const HeaderAMP = () => {
|
||||
height: 100%;
|
||||
padding: 0px 24px;
|
||||
padding-top: 25px;
|
||||
background-color: rgba(7,11,14,.99);
|
||||
background-color: rgba(7, 11, 14, 0.99);
|
||||
width: 320px;
|
||||
}
|
||||
amp-sidebar nav li {
|
||||
@ -79,9 +79,14 @@ const HeaderAMP = () => {
|
||||
<div className="header-content amp">
|
||||
<div className="header-content__logo">
|
||||
<LogoIcon />
|
||||
<a href='/'>devthread.ru</a>
|
||||
<a href="/">devthread.ru</a>
|
||||
</div>
|
||||
<button tabindex="0" on='tap:sidebar-header' aria-label="menu" className="header-content__button mobile">
|
||||
<button
|
||||
tabindex="0"
|
||||
on="tap:sidebar-header"
|
||||
aria-label="menu"
|
||||
className="header-content__button mobile"
|
||||
>
|
||||
<span />
|
||||
<span />
|
||||
<span />
|
||||
@ -90,7 +95,13 @@ const HeaderAMP = () => {
|
||||
</header>
|
||||
<amp-sidebar id="sidebar-header" layout="nodisplay" side="left">
|
||||
<nav>
|
||||
<div role='button' tabindex="0" on='tap:sidebar-header.toggle' aria-label="menu" className='amp-sidebar__toggleBtn'>
|
||||
<div
|
||||
role="button"
|
||||
tabindex="0"
|
||||
on="tap:sidebar-header.toggle"
|
||||
aria-label="menu"
|
||||
className="amp-sidebar__toggleBtn"
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
<span>{title}</span>
|
||||
|
||||
@ -138,7 +138,7 @@ export const query = graphql`
|
||||
title
|
||||
image {
|
||||
childImageSharp {
|
||||
fluid(maxWidth: 650 quality: 100) {
|
||||
fluid(maxWidth: 650, quality: 100) {
|
||||
...GatsbyImageSharpFluid_withWebp
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ export const query = graphql`
|
||||
title
|
||||
image {
|
||||
childImageSharp {
|
||||
fluid(maxWidth: 650 quality: 100) {
|
||||
fluid(maxWidth: 650, quality: 100) {
|
||||
...GatsbyImageSharpFluid_withWebp
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from "react"
|
||||
import { parse } from 'node-html-parser'
|
||||
import { parse } from "node-html-parser"
|
||||
import { Main } from "../ui/ui"
|
||||
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||
import SEO from "../components/SEO/SEO"
|
||||
@ -16,12 +16,17 @@ const articleTemplateAmp = ({
|
||||
},
|
||||
},
|
||||
}) => {
|
||||
|
||||
// gatsbyImage to default image
|
||||
const parsedHTML = parse(html, { pre: true })
|
||||
const pictures = [...parsedHTML.querySelectorAll('.gatsby-resp-image-link')]
|
||||
const pictures = [...parsedHTML.querySelectorAll(".gatsby-resp-image-link")]
|
||||
|
||||
pictures.forEach(picture => picture.parentNode.parentNode.set_content(`<img src="${picture.getAttribute('href')}" alt="${picture.querySelector('.gatsby-resp-image-image').getAttribute('alt')}" height="350" />`))
|
||||
pictures.forEach(picture =>
|
||||
picture.parentNode.parentNode.set_content(
|
||||
`<img src="${picture.getAttribute("href")}" alt="${picture
|
||||
.querySelector(".gatsby-resp-image-image")
|
||||
.getAttribute("alt")}" height="350" />`
|
||||
)
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -40,7 +45,11 @@ const articleTemplateAmp = ({
|
||||
<Grid fluid style={{ maxWidth: 800 }}>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<Article data={frontmatter} html={parsedHTML.toString().replace(/loading="[^"]*"/, "")} amp={true} />
|
||||
<Article
|
||||
data={frontmatter}
|
||||
html={parsedHTML.toString().replace(/loading="[^"]*"/, "")}
|
||||
amp={true}
|
||||
/>
|
||||
<Newsletter />
|
||||
<MoreArticles amp={true} />
|
||||
</Col>
|
||||
@ -61,7 +70,7 @@ export const pageQuery = graphql`
|
||||
title
|
||||
image {
|
||||
childImageSharp {
|
||||
fluid(maxWidth: 1400 quality: 100) {
|
||||
fluid(maxWidth: 1400, quality: 100) {
|
||||
...GatsbyImageSharpFluid_withWebp
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ export const pageQuery = graphql`
|
||||
title
|
||||
image {
|
||||
childImageSharp {
|
||||
fluid(maxWidth: 1200 quality: 100) {
|
||||
fluid(maxWidth: 1200, quality: 100) {
|
||||
...GatsbyImageSharpFluid_withWebp
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ export const pageQuery = graphql`
|
||||
title
|
||||
image {
|
||||
childImageSharp {
|
||||
fluid(maxWidth: 650 quality: 100) {
|
||||
fluid(maxWidth: 650, quality: 100) {
|
||||
...GatsbyImageSharpFluid_withWebp
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ export const pageQuery = graphql`
|
||||
title
|
||||
image {
|
||||
childImageSharp {
|
||||
fluid(maxWidth: 650 quality: 100) {
|
||||
fluid(maxWidth: 650, quality: 100) {
|
||||
...GatsbyImageSharpFluid_withWebp
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user