Skip to content

Commit

Permalink
Merge pull request #92 from igor-starostenko/develop
Browse files Browse the repository at this point in the history
v2.3.2
  • Loading branch information
igor-starostenko authored Jan 9, 2023
2 parents 11ecfcd + ddc68ff commit 5b1faa2
Show file tree
Hide file tree
Showing 16 changed files with 246 additions and 55 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ out

public/browserconfig.xml
public/icons/
public/images/
public/manifest.json
public/manifest.webmanifest
public/sitemap.xml
Expand Down
1 change: 1 addition & 0 deletions amplify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ frontend:
cache:
paths:
- node_modules/**/*
- public/images/**/*
15 changes: 10 additions & 5 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
const imageOptimization = (process.env.IMAGE_OPTIMIZATION || '1') === '1';

const next_config = {
images: {
domains: ['images.ctfassets.net'],
...{ ...(imageOptimization ? {} : { loader: 'custom' }) },
loader: 'custom',
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
},
env: {
imageOptimization,
nextImageExportOptimizer_imageFolderPath: 'public/images',
nextImageExportOptimizer_exportFolderPath: 'out',
nextImageExportOptimizer_quality: 50,
nextImageExportOptimizer_storePicturesInWEBP: true,
nextImageExportOptimizer_generateAndUseBlurImages: true,
},
productionBrowserSourceMaps: true,
};

module.exports = { ...next_config };
module.exports = next_config;
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
"license": "MIT",
"author": "Igor Starostenko <contact@igorstar.com>",
"scripts": {
"analyze": "source-map-explorer .next/static/**/*.js",
"dev": "next dev",
"start": "next start",
"format": "prettier --config ./.prettierrc --write src/**/*.js",
"lint": "next lint",
"build:dir": "mkdirp ./public/icons/",
"build:analyze": "npm run build && npm run analyze",
"build:dir": "mkdirp ./public/icons/ && mkdirp ./public/images/",
"build:favicons": "node scripts/favicons",
"build:images": "npm run contentful:assets && next-image-export-optimizer --exportFolderPath=out --nextConfigPath=next.config.js",
"build:sitemap": "next-sitemap",
"build": "npm run build:dir && npm run build:favicons && next build && npm run build:sitemap && next export",
"build": "npm run build:dir && npm run build:favicons && next build && npm run build:sitemap && next export && npm run build:images",
"contentful:assets": "node scripts/contentful_assets.js",
"contentful:backup": "node scripts/contentful_backup.js",
"contentful:export": "contentful space export --space-id $CONTENTFUL_SPACE_ID",
"test:lighthouse": "npx ava scripts/lighthouse.test.js"
Expand All @@ -30,6 +34,7 @@
"dotenv": "^10.0.0",
"framer-motion": "^5.2.1",
"next": "^13.1.1",
"next-image-export-optimizer": "^1.1.2",
"prop-types": "^15.6.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand All @@ -56,6 +61,7 @@
"next-sitemap": "^3.1.43",
"node-gyp": "^9.3.1",
"prettier": "^2.4.1",
"source-map-explorer": "^2.5.3",
"webpack": "^5.75.0"
}
}
53 changes: 53 additions & 0 deletions scripts/contentful_assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const fs = require('fs');
const fetch = require('node-fetch');
const contentful = require('contentful');
require('dotenv').config();

const imageDirectory = process.env.IMAGE_DIRECTORY || './public/images/';
const replaceImages = parseInt(process.env.REPLACE_IMAGES || '0');
const limit = parseInt(process.env.CONTENTFUL_LIMIT || '100');

const client = contentful.createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_DELIVERY_TOKEN,
});

const saveFile = async (i, url, name) => {
const path = imageDirectory + name;
if (!replaceImages && fs.existsSync(path)) {
return console.log(`${i + 1}. ${path} already exists`);
}

const response = await fetch(url);
const buffer = await response.buffer();
fs.writeFile(path, buffer, () =>
console.log(`${i + 1}. Saved ${url} into ${path}`)
);
};

const getAllAssets = async (options) => {
let records = { items: [] };
// Ensure we load all records, regardless of the API limit
while (records.total != 0 && records.items.length < (records.total || 1)) {
let response = await client.getAssets({
...options, // skip can't be overriden
skip: records.items.length,
});
records = { ...response, items: [...records.items, ...response.items] };
}
return records;
};

const saveAllAssets = async (items) => {
for (let i = 0; i < items.length; i += 1) {
const src = `https:${items[i].fields.file.url}`;
const fileName = `${items[i].sys.id}_${items[i].fields.file.fileName}`;
await saveFile(i, src, fileName);
}
};

