Skip to content

Commit

Permalink
use webp as default; add responsive image
Browse files Browse the repository at this point in the history
  • Loading branch information
homuch authored and weiber2002 committed May 2, 2024
1 parent 48ff2a3 commit d7eacc7
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 11 deletions.
6 changes: 6 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"html-react-parser": "^1.2.8",
"html-webpack-plugin": "^5.3.2",
"jodit-react": "^1.1.1",
"lazysizes": "^5.3.2",
"path": "^0.12.7",
"prop-types": "^15.7.2",
"react": "^17.0.2",
Expand Down Expand Up @@ -78,7 +79,9 @@
"eslint-plugin-prettier": "^3.4.0",
"prettier": "2.3.2",
"react-scripts": "^4.0.3",
"responsive-loader": "3.1.2",
"sass": "^1.35.1",
"sharp": "0.32.6",
"tsparticles": "^2.0.6"
},
"scripts": {
Expand All @@ -99,5 +102,8 @@
"engines": {
"node": ">=10",
"npm": ">=6"
},
"imports": {
"#assets/*": "./src/assets/*"
}
}
62 changes: 62 additions & 0 deletions client/src/components/ResImage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react'
import propType from 'prop-types'
import { CImage } from '@coreui/react'

import 'lazysizes'
import 'lazysizes/plugins/attrchange/ls.attrchange'
import 'lazysizes/plugins/respimg/ls.respimg.js'

/**
* ResImage component displays an image with lazy loading support and multiple image sources.
*
* @component
* @param {Object} props - The component props.
* @param {Object} props.avifSrc - The AVIF image source object.
* @param {Object} props.jpgSrc - The JPG image source object.
* @param {Object} props.webpSrc - The WebP image source object.
* @param {string} props.alt - The alternative text for the image.
* @param {boolean} props.lazySize - Enable this help provide an actual size automatically to load proper size size, but since it will deffer the image load, **don't use it for images that user can see at the first glance.**
* @param {string} props.sizes - The sizes attribute for the image. For images near to top, please use it instead of lazySize.
* @param {string} props.className - The CSS class name for the image.
* @returns {JSX.Element} The rendered ResImage component.
*/
const ResImage = ({ avifSrc, jpgSrc, webpSrc, alt, lazySize, sizes, ...props }) => {
return lazySize ? (
<picture>
{avifSrc && <source data-srcset={avifSrc.srcSet} type="image/avif" data-sizes="auto" />}
{webpSrc && <source data-srcset={webpSrc.srcSet} type="image/webp" data-sizes="auto" />}
<CImage
{...props}
data-src={jpgSrc || webpSrc || avifSrc}
data-srcset={jpgSrc.srcSet}
data-sizes="auto"
alt={alt || null}
className={`lazyload ${props.className || ''}`}
/>
</picture>
) : (
<picture>
{avifSrc && <source srcSet={avifSrc.srcSet} type="image/avif" sizes={sizes || 'auto'} />}
{webpSrc && <source srcSet={webpSrc.srcSet} type="image/webp" sizes={sizes || 'auto'} />}
<CImage
{...props}
src={jpgSrc || webpSrc || avifSrc}
srcSet={jpgSrc.srcSet}
sizes={sizes || 'auto'}
alt={alt || null}
/>
</picture>
)
}

ResImage.propTypes = {
avifSrc: propType.any,
jpgSrc: propType.any,
webpSrc: propType.any,
alt: propType.string,
className: propType.string,
lazySize: propType.bool,
sizes: propType.string,
}

export default ResImage
3 changes: 2 additions & 1 deletion client/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import AppHeaderDropdown from './header/AppHeaderDropdown'
import AppSidebar from './AppSidebar'
import AppBackground from './AppBackground'
import { AppFallbackRender } from './AppFallbackRender'

import ResImage from './ResImage'
export {
AppContent,
AppFooter,
Expand All @@ -14,4 +14,5 @@ export {
AppSidebar,
AppBackground,
AppFallbackRender,
ResImage,
}
40 changes: 30 additions & 10 deletions client/src/views/out/home/services/Services.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
/* eslint-disable prettier/prettier */
import { CContainer, CRow } from '@coreui/react'
import React from 'react'
import { CContainer, CRow, CImage } from '@coreui/react'
import studyabroad from '../../../../assets/images/studyabroad.png'
import column from '../../../../assets/images/column.png'
import communicate from '../../../../assets/images/communicate.png'
import career from '../../../../assets/images/career.png'

import { ResImage } from '../../../../components'
const Services = () => {
return (
<div id="services" className="text-center section">
Expand All @@ -21,7 +17,13 @@ const Services = () => {
<div className="col-xs-6 col-sm-3">
{' '}
<div className="square-img-container">
<CImage src={communicate} alt="..." className="img img-fluid"></CImage>
<ResImage
avifSrc={require('#assets/images/communicate.png?{format: "avif", sizes:[310, 520]}')}
jpgSrc={require('#assets/images/communicate.png?{format: "jpg", sizes:[310, 520]}')}
alt="..."
className="img img-fluid"
sizes="(max-width: 575px) 520px, 300px"
/>
</div>
<h3>通訊錄</h3>
<p>
Expand All @@ -33,7 +35,13 @@ const Services = () => {
<div className="col-xs-6 col-sm-3">
{' '}
<div className="square-img-container">
<CImage src={career} alt="..." className="img img-fluid"></CImage>
<ResImage
avifSrc={require('#assets/images/career.png?{format: "avif", sizes:[310, 520]}')}
jpgSrc={require('#assets/images/career.png?{format: "jpg", sizes:[310, 520]}')}
alt="..."
className="img img-fluid"
sizes="(max-width: 575px) 520px, 300px"
/>
</div>
<h3>徵才求職</h3>
<p>
Expand All @@ -45,7 +53,13 @@ const Services = () => {
<div className="col-xs-6 col-sm-3">
{' '}
<div className="square-img-container">
<CImage src={studyabroad} alt="..." className="img img-fluid"></CImage>
<ResImage
avifSrc={require('#assets/images/studyabroad.png?{format: "avif", sizes:[310, 520]}')}
jpgSrc={require('#assets/images/studyabroad.png?{format: "jpg", sizes:[310, 520]}')}
alt="..."
className="img img-fluid"
sizes="(max-width: 575px) 520px, 300px"
/>
</div>
<h3>留學資訊</h3>
<p>
Expand All @@ -57,7 +71,13 @@ const Services = () => {
<div className="col-xs-6 col-sm-3">
{' '}
<div className="square-img-container">
<CImage src={column} alt="..." className="img img-fluid"></CImage>
<ResImage
avifSrc={require('#assets/images/column.png?{format: "avif", sizes:[310, 520]}')}
jpgSrc={require('#assets/images/column.png?{format: "jpg", sizes:[310, 520]}')}
alt="..."
className="img img-fluid"
sizes="(max-width: 575px) 520px, 300px"
/>
</div>
<h3>採訪文章</h3>
<p>
Expand Down
17 changes: 17 additions & 0 deletions client/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,23 @@ module.exports = {
test: /\.(scss)$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(png|jpe?g|gif|webp|avif)$/i,
use: [
{
loader: 'responsive-loader',
options: {
adapter: require('responsive-loader/sharp'),
sizes: [480, 960, 1500],
placeholder: true,
placeholderSize: 40,
pregressive: true,
format: 'webp', // ? or 'avif' in the future
},
},
],
type: 'javascript/auto',
},
{
test: /\.(png|svg|jpg|gif)$/,
use: {
Expand Down

0 comments on commit d7eacc7

Please sign in to comment.