サクサク読めて、アプリ限定の機能も多数!
トップへ戻る
GPT-4o
zenn.dev/catnose99
2022年10月にHashnode(英語圏では人気のある技術ブログ作成サービス)に脆弱性を報告したのですが、最近になって修正されたようなので記事にしておきます。 Hashnode社の方には脆弱性について記事にすることの許可をもらっています[1]。 Hashnodeのカスタムドメイン設定機能について Hashnodeの目玉機能として、ユーザーごとにブログを作成し、そのブログにカスタムドメインを紐づけられる機能があります。カスタムドメインのブログであっても、LikeやフォローといったHashnodeの認証が絡む機能を使うことができます。 カスタムドメインが設定されたブログでもフォローなどの機能が使える hashnode.comにログインしていれば、ユーザーのブログ(example.com)を開いたときにもログイン状態が保持されているというわけです。 クロスドメインでログイン状態を保持するのはめ
/* 一部省略しています。完成形のCSSはCodePenをチェックしてください */ .container { position: relative; } .text { margin: 0; /* 見出しのマージンを消しておく */ position: absolute; /* 絶対配置で画像の中央に配置 */ left: 50%; top: 50%; transform: translate(-50%, -50%); width: 100%; color: #FFF; font-weight: 800; font-size: 100px; mix-blend-mode: overlay; /* 👈 ポイント */ } mix-blend-modeのオーバーレイ(overlay)とは MDNにもあまり詳しい解説が載っていなかったので、仕様書を読んでみます。引用とざっくりとした意訳を載せ
iOSのブラウザ(Safari、Chromeなどなど)で体験の良いWYSIWYGエディタを作るのは無理ゲーである。色々と理由はあるが、いちばん辛いのはバーチャルキーボード(オンスクリーンキーボード)を表示したときの挙動だと思っている。 キーボードが表示されているときにposition: fixedが効かない WYSIWYGエディタではテキストの装飾や画像挿入などのボタンを画面のどこかに固定したくなることが多い。 しかし、iOS Safariではキーボードが表示されているときにposition: fixedなどのCSSだけで画面上に何かを固定させることが難しい。 position: fixedとbottom: 0 やtop: 0を使っても要素が画面に固定されない仕様となっている(これはposition: stickyにしても同じ)。 ワークアラウンドも上手く動かない noteやscrapbo
メモ。調べたいURLを入力しHTTPを選んで実行すると、各国からリクエストしたときのレスポンスタイムやサーバーのIPアドレスを表示してくれる。
Ruby on Rails Action Mailer でのマルチパートメールの作り方 HTMLテンプレートとTEXTテンプレートを用意する方法 メールを送るときに html と text のボディを明示的に指定する方法 がある。 HTMLテンプレートとTEXTテンプレートを用意する方法 Rails ガイドが参考になる。 html と text のボディを明示的に指定する方法 英語のほうのガイドが参考になる。 class UserMailer < ApplicationMailer default from: 'notifications@example.com' def welcome_email @user = params[:user] @url = 'http://example.com/login' mail(to: @user.email, subject: 'Welcome
こんなWebサービスをリリースしたので、技術的な話をまとめておこうと思います。 元々このサービスは、趣味の延長線のような感じで開発を始めました。競合にあたるnoteやはてなブログなどのサービスが確固たる地位を築いているということもあり、「お金にはならないだろうけど、自分の趣味を詰め込んだものにしよう」というゆるい気持ちで開発を続けています(楽しい)。 選定の方針 趣味と言っても文章投稿サービスなので、ユーザーが少数であったとしても長期間運営しなければなりません。そのため、ユーザー数が少なければランニングコストが数千円/月以下、ユーザー数が増えたときは段階的にコストが上がるように選定を行いました。 アプリケーション フルスタックNext.jsアプリケーションをCloud Runにデプロイしています。各APIエンドポイントはNext.jsのAPI Routesで生やしています。 Next.js
https://sizu.me ではCSSやJSなどの静的ファイルをstatic.sizu.meから読み込んでいる。しかしブラウザがsizu.meから返されたHTMLを読んでからstatic.sizu.meへのDNS Lookupなどを始めるのは効率が悪い。 そこで103 Early Hintsによりstatic.sizu.meへのpreconnectがなる早で開始されるようにできないか試してみた。 ちなみに2023/11/25時点では、103 Early Hintsに一部のブラウザが対応していないことに注意(caniuse)。未対応のブラウザ向けにはheadのなるべく上にpreconnect用のlinkを配置しておく。
Webサービスのステージング環境をアクセス制限をCloudflare Zero Trustでやってみたところ、とても手軽でちょうど良かった。特に必要な知識はなかったが、今後同じことをやりたくなったときのために設定内容をメモしておく。 やったこと Cloudflare Zero Trustで「特定のメールアドレスの所有者」にだけWebサイトへのアクセスを許可する(ここでは例としてhttps://app.example.com/*へのアクセスを制限する) 前提 ドメインをCloudflareで管理しており、DNS設定でプロキシモードが有効になっていること 設定その1: ログイン方法を追加しておく Cloudflareにログインした状態でZero Trustを開く Settings → Authentication → Login methodsでOne-time PINを追加しておく 指定した
最近はじめた新しいプロジェクトでは、オブジェクトストレージとしてCloudflare R2を選んでいます。R2の何よりも魅力は良心的な料金設定です。 バージョニングに対応してない問題 R2は2023年10月時点ではS3やGoogle Cloud Storageにあるようなバージョニング機能には対応していません。 要望は挙がっていますが(R2 Object Versioning and Replication - Cloudflare Community)今のところ特に動きはありません。 バージョニング機能なしの場合、コンソールやAPI経由でうっかりオブジェクトを削除/上書きしてしまったようなときに復元ができません。ユーザーのアップロードしたファイルを保管するようなWebサービスであれば、これは大きな不安要素になると思います。 rcloneでCloud Storageへバックアップ バックア
Zennを立ち上げた人
今見てるWebページのOG画像をチェックしたくなるときがある。ソースコードを開いて画像のURLをコピペするのは面倒だし、ブラウザ拡張機能は本当に信頼できるものしか入れたくない。というわけで、ちょっとしたコードを書いて使い回せるようにしてみる。 1. ページ遷移で開く location.href = document.querySelector('meta[property="og:image"]').content
# 削除されるブランチ一覧を表示 git branch | grep -v "main\|*" # 削除を実行 git branch | grep -v "main\|*" | xargs -r git branch -D
アクセシビリティを考慮しつつ<input type="file" />を装飾する方法はこの記事にとても分かりやすくまとまっています。 個人的にもdisplay: noneを指定した<input type="file" />を<button />から発火するやり方が装飾がしやすくていいなと思いました。 この記事で紹介されてる方法をReactで実装するにはざっくりと以下のようになると思います。 import { useRef } from 'react'; export const Example = () => { const inputFileRef = useRef<HTMLInputElement>(null); return ( <> {/* クリック時に input[type="file"] を発火 */} <button onClick={() => inputFileRef.c
HTMLの<input type="range">を使うと、簡単にレンジ入力欄(スライダー)を設置できますが、デフォルトでは見た目がいまいちです。 FireFox 83.0の場合 また、ブラウザによってレンジ入力欄のデフォルトのスタイルが異なります。 CSSで<input type="range">を良い感じに装飾する レンジ入力欄はCSSで装飾できます。今回はそのサンプルを載せておきます。 例として<input type="range">にinput-rangeというクラス名をあてておきます。
主な使用サービス/ライブラリは以下です。 Next.js …アプリケーションのフレームワーク Vercel …デプロイ先 PlanetScale …サーバーレスDB(MySQL)。ORMにはPrismaを使用 Upstash …サーバーレスでRedisを使えるやつ Cloudflare R2 …画像のアップロード先 Open AI API ここに落ち着くまでに紆余曲折あったので、少し詳しく説明しておきます。 Next.js on Vercel 利用しているフレームワークはNext.jsです。クライアントからのデータの取得・更新リクエストはAPI Routesから受け付けるようにしています。 アプリケーションのデプロイ先はVercelにしました。最初はNext.js on Cloudflare Workersをやろうとしたのですが、辛い部分が多くて断念しました。 余談)なぜNext.jsをC
zxはJavaScriptでshellを書けるライブラリです。 zxの基本的な解説についてはこちらの記事が分かりやすいと思います。 仕事でjsonファイルの内容をmarkdownとして○○.mdに出力したいケースがあったので試しにzxでやってみることにしました。
先日だれでもAIメーカーというWebサービスをリリースしました。このサービスは例によってOpenAI APIを使っており、トークンの使用量がランニングコストに大きく影響します。 また、気軽に使ってもらえるよう未ログインでも使用できる仕様にしているため、気をつけないと悪意のある人に大量にトークンを使用されてしまう可能性があります。 ノーガードだとどうなるか 例えば、POST /api/askという「リクエストbodyのpromptの値を取り出し、OpenAI APIのChat Completionsに投げる」という単純なエンドポイントを作ったとします。 「未ログインでも使ってもらいたいから」と認証を一切しなかった場合どうなるでしょうか? 悪意のある攻撃者に見つかれば、promptを上限ギリギリの長さの文章に設定したうえで、/api/askに対してDoS攻撃するかもしれません。 トークンを大量
前提 前提として、Cloud Runで最小インスタンス(min-instances)を1以上に設定した場合、インスタンスが常に稼働するようになった分だけ課金される。最小インスタンスについてのドキュメントにも「この方法で実行されているインスタンスは課金対象になります」と記載がある。 疑問 Cloud Runで最小インスタンスを1以上に設定した場合、トラフィックが流れていない過去のリビジョン(インスタンス)分の課金が発生するのか疑問を持ったので調査。
調査結果まとめ 日本の真ん中あたりから東京リージョンのCloudRunにアクセスしたときのTTFB(Time To First Byte)のざっくり計測結果。詳細は後述。 Cloud Runのデフォルトドメインに直接アクセスした場合: 28msくらい Cloud Runにカスタムドメインをマッピングした場合: 99msくらい さらにCloudflareからCNAMEで指した場合: 114msくらい Cloudflare WorkersでCloud Runのデフォルトドメインをプロキシした場合: 44msくらい Cloud Run + Cloud Load Balancing(CDNなし): 31msくらい Cloud Runの東京リージョンで「カスタムドメインのマッピング」を利用するとレイテンシが発生する 2023年1月現在、Cloud Runのドキュメントの既知の問題には以下の記載があり
僕が作るWebアプリでは、日付の表示にだいたいDay.jsを使っています。Day.jsを使えば相対日時の表示も簡単です。例えば、以下のようにして相対日時を出力できます。 import dayjs from "dayjs" // 相対日時のプラグインを有効化 import relativeTime from "dayjs/plugin/relativeTime" dayjs.extend(relativeTime) // 日本語で ◯日前 のように表示する場合 import 'dayjs/locale/ja'; dayjs.locale('ja'); // 指定時刻から現在時刻との相対時間を取得 dayjs('2021-01-24T01:00:00').fromNow() // => 1時間前 「days ago」や「hours ago」の基準 ドキュメントのList of breakdow
OSSのnpmパッケージにおいて、第三者によるPRでyarn.lockやpackage-lock.jsonなどのロックファイルに変更が加えられている場合、すべての変更を徹底してチェックしなければならない。 なぜなら、パッケージの参照元となるyarnやnpmのレジストリのURLをしれっと改ざんされてしまうリスクがあるため。 例えば以下の画像のようにyarn.lockに定義されたパッケージのresolvedがhttps://registry.yarnpkg.com/...からhttps://malicious.example/...に書き換えられてしまうかもしれない。 lockfile-lint このリスクを軽減するのにlockfile-lintが便利。 例えば👆のコマンドではyarn.lockの中で npmとyarnのレジストリ以外のURLが参照されていないか すべてhttpsのURLにな
コンテンツ投稿系のWebサービスでは「ユーザーのページに好きな独自ドメインを登録できる」という機能をつけたくなることがあります。ユーザーからすると「コンテンツが自分自身の所有物であること」を感じやすいですし、コンテンツのポータビリティが上がりますし、とても夢がありますよね。僕もいつか実装してみたい機能のひとつです。 しかし、この機能を提供するには、以下のようなハードルがあります。 料金 ベンダーロックイン 複雑な実装(とくに認証) (1)の料金についてはデプロイ先によります。例えばVercelであればProプラン以上であれば無制限に独自ドメインを登録できます(Unlimited custom domains for all Pro teams)。 Google Cloudの場合にはCertificate Managerで独自ドメインごとの証明書を管理するのに「ひとつあたり○USD」という感
Googleスプレッドシートを操作するための準備 サービスアカウントの設定 GCPコンソールでGoogle Sheets APIを有効にする GCPコンソールのサービスアカウント設定でサービスアカウントを作成する。ロールは特に指定しなくてOK。ここでサービスアカウントのkeyとなるJSONを取得する 操作したいスプレッドシートを開き、共有設定にサービスアカウントのアドレス(foo@bar.iam.gserviceaccount.com)を追加する。参考 環境変数の設定 以上の操作が完了したらプロジェクトの環境変数として以下の3つを追加する(ハードコードは避ける)。 SHEET_ID='foo' # スプレッドシートのURLに含まれる文字列 GOOGLE_SERVICE_ACCOUNT_EMAIL='foo@bar.iam.gserviceaccount.com' # サービスアカウントのア
2022年現在、CSSでテキストに蛍光ペン風の下線を引く方法をググるとだいたいlinear-gradientを使った記事がヒットします。しかし、いまどきはlinear-gradientを使わなくてもtext-decorationで同じような表現ができるので紹介しておきます。 結論: こういうCSSをあてる /* セレクタ名はてきとう */ .highlight { text-decoration: underline; /* 下線 */ text-decoration-thickness: 0.5em; /* 線の太さ */ text-decoration-color: rgba(255, 228, 0, 0.4); /* 線の色 */ text-underline-offset: -0.2em; /* 線の位置。テキストに重なるようにやや上部にする */ text-decoration-
Appleは製品紹介ページなどによくグラデーションを使っています。カッコいいんですよね。 Apple Card 最近ではAppleっぽくグラーデーションでテキストを表現するWebサイトをよく見かけます。 vercel.com 今回はこのようなカッコいいグラデーションのテキストをCSSで実現する方法を書いていきます。 CSSサンプル HTMLは以下のようなものとします。 CSSでテキストに対してグラデーションをあてるには、backgroundプロパティでグラデーションの背景を指定したうえで、-webkit-background-clip: textと-webkit-text-fill-color: transparent;をあてます。 背景にグラデーションを塗って、その背景を文字の形で切り抜くというイメージです。 例えば、以下のようにします。 .text-gradient { display
ローカルにNode.jsがインストールされていれば、npxコマンドを使ってすぐに画像の最適化ができます。 例えばexample.pngをWebPに変換したいときは以下のコマンドを実行します。 npx @squoosh/cli --webp auto example.png # ✅ Squoosh results: # example.png: 24.85KB # └ example.webp → 8.74KB (35.2%)
メインコンテンツの高さが足りなくてもフッターが中途半端な位置に来ないようにしたい Webアプリケーションのレイアウトで、①ヘッダー②メインコンテンツ③フッターの3つで構成するというパターンはよくあると思うんですが、 👇 こんな感じでフッターの下に中途半端な隙間を作りたくないですよね。 これは困る 👇 メインコンテンツの高さが短くても、フッターがぴったりビューポートの下にくっつくようにしたいですよね。 良いね 👇 ただ、フッターが常に下に固定されているのではなくて、メインコンテンツがビューポートより高くなったときには、フッターは下にずれていってほしいんですよね。 良いね gridを使うと簡単 自分はこれをずっとflexで実現していたのですが、(メインコンテンツの)孫要素の高さを100%にしたいときなんかに色々ややこしくて、gridを使うのがいちばん楽だなーという結論に至りました。gri
2021年3月に一般提供がはじまったCloudflare Pagesに、同月にリリースされたばかりのGatsbyJS v3.0をデプロイしてみます。 1. Gatsbyのサイトを準備する Gatsby CLIを入れておくと開発がしやすいのでグローバルインストールしておきます。 僕はNode.jsのバージョン管理にnodenvを使っているのでグローバルインストールした後はnodenv rehashを実行します。これでgatsbyコマンドが使えるようになりました。 1-1. Gatsby v3に対応したスターターを探す Gatsby v3対応のスターターをチェックしてみます。今回は色んなところで見かけるgatsby-starter-blogを使うことにしました。 1-2. スターターをインストール スターターページにインストールコマンドが書かれているのでそちらを実行します。 $ gatsby
以前、Webページでスクロール位置に応じて要素のスタイルを変えたいようなケースがありました。 上の例では、最初は60pxですが、現在の位置より上にスクロールされると少しずつサイズが小さくなり、ビューポート上部に達したときに20pxになるように実装されています。 これをReactで雑に実装したので備忘録として残しておきます。 1. 要素の位置を取得するカスタムフックを作る まずビューポート内の要素の位置を取得する必要があります。複数の要素に対して同じことをやりたくなったときのために、要素の位置を取得する処理はカスタムフックに切り出しておきます。 import React, { useEffect, useState, useCallback } from "react"; export function useOffsetTop(ref?: React.RefObject<HTMLEleme
次のページ
このページを最初にブックマークしてみませんか?
『catnoseさんの記事一覧』の新着エントリーを見る
j次のブックマーク
k前のブックマーク
lあとで読む
eコメント一覧を開く
oページを開く