(async () => {
const assets = await getAllAssets({ limit });
console.log(`Total assets: ${assets.total}`);
await saveAllAssets(assets.items);
})();
22 changes: 10 additions & 12 deletions src/components/article/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ const Article = ({
}}
>
<Image
src={`https:${image.file.url}`}
alt={title}
{...image.file.details.image}
src={image.src}
backupSrc={image.backupSrc}
alt={image.alt}
width={image.width}
height={image.height}
/>
</Thumb>
</SLink>
Expand All @@ -75,15 +77,11 @@ Article.propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
image: PropTypes.shape({
file: PropTypes.shape({
url: PropTypes.string.isRequired,
details: PropTypes.shape({
image: PropTypes.shape({
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
}).isRequired,
}).isRequired,
}).isRequired,
src: PropTypes.string.isRequired,
backupSrc: PropTypes.string,
alt: PropTypes.string.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
}),
date: PropTypes.string.isRequired,
tags: PropTypes.arrayOf(PropTypes.string),
Expand Down
2 changes: 1 addition & 1 deletion src/components/filter/filter.css.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const Categories = styled.div`
a {
text-decoration: none;
color: ${colors.grey};
color: ${colors.darkGrey};
&:hover {
color: inherit;
Expand Down
4 changes: 3 additions & 1 deletion src/components/gallery/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const GalleryImage = ({ index, onClick, photo, margin }) => (
onClick={(e) => onClick(e, { index, photo })}
key={photo.id}
src={photo.src}
alt={photo.title}
backupSrc={photo.backupSrc}
alt={photo.alt}
width={photo.width}
height={photo.height}
/>
Expand All @@ -34,6 +35,7 @@ GalleryImage.propTypes = {
title: PropTypes.string.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
backupSrc: PropTypes.string,
src: PropTypes.string.isRequired,
}).isRequired,
margin: PropTypes.number,
Expand Down
4 changes: 2 additions & 2 deletions src/components/image/image.css.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from 'styled-components';
import Image from 'next/image';
import ExportedImage from 'next-image-export-optimizer';

export const ImageWrapper = styled.div`
box-shadow: -1px 3px 6px 1px rgba(0, 0, 0, 0.3);
Expand All @@ -19,7 +19,7 @@ export const ImageWrapper = styled.div`
}
`;

export const SImage = styled(Image)`
export const SImage = styled(ExportedImage)`
max-width: 100%;
height: auto;
`;
31 changes: 14 additions & 17 deletions src/components/image/image.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
import React from 'react';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { SImage } from './image.css';

const noOptimization = ({ src }) => src;

/* For contentful query params see
https://www.contentful.com/developers/docs/references/images-api/#/reference
*/
const BaseImage = ({ alt, src, query = '?fm=webp', ...rest }) => (
<SImage
alt={alt}
src={src + query}
{...(process.env.imageOptimization
? {} // image optimization is enabled by default with SSR
: {
loader: noOptimization,
unoptimized: true,
})}
{...rest}
/>
);
const BaseImage = ({ alt, src, backupSrc, ...rest }) => {
const [isError, setIsError] = useState(false);

if (isError) {
/* eslint-disable @next/next/no-img-element */
return <img src={backupSrc} alt={alt} {...rest} />;
}

return (
<SImage src={src} alt={alt} onError={() => setIsError(true)} {...rest} />
);
};

BaseImage.propTypes = {
src: PropTypes.string.isRequired,
alt: PropTypes.string.isRequired,
query: PropTypes.string,
backupSrc: PropTypes.string,
};

export default BaseImage;
3 changes: 2 additions & 1 deletion src/components/recommendations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const Recommendations = ({ category, posts }) => (
<Thumb>
<Image
src={post.thumbnail.src}
alt={post.thumbnail.description || post.title}
backupSrc={post.thumbnail.backupSrc}
alt={post.thumbnail.alt || post.title}
width={post.thumbnail.width}
height={post.thumbnail.height}
/>
Expand Down
3 changes: 1 addition & 2 deletions src/components/selfie/selfie.css.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import styled from 'styled-components';
import BaseImage from 'components/image/image';
import Box from 'components/box';
import MEDIA from 'helpers/mediaTemplates';

export const Image = styled(BaseImage)`
export const Image = styled.img`
cursor: initial;
border-radius: 50%;
border: 2px solid powderblue !important;
Expand Down
16 changes: 12 additions & 4 deletions src/contentClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,26 @@ const parseFields = (item) => {
};
};

const parseImage = (file) => {
const parseImage = (id, title, file) => {
const { width, height } = file.details.image;
return {
src: `https:${file.url}`,
src: `/images/${id}_${file.fileName}`,
backupSrc: `https:${file.url}`,
alt: title,
width,
height,
};
};

const parseItem = (data) => {
const { file, ...fields } = parseFields(data);
return { ...fields, ...parseImage(file) };
const item = parseFields(data);

if (!item) {
return null;
}

const { id, title, file, ...fields } = item;
return { id, ...fields, ...parseImage(id, title, file) };
};

const getEntries = async (options) => {
Expand Down
4 changes: 2 additions & 2 deletions src/pages/[category].js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
getEntries,
getAllEntries,
getCategoriesPaths,
parseFields,
parseItem,
} from 'contentClient';
import Category from 'components/category';

Expand Down Expand Up @@ -32,7 +32,7 @@ export const getStaticProps = async ({ params }) => {
...posts,
/* eslint-disable no-unused-vars */
items: posts.items.map(({ thumbnail, images, ...fields }) => ({
thumbnail: parseFields(thumbnail),
thumbnail: parseItem(thumbnail || {}),
...fields,
})),
},
Expand Down
4 changes: 2 additions & 2 deletions src/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { getEntries, getAllEntries, parseFields } from 'contentClient';
import { getEntries, getAllEntries, parseItem } from 'contentClient';
import Category from 'components/category';

const Index = ({ page, posts }) => <Category page={page} posts={posts} />;
Expand All @@ -25,7 +25,7 @@ export const getStaticProps = async () => {
...posts,
/* eslint-disable no-unused-vars */
items: posts.items.map(({ thumbnail, images, ...fields }) => ({
thumbnail: parseFields(thumbnail),
thumbnail: parseItem(thumbnail || {}),
...fields,
})),
},
Expand Down
Loading

0 comments on commit 5b1faa2

Please sign in to comment.