ãã®è¨äºã¯ç¾
éç¤ ã¢ããã³ãã«ã¬ã³ãã¼ 2024ã®6æ¥ç®ã®è¨äºã§ãã
qiita.com
5æ¥ç®ã®è¨äºã¯ クリエイティブ職向け macOS 個人的おすすめツール 8つ - 羅針盤 技術航海日誌 ã§ããã
ããã«ã¡ã¯ãç¾
éç¤ã®æ£®å·ã§ãã
æè¿ã®ãã¤ãã¼ã ã¯ããã·ã¥ã«ã¼ã ã§ããçã®ã¾ã¾ã¹ã©ã¤ã¹ãã¦ãªãªã¼ããªã¤ã«ã¨é»è¡æ¤ãæ¯ãã ãã§ã¯ã¤ã³ãç¾å³ãã飲ãã¾ãã
ããã·ã¥ã«ã¼ã ã¯å®ãã¦ããæããªãã§ããããªãªã¼ããªã¤ã«ãé«é¨°ãããã¦æ³£ãããã§ãã
2024å¹´è²ããªãã¨ãããã¾ãããï¼2åç®ï¼ã
æ°ã¥ãããä¸çã®97%ãWebP対å¿ãã¦ãã¾ãããããã£ã´ã¼ï¼
PageSpeed Insights ã§ãææãããã®ã§ãSEOãéè¦ãªWebãµã¤ãã®ç»åã¯ããJPGã¯ããã¦WebPã«ãããã¨ã«ãã¾ããã
å°éã®ç»åå¤æã ã£ããGoogleã®Squooshã§ãããã§ãããæ¯åä½æãä½åæã¨ãªãã¨ãªããªãé¢åã§ãã
webPå
cwebp
ã³ãã³ãã使ãã¨JPEGãPNGãWebPã«å¤æã§ãã¾ãã
cwebp -q 80 image.png -o image.webp
ããã使ã£ã¦ä¸æ¬å¤æããã°ãããã§ãããããã使ã£ã¦ãã ããããé¡ããã¾ããâªãã£ã¦æ¸¡ãããç»åãã¡ã¤ã«ã¡ããéã«ã¯JPEGã ãã§ãªãããã¾ã«HEICãæ··ãã£ã¦ããã縦横æ¯ãããããã£ãããæååããã¦ãããã¨ãªãã ãä¸ç©ã§ãã æååãã¯ãã¯ãã©ããããããªãã§ãããä»ã解決ããããã«ã¯ã©ããããããã§ããããï¼
tl;dr ãã¡ãã使ã£ã¦ãã ããï¼ãã ãmacç¨ï¼
#!/bin/bash ######################################################################## # æ¦è¦: # æå®ãã£ã¬ã¯ããªå ã®ç»åãã¡ã¤ã«ãWebPå½¢å¼ã«å¤æãããªãµã¤ãºããã¹ã¯ãªãã ######################################################################## ### è¨å®å¤: ç°å¢å¤æ°ã§æå®ãã ### # å ¥åå ãã£ã¬ã¯ã㪠WEBP_INPUT_DIR=${WEBP_INPUT_DIR-'.'} # åºåå ãã£ã¬ã¯ããªã»ããªãã£ã¯ã¹ WEBP_OUTPUT_DIR=${WEBP_OUTPUT_DIR-'output/'} # åºåãµã¤ãº: æ¨ªå¹ WEBP_TARGET_WIDTH=${WEBP_TARGET_WIDTH-500} # åºåãµã¤ãº: æ£æ¹å½¢ã«ããã (0: ããªã, 1: ãã) WEBP_TARGET_SQUARE=${WEBP_TARGET_SQUARE-0} # ä¸æãã£ã¬ã¯ããªï¼åºæ¬çã«ã¯å¤æ´ä¸è¦ï¼ WEBP_TEMP_DIR=${WEBP_TEMP_DIR-'/tmp/webp'} # ============================================== # ã¡ã¤ã³å¦ç function run { check_dependency copy_temp_to_square convert_webp } # ä¾åãã¼ã«ã®ç¢ºèª function check_dependency { type cwebp >/dev/null 2>&1 || { echo >&2 "[error] 'cwebp' not installed. (e.g. 'brew install webp')"; exit 1; } type identify >/dev/null 2>&1 || { echo >&2 "[error] 'imagemagick' not installed. (e.g. 'brew install imagemagick')"; exit 1; } } # æ£æ¹å½¢åã¨ä¸æãã£ã¬ã¯ããªã¸ã®ã³ãã¼ function copy_temp_to_square { mkdir -p ${WEBP_TEMP_DIR} for img in `find_image ${WEBP_INPUT_DIR}`; do local width=(`identify -format '%w' $img`) local height=(`identify -format '%h' $img`) local file_name=$(basename $img) # æ¡å¼µåæã local file_name_base=${file_name%.*} # æ¡å¼µåæã local file_ext=${img##*.} # æ¡å¼µåã®ã¿ # å°æåã«çµ±ä¸ file_ext=`echo $file_ext | tr '[:upper:]' '[:lower:]'` if [ ${width} -eq ${height} -o "${WEBP_TARGET_SQUARE}" = "0" ]; then if [ "${file_ext}" = "heic" ]; then # HEICã®å ´åã¯jpgã«å¤æ echo "[info] convert HEIC: ${file_name}" convert $img ${WEBP_TEMP_DIR}/${file_name_base}.jpg else # æ¢ã«æ£æ¹å½¢ã»ã¾ãã¯æ£æ¹å½¢åæå®ãªãã®å ´åã¯ãã®ã¾ã¾ãã¡ã¤ã«ã³ãã¼ cp $img ${WEBP_TEMP_DIR}/${file_name} fi continue fi # æ£æ¹å½¢å local crop_size=${width} if [ ${width} -gt ${height} ]; then # heightã«åããã¦crop crop_size=${height} fi local output_file_name=${file_name} if [ "${file_ext}" = "heic" ]; then # HEICã®å ´åã¯jpgã«å¤æ output_file_name=${file_name_base}.jpg fi echo "[info] crop: ${file_name}" convert $img -gravity center -crop ${crop_size}x${crop_size}+0+0 ${WEBP_TEMP_DIR}/${output_file_name} done } # WebPå¤æ function convert_webp { mkdir -p ${WEBP_OUTPUT_DIR} for img in `find_image ${WEBP_TEMP_DIR}`; do echo "[info] convert: ${img}" local width=(`identify -format '%w' $img`) if [ ${width} -gt ${WEBP_TARGET_WIDTH} ]; then local resize_opt="-resize ${WEBP_TARGET_WIDTH} 0" fi cwebp -metadata icc -sharp_yuv -q 80 $img ${resize_opt} -o ${WEBP_OUTPUT_DIR}$(basename ${img%.*}).webp > /dev/null 2>&1 rm -f $img done } # æå®ãã£ã¬ã¯ããªããç»åãã¡ã¤ã«ãæ¤ç´¢ function find_image { local dir=${1-'.'} find -E ${dir} -type f -iregex ".*\.(png|jpg|jpeg|gif|heic)" } # å®è¡ run
ã¨ãããã webp(cwebp
) 㨠imagemagick (convert
㨠identify
) ãå
¥ã£ã¦ããã°ãªãã¨ã使ããã¨æãã¾ãã
ç°¡åã«è§£èª¬ãã¦ããã¨ãcopy_temp_to_square
ã§ç»åãä¸æãã£ã¬ã¯ããªã«ä¿åãã¾ããæ£æ¹å½¢åãå¿
è¦ãªå ´åã¯æ£æ¹å½¢ã«ããããHEICã®å ´åã¯JPEGã«å¤æãã¾ãã
ä¸æãã£ã¬ã¯ããªã«ä¿åãããè£æ£æ¸ã¿ã®JPEG/PNGãã¡ã¤ã«ã convert_webp
ã§ã対象ã®ãã£ã¬ã¯ããªã«WebPåãã¦ä¿åãã¦ãã¾ãã
ãã«ãªã¯ã¨ã¹ãã§ãã§ãã¯
ç»åå°ç¨ã®ãªãã¸ããªãç¨æãã¦ãã¦ãããã§ãã«ãªã¯ã¨ã¹ãåºãã¦ããã£ã¦ãã§ãã¯ãã¦ãã¾ãã ã¨ãããããã¡ã¤ã«ãµã¤ãºã大ãããã®ãç¡ãããGitHub Actionsã§æ©æ¢°çã«å¤å®ãã¾ãã
name: Large File Warning on: pull_request: types: [opened, synchronize] jobs: lfs_warning: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v4 - name: LFS Warning uses: ppremk/[email protected] with: # accepts 'b', 'mb', 'gb' only filesizelimit: '307200b' # 300kb labelName: 'warning/large-file' labelColor: 'ff69b4'
ããã§ã¯300KBã«ãã¦ãã¾ãããç»é¢å ¨ä½ã«åºããç»åçã§ã¯ãã¡ã¤ã«ãµã¤ãºãè¶ ãããã¨ãããã®ã§ããã¯ä»æ¹ãªãã§ãã ããªãã³ã°æ¼ããWebPæ¼ããç¡ããèªåã§æ°ä»ããããããã«ããããã®ã¯ã¼ã¯ããã¼ã§ãã
ãªããWebPã¯GitHubã§è¦ã¥ããã®ã§å¾æ¥Chrome Extensionãç´¹ä»ãã¾ãã
GCSã¸rsync
GCSã¸ã®ãã¡ã¤ã«åæãGitHub Actionsã使ãã¾ãã
ã¾ãã¯ã¹ãã¼ã¸ã³ã°ã¨æ¬çªå ±éã® reuseable workflow ãã説æãã¾ãã
# _common-rsync-static.yml name: Rsync data to GCS (reuseable workflow) on: workflow_call: inputs: TARGET_DIR: required: true type: string ENV_NAME: required: true type: string ENV_URL: required: true type: string secrets: github-token: required: true GCP_PROJECT_ID: required: true GCP_PROJECT_NUMBER: required: true jobs: rsync_gcs: runs-on: ubuntu-latest timeout-minutes: 8 permissions: id-token: write contents: read deployments: write steps: - name: Checkout Repository uses: actions/checkout@v4 # â»1 - name: Check if on main branch for prod dir if: ${{ inputs.TARGET_DIR == 'prod' && github.ref != 'refs/heads/main' }} run: | echo "'prod' dir can only run on the main branch." exit 1 # â»2 - name: Create deployment on GitHub uses: chrnorm/deployment-action@releases/v2 id: deployment with: token: "${{ secrets.GITHUB_TOKEN }}" environment: ${{ inputs.ENV_NAME }} environment-url: ${{ inputs.ENV_URL }} initial-status: "in_progress" # â»3 - id: "auth" uses: "google-github-actions/auth@v2" with: workload_identity_provider: projects/${{ secrets.GCP_PROJECT_NUMBER }}/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider service_account: image-deploy-github-actions@${{ secrets.GCP_PROJECT_ID }}.iam.gserviceaccount.com project_id: ${{ secrets.GCP_PROJECT_ID }} # â»3 - name: "Set up Cloud SDK" uses: "google-github-actions/setup-gcloud@v2" with: project_id: ${{ secrets.GCP_PROJECT_ID }} # â»4 # å é ã . 以å¤ã®ãã¡ã¤ã«ã»ãã£ã¬ã¯ããªãå ¨ã¦ã¢ãããã¼ãï¼å·®åã¯åé¤ãããï¼ - name: Rsync to GCS run: | gsutil -m rsync -x '(^|/)\.' -r -d ./static.example.com/image gs://static.example.com/${{ inputs.TARGET_DIR }} # â»2 - name: Update deployment status (success) if: success() uses: chrnorm/deployment-status@v2 with: token: "${{ secrets.GITHUB_TOKEN }}" state: 'success' deployment-id: ${{ steps.deployment.outputs.deployment_id }} # â»2 - name: Update deployment status (failure) if: failure() uses: chrnorm/deployment-status@v2 with: token: "${{ secrets.GITHUB_TOKEN }}" state: 'failure' deployment-id: ${{ steps.deployment.outputs.deployment_id }}
åæã¨ãã¦ãããã§ã¯ã¹ãã¼ã¸ã³ã°ã¨æ¬çªã¨ã§åãGCSãã±ããã使ã£ã¦ãã¾ããï¼åä¸ãã¡ã¤ã³ã«ãããã®ã§ï¼
æåã®ããªãã£ã¯ã¹ã§åãã¦ãã¾ãï¼èª¬æã®åãããããã®ãã /prod/
, /dev/
ã«ãã¾ããï¼
- â»1 ã§ã¯æ¬çªã®ãã£ã¬ã¯ããª
/prod/
㯠mainãã©ã³ã ã®ã¿ã§å¯è½ã«ãã¦ãã¾ããééãã¦å¤ãªãã©ã³ããæ¬çªã§ä½¿ããªãããã«ãã¦ãã¾ãã - â»2 ã§ã¯GitHub Deploymentsã®ããã®è¨å®ã§ããç¡ãã¦ãããã§ãããããã¨åãããããã®ã§ä¾¿å©ã
- â»3 ã§ã¯Workload Identity ã§ã®GCPèªè¨¼ããã¦ãã¾ãããµã¼ãã¹ã¢ã«ã¦ã³ãåããããã¤ãã¼åã¯åºå®ã«ãã¦ãã¾ããå¿ è¦ã«å¿ãã¦å¤ãã¦ãã ããã
- â»4 ã§ã¯ ãªãã¸ããªå ã® /static.example.com/image/ ã¨ãããã£ã¬ã¯ããªé ä¸ã«ãããã¡ã¤ã«ãå ¨ã¦GCSã¸ã¢ãããã¼ããã¦ãã¾ãããã±ããåï¼ãã¡ã¤ã³ï¼ã¯é©å®å¤ãã¦ãã ããã
次ã«åç°å¢ã®ã¯ã¼ã¯ããã¼ã§ãããããã§ã¯éçºã»ã¹ãã¼ã¸ã³ã°ç¨ã®ãµã³ãã«ã«ãªãã¾ãã ï¼æ¬çªãå 容ã¯ä¸ç·ã§ããï¼
name: Rsync data to GCS (dev) on: workflow_dispatch: jobs: rsync_gcs_development: uses: <my-org-name>/<repo-name>/.github/workflows/_common-rsync-static.yml@main with: TARGET_DIR: dev ENV_NAME: development ENV_URL: https://console.cloud.google.com/storage/browser/static.example.com secrets: github-token: ${{ secrets.GITHUB_TOKEN }} GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} GCP_PROJECT_NUMBER: ${{ secrets.GCP_PROJECT_NUMBER }}
TARGET_DIR
ã¯/prod/
ã/dev/
ãå ¥ãããªãã£ã¯ã¹ã®é¨åã§ãENV_NAME
㯠GitHub Deployment ã§ä½¿ãç°å¢åã§ãENV_URL
ã GitHub Deployment ã§ä½¿ãã ããªã®ã§ãã¡ãã¨è¨å®ããªãã¦ãããã§ãsecrets.GCP_PROJECT_ID
ã¨secrets.GCP_PROJECT_NUMBER
ã¯GCPã®ã¦ã§ã«ã«ã ãã¼ã¸ã«ããããã¸ã§ã¯ãIDã¨çªå·ãå ¥ãã¦ãã ãã
https://console.cloud.google.com/welcome
ãã¦ãä»æ¥ã¯ããã§å¯ã¾ãã ç´ æµãªWebPçæ´»ãããããã¿ãªããã