Browse Source

Image Optimization Script (#348)

A build-time script to optimize images. Note that going forward, all images should be placed in `images` instead of `public/images`.

Co-authored-by: Amy <a258wang@uwaterloo.ca>
Reviewed-on: #348
Reviewed-by: Aditya Thakral <a3thakra@csclub.uwaterloo.ca>
Reviewed-by: n3parikh <n3parikh@csclub.uwaterloo.ca>
Co-authored-by: Amy <a258wang@csclub.uwaterloo.ca>
Co-committed-by: Amy <a258wang@csclub.uwaterloo.ca>
pull/358/head
Amy 10 months ago
parent
commit
aae5c9adef
  1. 15
      .drone.yml
  2. 5
      .gitignore
  3. 0
      images/about-us.svg
  4. 0
      images/advice.svg
  5. 0
      images/bubble-decoration.svg
  6. 0
      images/code-of-conduct.svg
  7. 0
      images/constitution.svg
  8. 0
      images/dropdown-icon.svg
  9. 0
      images/events/2021/fall/BOT.png
  10. 0
      images/events/2021/fall/project-program-kickoff.png
  11. 0
      images/get-involved/codey.svg
  12. 0
      images/hamburger.svg
  13. 0
      images/home/codey_sitting.svg
  14. 0
      images/logo-icon.svg
  15. 0
      images/our-supporters/codey.svg
  16. 0
      images/services.svg
  17. 0
      images/shapes/asterisk.svg
  18. 0
      images/shapes/circle.svg
  19. 0
      images/shapes/cross.svg
  20. 0
      images/shapes/dots.svg
  21. 0
      images/shapes/hash.svg
  22. 0
      images/shapes/plus.svg
  23. 0
      images/shapes/ring.svg
  24. 0
      images/shapes/triangle.svg
  25. 0
      images/shapes/triangleBig.svg
  26. 0
      images/shapes/waves.svg
  27. 0
      images/shapes/wavesBig.svg
  28. 0
      images/team/AaronChoo.jpg
  29. 0
      images/team/AdityaThakral.jpg
  30. 0
      images/team/AlexZhang.jpg
  31. 0
      images/team/AndrewWang-Syscom.jpg
  32. 0
      images/team/AndrewWang.jpg
  33. 0
      images/team/AnjingLi.jpg
  34. 0
      images/team/AnnaWang.jpg
  35. 0
      images/team/AthenaLiu.jpg
  36. 0
      images/team/BettyGuo.jpg
  37. 0
      images/team/BonniePeng.jpg
  38. 0
      images/team/BrendanWong.jpg
  39. 0
      images/team/CatherineWan.jpg
  40. 0
      images/team/CharlesZhang.jpg
  41. 0
      images/team/ChrisXie.jpg
  42. 0
      images/team/Codey.jpg
  43. 0
      images/team/DoraSu.jpg
  44. 0
      images/team/EdenChan.jpg
  45. 0
      images/team/EdwinYang.jpg
  46. 0
      images/team/FelixYang.jpg
  47. 0
      images/team/GordonLe.jpg
  48. 0
      images/team/GuneetBola.jpg
  49. 0
      images/team/JaredHe.jpg
  50. 0
      images/team/JasonSang.jpg
  51. 0
      images/team/JuthikaHoque.jpg
  52. 0
      images/team/KailinChan.jpg
  53. 0
      images/team/KallenTu.jpg
  54. 0
      images/team/KarenLee.jpg
  55. 0
      images/team/LinnaLuo.jpg
  56. 0
      images/team/MarkChen.jpg
  57. 0
      images/team/MaxErenberg.jpg
  58. 0
      images/team/NeilParikh.jpg
  59. 0
      images/team/PatrickHe.jpg
  60. 0
      images/team/RavinduAngammana.jpg
  61. 0
      images/team/RaymondLi.jpg
  62. 0
      images/team/RichaDalal.jpg
  63. 0
      images/team/RioLiu.jpg
  64. 0
      images/team/SamHonoridez.jpg
  65. 0
      images/team/SherryLev.jpg
  66. 0
      images/team/ShiHan.jpg
  67. 0
      images/team/StephanieXu.jpg
  68. 0
      images/team/WilliamTran.jpg
  69. 0
      images/team/YanniWang.jpg
  70. 0
      images/team/popup-close.svg
  71. 0
      images/team/team-codey.svg
  72. 0
      images/team/team-member-placeholder.svg
  73. 0
      images/tech-talks.svg
  74. 1
      lib/team.ts
  75. 122
      package-lock.json
  76. 9
      package.json
  77. 107
      scripts/optimize-images.ts

15
.drone.yml

@ -23,25 +23,32 @@ steps:
commands:
- npm run lint
- name: build
- name: optimize-images
image: node:16
depends_on:
- install-deps
commands:
- npm run build:web
- npm run build:images
- name: generate-calendar
image: node:16
depends_on:
- install-deps
commands:
- npm run generate:calendar
- npm run build:calendar
- name: build
image: node:16
depends_on:
- optimize-images
commands:
- npm run build:web
- name: export
image: node:16
depends_on:
- build
- generate-calendar
- build
commands:
- npm run export

5
.gitignore vendored

@ -25,4 +25,7 @@ yarn-debug.log*
yarn-error.log*
# Calendar is automatically generated
/public/events.ics
/public/events.ics
# Images should be optimized
/public/images

0
public/images/about-us.svg → images/about-us.svg

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

0
public/images/advice.svg → images/advice.svg

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

0
public/images/bubble-decoration.svg → images/bubble-decoration.svg

Before

Width:  |  Height:  |  Size: 906 B

After

Width:  |  Height:  |  Size: 906 B

0
public/images/code-of-conduct.svg → images/code-of-conduct.svg

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

0
public/images/constitution.svg → images/constitution.svg

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

0
public/images/dropdown-icon.svg → images/dropdown-icon.svg

Before

Width:  |  Height:  |  Size: 318 B

After

Width:  |  Height:  |  Size: 318 B

0
public/images/events/2021/fall/BOT.png → images/events/2021/fall/BOT.png

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 125 KiB

0
public/images/events/2021/fall/project-program-kickoff.png → images/events/2021/fall/project-program-kickoff.png

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

0
public/images/get-involved/codey.svg → images/get-involved/codey.svg

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

0
public/images/hamburger.svg → images/hamburger.svg

Before

Width:  |  Height:  |  Size: 475 B

After

Width:  |  Height:  |  Size: 475 B

0
public/images/home/codey_sitting.svg → images/home/codey_sitting.svg

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

0
public/images/logo-icon.svg → images/logo-icon.svg

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

0
public/images/our-supporters/codey.svg → images/our-supporters/codey.svg

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

0
public/images/services.svg → images/services.svg

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

0
public/images/shapes/asterisk.svg → images/shapes/asterisk.svg

Before

Width:  |  Height:  |  Size: 836 B

After

Width:  |  Height:  |  Size: 836 B

0
public/images/shapes/circle.svg → images/shapes/circle.svg

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 425 B

0
public/images/shapes/cross.svg → images/shapes/cross.svg

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

0
public/images/shapes/dots.svg → images/shapes/dots.svg

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

0
public/images/shapes/hash.svg → images/shapes/hash.svg

Before

Width:  |  Height:  |  Size: 627 B

After

Width:  |  Height:  |  Size: 627 B

0
public/images/shapes/plus.svg → images/shapes/plus.svg

Before

Width:  |  Height:  |  Size: 365 B

After

Width:  |  Height:  |  Size: 365 B

0
public/images/shapes/ring.svg → images/shapes/ring.svg

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

0
public/images/shapes/triangle.svg → images/shapes/triangle.svg

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 190 B

0
public/images/shapes/triangleBig.svg → images/shapes/triangleBig.svg

Before

Width:  |  Height:  |  Size: 220 B

After

Width:  |  Height:  |  Size: 220 B

0
public/images/shapes/waves.svg → images/shapes/waves.svg

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

0
public/images/shapes/wavesBig.svg → images/shapes/wavesBig.svg

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

0
public/images/team/AaronChoo.jpg → images/team/AaronChoo.jpg

Before

Width:  |  Height:  |  Size: 323 KiB

After

Width:  |  Height:  |  Size: 323 KiB

0
public/images/team/AdityaThakral.jpg → images/team/AdityaThakral.jpg

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

0
public/images/team/AlexZhang.jpg → images/team/AlexZhang.jpg

Before

Width:  |  Height:  |  Size: 877 KiB

After

Width:  |  Height:  |  Size: 877 KiB

0
public/images/team/AndrewWang-Syscom.jpg → images/team/AndrewWang-Syscom.jpg

Before

Width:  |  Height:  |  Size: 907 KiB

After

Width:  |  Height:  |  Size: 907 KiB

0
public/images/team/AndrewWang.jpg → images/team/AndrewWang.jpg

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

0
public/images/team/AnjingLi.jpg → images/team/AnjingLi.jpg

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

0
public/images/team/AnnaWang.jpg → images/team/AnnaWang.jpg

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 246 KiB

0
public/images/team/AthenaLiu.jpg → images/team/AthenaLiu.jpg

Before

Width:  |  Height:  |  Size: 183 KiB

After

Width:  |  Height:  |  Size: 183 KiB

0
public/images/team/BettyGuo.jpg → images/team/BettyGuo.jpg

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

0
public/images/team/BonniePeng.jpg → images/team/BonniePeng.jpg

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

0
public/images/team/BrendanWong.jpg → images/team/BrendanWong.jpg

Before

Width:  |  Height:  |  Size: 4.2 MiB

After

Width:  |  Height:  |  Size: 4.2 MiB

0
public/images/team/CatherineWan.jpg → images/team/CatherineWan.jpg

Before

Width:  |  Height:  |  Size: 786 KiB

After

Width:  |  Height:  |  Size: 786 KiB

0
public/images/team/CharlesZhang.jpg → images/team/CharlesZhang.jpg

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 200 KiB

0
public/images/team/ChrisXie.jpg → images/team/ChrisXie.jpg

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 218 KiB

0
public/images/team/Codey.jpg → images/team/Codey.jpg

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

0
public/images/team/DoraSu.jpg → images/team/DoraSu.jpg

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.2 MiB

0
public/images/team/EdenChan.jpg → images/team/EdenChan.jpg

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

0
public/images/team/EdwinYang.jpg → images/team/EdwinYang.jpg

Before

Width:  |  Height:  |  Size: 847 KiB

After

Width:  |  Height:  |  Size: 847 KiB

0
public/images/team/FelixYang.jpg → images/team/FelixYang.jpg

Before

Width:  |  Height:  |  Size: 968 KiB

After

Width:  |  Height:  |  Size: 968 KiB

0
public/images/team/GordonLe.jpg → images/team/GordonLe.jpg

Before

Width:  |  Height:  |  Size: 733 KiB

After

Width:  |  Height:  |  Size: 733 KiB

0
public/images/team/GuneetBola.jpg → images/team/GuneetBola.jpg

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

0
public/images/team/JaredHe.jpg → images/team/JaredHe.jpg

Before

Width:  |  Height:  |  Size: 336 KiB

After

Width:  |  Height:  |  Size: 336 KiB

0
public/images/team/JasonSang.jpg → images/team/JasonSang.jpg

Before

Width:  |  Height:  |  Size: 461 KiB

After

Width:  |  Height:  |  Size: 461 KiB

0
public/images/team/JuthikaHoque.jpg → images/team/JuthikaHoque.jpg

Before

Width:  |  Height:  |  Size: 277 KiB

After

Width:  |  Height:  |  Size: 277 KiB

0
public/images/team/KailinChan.jpg → images/team/KailinChan.jpg

Before

Width:  |  Height:  |  Size: 862 KiB

After

Width:  |  Height:  |  Size: 862 KiB

0
public/images/team/KallenTu.jpg → images/team/KallenTu.jpg

Before

Width:  |  Height:  |  Size: 1012 KiB

After

Width:  |  Height:  |  Size: 1012 KiB

0
public/images/team/KarenLee.jpg → images/team/KarenLee.jpg

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

0
public/images/team/LinnaLuo.jpg → images/team/LinnaLuo.jpg

Before

Width:  |  Height:  |  Size: 526 KiB

After

Width:  |  Height:  |  Size: 526 KiB

0
public/images/team/MarkChen.jpg → images/team/MarkChen.jpg

Before

Width:  |  Height:  |  Size: 454 KiB

After

Width:  |  Height:  |  Size: 454 KiB

0
public/images/team/MaxErenberg.jpg → images/team/MaxErenberg.jpg

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

0
public/images/team/NeilParikh.jpg → images/team/NeilParikh.jpg

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

0
public/images/team/PatrickHe.jpg → images/team/PatrickHe.jpg

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

0
public/images/team/RavinduAngammana.jpg → images/team/RavinduAngammana.jpg

Before

Width:  |  Height:  |  Size: 897 KiB

After

Width:  |  Height:  |  Size: 897 KiB

0
public/images/team/RaymondLi.jpg → images/team/RaymondLi.jpg

Before

Width:  |  Height:  |  Size: 785 KiB

After

Width:  |  Height:  |  Size: 785 KiB

0
public/images/team/RichaDalal.jpg → images/team/RichaDalal.jpg

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 114 KiB

0
public/images/team/RioLiu.jpg → images/team/RioLiu.jpg

Before

Width:  |  Height:  |  Size: 210 KiB

After

Width:  |  Height:  |  Size: 210 KiB

0
public/images/team/SamHonoridez.jpg → images/team/SamHonoridez.jpg

Before

Width:  |  Height:  |  Size: 341 KiB

After

Width:  |  Height:  |  Size: 341 KiB

0
public/images/team/SherryLev.jpg → images/team/SherryLev.jpg

Before

Width:  |  Height:  |  Size: 223 KiB

After

Width:  |  Height:  |  Size: 223 KiB

0
public/images/team/ShiHan.jpg → images/team/ShiHan.jpg

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

0
public/images/team/StephanieXu.jpg → images/team/StephanieXu.jpg

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

0
public/images/team/WilliamTran.jpg → images/team/WilliamTran.jpg

Before

Width:  |  Height:  |  Size: 738 KiB

After

Width:  |  Height:  |  Size: 738 KiB

0
public/images/team/YanniWang.jpg → images/team/YanniWang.jpg

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 320 KiB

0
public/images/team/popup-close.svg → images/team/popup-close.svg

Before

Width:  |  Height:  |  Size: 377 B

After

Width:  |  Height:  |  Size: 377 B

0
public/images/team/team-codey.svg → images/team/team-codey.svg

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

0
public/images/team/team-member-placeholder.svg → images/team/team-member-placeholder.svg

Before

Width:  |  Height:  |  Size: 175 B

After

Width:  |  Height:  |  Size: 175 B

0
public/images/tech-talks.svg → images/tech-talks.svg

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

1
lib/team.ts

@ -52,6 +52,7 @@ export async function getMemberImagePath(name: string) {
(await getImage(imgPath + ".jpg")) ??
(await getImage(imgPath + ".png")) ??
(await getImage(imgPath + ".gif")) ??
(await getImage(imgPath + ".jpeg")) ??
placeholder;
return img;
}

122
package-lock.json generated

@ -10,8 +10,11 @@
"@mdx-js/loader": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@next/mdx": "11.0.1",
"@squoosh/lib": "^0.4.0",
"date-fns": "^2.11.1",
"date-fns-tz": "^1.1.6",
"fs-extra": "^10.0.0",
"image-size": "^1.0.0",
"next": "11.0.1",
"next-mdx-remote": "3.0.4",
"prettier": "^2.3.0",
@ -21,6 +24,7 @@
"remark-html": "^12.0.0"
},
"devDependencies": {
"@types/fs-extra": "^9.0.13",
"@types/mdx-js__react": "^1.5.3",
"@types/node": "^16.9.1",
"@types/react": "^17.0.14",
@ -990,6 +994,18 @@
"node": ">= 8"
}
},
"node_modules/@squoosh/lib": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.4.0.tgz",
"integrity": "sha512-O1LyugWLZjMI4JZeZMA5vzfhfPjfMZXH5/HmVkRagP8B70wH3uoR7tjxfGNdSavey357MwL8YJDxbGwBBdHp7Q==",
"dependencies": {
"wasm-feature-detect": "^1.2.11",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": " ^12.5.0 || ^14.0.0 || ^16.0.0 "
}
},
"node_modules/@tsconfig/node10": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
@ -1014,6 +1030,15 @@
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true
},
"node_modules/@types/fs-extra": {
"version": "9.0.13",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
"integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/hast": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.1.tgz",
@ -3510,6 +3535,19 @@
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
},
"node_modules/fs-extra": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
"integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -4549,6 +4587,17 @@
"json5": "lib/cli.js"
}
},
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dependencies": {
"universalify": "^2.0.0"
},
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/jsx-ast-utils": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
@ -8963,6 +9012,14 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@ -9104,6 +9161,11 @@
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
},
"node_modules/wasm-feature-detect": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
},
"node_modules/watchpack": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz",
@ -9125,6 +9187,14 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/web-streams-polyfill": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.1.1.tgz",
"integrity": "sha512-Czi3fG883e96T4DLEPRvufrF2ydhOOW1+1a6c3gNjH2aIh50DNFBdfwh2AKoOf1rXvpvavAoA11Qdq9+BKjE0Q==",
"engines": {
"node": ">= 8"
}
},
"node_modules/webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
@ -10052,6 +10122,15 @@
"fastq": "^1.6.0"
}
},
"@squoosh/lib": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.4.0.tgz",
"integrity": "sha512-O1LyugWLZjMI4JZeZMA5vzfhfPjfMZXH5/HmVkRagP8B70wH3uoR7tjxfGNdSavey357MwL8YJDxbGwBBdHp7Q==",
"requires": {
"wasm-feature-detect": "^1.2.11",
"web-streams-polyfill": "^3.0.3"
}
},
"@tsconfig/node10": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
@ -10076,6 +10155,15 @@
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true
},
"@types/fs-extra": {
"version": "9.0.13",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
"integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/hast": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.1.tgz",
@ -11967,6 +12055,16 @@
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
},
"fs-extra": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
"integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -12650,6 +12748,15 @@
"minimist": "^1.2.0"
}
},
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
}
},
"jsx-ast-utils": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
@ -15975,6 +16082,11 @@
"unist-util-is": "^4.0.0"
}
},
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@ -16096,6 +16208,11 @@
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
},
"wasm-feature-detect": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
},
"watchpack": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz",
@ -16110,6 +16227,11 @@
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz",
"integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw=="
},
"web-streams-polyfill": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.1.1.tgz",
"integrity": "sha512-Czi3fG883e96T4DLEPRvufrF2ydhOOW1+1a6c3gNjH2aIh50DNFBdfwh2AKoOf1rXvpvavAoA11Qdq9+BKjE0Q=="
},
"webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",

9
package.json

@ -7,21 +7,25 @@
},
"scripts": {
"dev": "next dev",
"build": "npm run build:web && npm run generate:calendar",
"build": "npm run build:images && npm run build:web && npm run build:calendar",
"build:images": "ts-node ./scripts/optimize-images",
"build:web": "next build",
"build:calendar": "ts-node ./scripts/generate-calendar",
"start": "next start",
"export": "next export",
"lint": "eslint \"{pages,components,lib,hooks,scripts}/**/*.{js,ts,tsx,jsx}\" --quiet",
"lint:fix": "eslint \"{pages,components,lib,hooks,scripts}/**/*.{js,ts,tsx,jsx}\" --quiet --fix",
"generate:calendar": "ts-node ./scripts/generate-calendar",
"check-lockfile": "ts-node ./scripts/check-lockfile"
},
"dependencies": {
"@mdx-js/loader": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@next/mdx": "11.0.1",
"@squoosh/lib": "^0.4.0",
"date-fns": "^2.11.1",
"date-fns-tz": "^1.1.6",
"fs-extra": "^10.0.0",
"image-size": "^1.0.0",
"next": "11.0.1",
"next-mdx-remote": "3.0.4",
"prettier": "^2.3.0",
@ -31,6 +35,7 @@
"remark-html": "^12.0.0"
},
"devDependencies": {
"@types/fs-extra": "^9.0.13",
"@types/mdx-js__react": "^1.5.3",
"@types/node": "^16.9.1",
"@types/react": "^17.0.14",

107
scripts/optimize-images.ts

@ -0,0 +1,107 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
// TODO: upgrade libsquoosh once types are available: https://github.com/GoogleChromeLabs/squoosh/issues/1077
import { cpus } from "os";
import path from "path";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { ImagePool } from "@squoosh/lib";
import fse from "fs-extra";
import { default as getImageDimensions } from "image-size";
const SOURCE_DIRECTORY = "images";
const DESTINATION_DIRECTORY = path.join("public", "images");
// directory where Meet the Team headshots are stored, relative to the source directory
const TEAM_IMAGES_DIRECTORY = path.join("team", "");
const IMAGE_MINIMUM_SIZE = 512;
const GET_ENCODER_FROM_EXTENSION: { [imageExtension: string]: string } = {
jpg: "mozjpeg",
jpeg: "mozjpeg",
png: "oxipng",
};
const ENCODER_OPTIONS: { [encoder: string]: Record<string, unknown> } = {
mozjpeg: {},
oxipng: {},
};
void optimizeImages();
export async function optimizeImages() {
const imagePaths = await getFilePathsInDirectory(SOURCE_DIRECTORY);
await fse.emptyDir(DESTINATION_DIRECTORY);
// maximum number of workers is 8 in order to avoid running out of memory
const numberOfWorkers = Math.min(cpus().length, 8);
const imagePool = new ImagePool(numberOfWorkers);
await Promise.all(
imagePaths.map(async (imagePath) => {
const sourcePath = path.join(SOURCE_DIRECTORY, imagePath);
const destinationPath = path.join(DESTINATION_DIRECTORY, imagePath);
const fileExtension = imagePath.split(".").pop() ?? "";
const encoder = GET_ENCODER_FROM_EXTENSION[fileExtension];
if (!encoder) {
await fse.copy(sourcePath, destinationPath);
return;
}
const rawImageFile = await fse.readFile(sourcePath);
const ingestedImage = imagePool.ingestImage(rawImageFile);
const { width, height } = getImageDimensions(rawImageFile);
await ingestedImage.decoded;
const shouldResize =
imagePath.startsWith(TEAM_IMAGES_DIRECTORY) &&
(width ?? 0) > IMAGE_MINIMUM_SIZE &&
(height ?? 0) > IMAGE_MINIMUM_SIZE;
if (width && height && shouldResize) {
const smallerDimension = width < height ? "width" : "height";
// specifying only one dimension maintains the aspect ratio
const preprocessOptions = {
resize: {
enabled: true,
[smallerDimension]: IMAGE_MINIMUM_SIZE,
},
};
await ingestedImage.preprocess(preprocessOptions);
}
const encodeOptions = { [encoder]: ENCODER_OPTIONS[encoder] };
await ingestedImage.encode(encodeOptions);
const encodedImage = await ingestedImage.encodedWith[encoder];
await fse.outputFile(destinationPath, encodedImage.binary);
})
);
await imagePool.close();
}
async function getFilePathsInDirectory(directory: string): Promise<string[]> {
const entries = await fse.readdir(directory, { withFileTypes: true });
return (
await Promise.all(
entries.map(async (entry) => {
if (entry.isDirectory()) {
const subdirectory = path.join(directory, entry.name);
const subentries = await getFilePathsInDirectory(subdirectory);
return subentries.map((subentry) => path.join(entry.name, subentry));
}
return entry.name;
})
)
).flat();
}
Loading…
Cancel
Save