[{"data":1,"prerenderedAt":668},["ShallowReactive",2],{"article-2025-cloudflare-workers-cache-layer":3,"articles-[]":523},{"id":4,"title":5,"alt":5,"body":6,"category":508,"cover":509,"createDate":510,"description":511,"extension":512,"homepage":118,"meta":513,"navigation":118,"path":517,"recommend":118,"seo":518,"showCover":118,"slug":519,"stem":520,"tag":521,"updated":510,"__hash__":522},"articles\u002Farticles\u002F2025\u002Fcloudflare-workers-cache-layer.md","Cloudflare Workers でキャッシュ層を作る",{"type":7,"value":8,"toc":500},"minimark",[9,13,17,27,459,462,465,470,477,481,487,490,493,496],[10,11,12],"p",{},"画像サーバーの前段に Cloudflare Workers でキャッシュ層を作ったら転送量が大幅に減ったので記録です。",[14,15,16],"h2",{"id":16},"やったこと",[18,19,20,24],"ol",{},[21,22,23],"li",{},"以下のコードで Workers を作りカスタムドメインを当てる",[21,25,26],{},"ソースコードの URL を Workers に割り当てたドメインに変更する",[28,29,34],"pre",{"className":30,"code":31,"language":32,"meta":33,"style":33},"language-ts shiki shiki-themes github-light github-dark","export default {\n  async fetch(request, env, ctx) {\n    \u002F\u002F 1) リクエストURLを解析\n    const url = new URL(request.url)\n\n    \u002F\u002F 書き換え元・書き換え先のドメイン\n    const domain = 'workers.example.com' \u002F\u002F Workers に割り当てるドメイン\n    const mirror = 'origin.example.com' \u002F\u002F 本来の画像サーバーのドメイン\n\n    \u002F\u002F 2) ドメインが一致する場合は書き換え\n    if (url.hostname === domain) {\n      url.hostname = mirror\n    }\n\n    \u002F\u002F 3) キャッシュキーとして使うために、新しい Request オブジェクトを作成\n    const cacheKey = new Request(url.toString(), {\n      method: request.method,\n      headers: request.headers,\n      body: request.body,\n      redirect: request.redirect,\n      \u002F\u002F POST \u002F PUT などでボディがある場合はストリームを読み込み済みにする必要があるため注意。\n      \u002F\u002F ここではGETリクエスト想定で簡単に記述しています。\n    })\n\n    \u002F\u002F 4) デフォルトキャッシュから取得を試みる\n    const cache = caches.default\n    let response = await cache.match(cacheKey)\n\n    \u002F\u002F 5) キャッシュに無ければ fetch\n    if (!response) {\n      response = await fetch(cacheKey)\n\n      \u002F\u002F 6) レスポンスがOKならキャッシュに put する\n      if (response.ok) {\n        \u002F\u002F 非同期タスクとしてキャッシュ処理をバックグラウンド実行\n        ctx.waitUntil(cache.put(cacheKey, response.clone()))\n      }\n    }\n\n    \u002F\u002F 7) レスポンスを返却\n    return response\n  },\n}\n","ts","",[35,36,37,53,84,91,113,120,126,143,159,164,170,185,197,203,208,214,238,244,250,256,262,268,274,280,285,291,304,327,332,338,352,366,371,377,386,392,416,422,427,432,438,447,453],"code",{"__ignoreMap":33},[38,39,42,46,49],"span",{"class":40,"line":41},"line",1,[38,43,45],{"class":44},"szBVR","export",[38,47,48],{"class":44}," default",[38,50,52],{"class":51},"sVt8B"," {\n",[38,54,56,59,63,66,70,73,76,78,81],{"class":40,"line":55},2,[38,57,58],{"class":44},"  async",[38,60,62],{"class":61},"sScJk"," fetch",[38,64,65],{"class":51},"(",[38,67,69],{"class":68},"s4XuR","request",[38,71,72],{"class":51},", ",[38,74,75],{"class":68},"env",[38,77,72],{"class":51},[38,79,80],{"class":68},"ctx",[38,82,83],{"class":51},") {\n",[38,85,87],{"class":40,"line":86},3,[38,88,90],{"class":89},"sJ8bj","    \u002F\u002F 1) リクエストURLを解析\n",[38,92,94,97,101,104,107,110],{"class":40,"line":93},4,[38,95,96],{"class":44},"    const",[38,98,100],{"class":99},"sj4cs"," url",[38,102,103],{"class":44}," =",[38,105,106],{"class":44}," new",[38,108,109],{"class":61}," URL",[38,111,112],{"class":51},"(request.url)\n",[38,114,116],{"class":40,"line":115},5,[38,117,119],{"emptyLinePlaceholder":118},true,"\n",[38,121,123],{"class":40,"line":122},6,[38,124,125],{"class":89},"    \u002F\u002F 書き換え元・書き換え先のドメイン\n",[38,127,129,131,134,136,140],{"class":40,"line":128},7,[38,130,96],{"class":44},[38,132,133],{"class":99}," domain",[38,135,103],{"class":44},[38,137,139],{"class":138},"sZZnC"," 'workers.example.com'",[38,141,142],{"class":89}," \u002F\u002F Workers に割り当てるドメイン\n",[38,144,146,148,151,153,156],{"class":40,"line":145},8,[38,147,96],{"class":44},[38,149,150],{"class":99}," mirror",[38,152,103],{"class":44},[38,154,155],{"class":138}," 'origin.example.com'",[38,157,158],{"class":89}," \u002F\u002F 本来の画像サーバーのドメイン\n",[38,160,162],{"class":40,"line":161},9,[38,163,119],{"emptyLinePlaceholder":118},[38,165,167],{"class":40,"line":166},10,[38,168,169],{"class":89},"    \u002F\u002F 2) ドメインが一致する場合は書き換え\n",[38,171,173,176,179,182],{"class":40,"line":172},11,[38,174,175],{"class":44},"    if",[38,177,178],{"class":51}," (url.hostname ",[38,180,181],{"class":44},"===",[38,183,184],{"class":51}," domain) {\n",[38,186,188,191,194],{"class":40,"line":187},12,[38,189,190],{"class":51},"      url.hostname ",[38,192,193],{"class":44},"=",[38,195,196],{"class":51}," mirror\n",[38,198,200],{"class":40,"line":199},13,[38,201,202],{"class":51},"    }\n",[38,204,206],{"class":40,"line":205},14,[38,207,119],{"emptyLinePlaceholder":118},[38,209,211],{"class":40,"line":210},15,[38,212,213],{"class":89},"    \u002F\u002F 3) キャッシュキーとして使うために、新しい Request オブジェクトを作成\n",[38,215,217,219,222,224,226,229,232,235],{"class":40,"line":216},16,[38,218,96],{"class":44},[38,220,221],{"class":99}," cacheKey",[38,223,103],{"class":44},[38,225,106],{"class":44},[38,227,228],{"class":61}," Request",[38,230,231],{"class":51},"(url.",[38,233,234],{"class":61},"toString",[38,236,237],{"class":51},"(), {\n",[38,239,241],{"class":40,"line":240},17,[38,242,243],{"class":51},"      method: request.method,\n",[38,245,247],{"class":40,"line":246},18,[38,248,249],{"class":51},"      headers: request.headers,\n",[38,251,253],{"class":40,"line":252},19,[38,254,255],{"class":51},"      body: request.body,\n",[38,257,259],{"class":40,"line":258},20,[38,260,261],{"class":51},"      redirect: request.redirect,\n",[38,263,265],{"class":40,"line":264},21,[38,266,267],{"class":89},"      \u002F\u002F POST \u002F PUT などでボディがある場合はストリームを読み込み済みにする必要があるため注意。\n",[38,269,271],{"class":40,"line":270},22,[38,272,273],{"class":89},"      \u002F\u002F ここではGETリクエスト想定で簡単に記述しています。\n",[38,275,277],{"class":40,"line":276},23,[38,278,279],{"class":51},"    })\n",[38,281,283],{"class":40,"line":282},24,[38,284,119],{"emptyLinePlaceholder":118},[38,286,288],{"class":40,"line":287},25,[38,289,290],{"class":89},"    \u002F\u002F 4) デフォルトキャッシュから取得を試みる\n",[38,292,294,296,299,301],{"class":40,"line":293},26,[38,295,96],{"class":44},[38,297,298],{"class":99}," cache",[38,300,103],{"class":44},[38,302,303],{"class":51}," caches.default\n",[38,305,307,310,313,315,318,321,324],{"class":40,"line":306},27,[38,308,309],{"class":44},"    let",[38,311,312],{"class":51}," response ",[38,314,193],{"class":44},[38,316,317],{"class":44}," await",[38,319,320],{"class":51}," cache.",[38,322,323],{"class":61},"match",[38,325,326],{"class":51},"(cacheKey)\n",[38,328,330],{"class":40,"line":329},28,[38,331,119],{"emptyLinePlaceholder":118},[38,333,335],{"class":40,"line":334},29,[38,336,337],{"class":89},"    \u002F\u002F 5) キャッシュに無ければ fetch\n",[38,339,341,343,346,349],{"class":40,"line":340},30,[38,342,175],{"class":44},[38,344,345],{"class":51}," (",[38,347,348],{"class":44},"!",[38,350,351],{"class":51},"response) {\n",[38,353,355,358,360,362,364],{"class":40,"line":354},31,[38,356,357],{"class":51},"      response ",[38,359,193],{"class":44},[38,361,317],{"class":44},[38,363,62],{"class":61},[38,365,326],{"class":51},[38,367,369],{"class":40,"line":368},32,[38,370,119],{"emptyLinePlaceholder":118},[38,372,374],{"class":40,"line":373},33,[38,375,376],{"class":89},"      \u002F\u002F 6) レスポンスがOKならキャッシュに put する\n",[38,378,380,383],{"class":40,"line":379},34,[38,381,382],{"class":44},"      if",[38,384,385],{"class":51}," (response.ok) {\n",[38,387,389],{"class":40,"line":388},35,[38,390,391],{"class":89},"        \u002F\u002F 非同期タスクとしてキャッシュ処理をバックグラウンド実行\n",[38,393,395,398,401,404,407,410,413],{"class":40,"line":394},36,[38,396,397],{"class":51},"        ctx.",[38,399,400],{"class":61},"waitUntil",[38,402,403],{"class":51},"(cache.",[38,405,406],{"class":61},"put",[38,408,409],{"class":51},"(cacheKey, response.",[38,411,412],{"class":61},"clone",[38,414,415],{"class":51},"()))\n",[38,417,419],{"class":40,"line":418},37,[38,420,421],{"class":51},"      }\n",[38,423,425],{"class":40,"line":424},38,[38,426,202],{"class":51},[38,428,430],{"class":40,"line":429},39,[38,431,119],{"emptyLinePlaceholder":118},[38,433,435],{"class":40,"line":434},40,[38,436,437],{"class":89},"    \u002F\u002F 7) レスポンスを返却\n",[38,439,441,444],{"class":40,"line":440},41,[38,442,443],{"class":44},"    return",[38,445,446],{"class":51}," response\n",[38,448,450],{"class":40,"line":449},42,[38,451,452],{"class":51},"  },\n",[38,454,456],{"class":40,"line":455},43,[38,457,458],{"class":51},"}\n",[14,460,461],{"id":461},"結果",[10,463,464],{},"上がり調子だった転送量を大幅に減らすことができました！",[466,467,469],"h3",{"id":468},"impressions","Impressions",[10,471,472],{},[473,474],"img",{"alt":475,"src":476},"cloudflare-workers-cache-layer_010","\u002Fimg\u002Fcloudflare-workers-cache-layer\u002Fcloudflare-workers-cache-layer_010.png",[466,478,480],{"id":479},"bandwidth","Bandwidth",[10,482,483],{},[473,484],{"alt":485,"src":486},"cloudflare-workers-cache-layer_020","\u002Fimg\u002Fcloudflare-workers-cache-layer\u002Fcloudflare-workers-cache-layer_020.png",[14,488,489],{"id":489},"さいごに",[10,491,492],{},"それにしても Cloudflare Workers はすごいですね。月5ドルで1,000万リクエスト捌けるので、他にも色々遊んでみたいです。",[10,494,495],{},"P.S. 確認したら160万リクエストだったのでまだまだ遊べそうです。",[497,498,499],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":33,"searchDepth":55,"depth":55,"links":501},[502,503,507],{"id":16,"depth":55,"text":16},{"id":461,"depth":55,"text":461,"children":504},[505,506],{"id":468,"depth":86,"text":469},{"id":479,"depth":86,"text":480},{"id":489,"depth":55,"text":489},"web","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_text:MPLUS1p-Black.ttf_88_bold:Cloudflare Workers で%0Aキャッシュ層を%0A作る,co_rgb:fff,w_720,c_fit\u002Fv1712091289\u002Fcover_2025_rpwog8.png","2025\u002F02\u002F23","画像サーバーの前段に Cloudflare Workers でキャッシュ層を作ったら転送量が大幅に減ったので記録です。やりかたです。1. 以下のコードで Workers を作りカスタムドメインを当てる。2. ソースコードの URL を Workers に割り当てたドメインに変更する。","md",{"emoji":514,"type":515,"topics":516,"published":118},"🧪","tech",[],"\u002Farticles\u002F2025\u002Fcloudflare-workers-cache-layer",{"title":5,"description":511},"cloudflare-workers-cache-layer","articles\u002F2025\u002Fcloudflare-workers-cache-layer",[],"3OJXeDKKZJhVkTS6amJNbN6f5k6NSNxmZ2S0r-9K5to",{"items":524,"total":246},[525,535,544,550,558,566,573,582,589,599,609,616,623,633,640,644,654,661],{"_path":526,"title":527,"description":528,"cover":529,"alt":527,"category":530,"categoryBasePath":531,"tags":532,"createDate":533,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2026\u002Fmy-app-stack\u002F","2年半のフルプラットフォーム開発について全部書く","2年半前、人生で一番追い詰められたプロジェクトが終わりました。少しだけ時間に余裕ができたので、個人で運用していたWebアプリをリプレイスすることにしました。そしてあれこれ試行錯誤していたら、2年半経っていました。やりたかった事を一通りやり切ることができたので、こだわり部分を紹介します。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_text:MPLUS1p-Black.ttf_72_bold:フルプラットフォーム開発について全部書く,co_rgb:fff,w_720,c_fit\u002Fv1712091289\u002Fogp_my-web-app-stack_ztafxo.webp","other","\u002Farticles\u002Fcategory\u002Fother\u002F",[],"2026\u002F04\u002F08","ja",{"_path":536,"title":537,"description":538,"cover":539,"alt":539,"category":33,"categoryBasePath":540,"tags":541,"createDate":542,"homepage":543,"recommend":543,"showCover":543,"lang":534},"\u002Farticles\u002F2026\u002Fthe-goal\u002F","『ザ・ゴール ― 企業の究極の目的とは何か』を読んだ","「ザ・ゴール ― 企業の究極の目的とは何か」を読みました。",null,"\u002Farticles\u002Fcategory\u002F",[],"2026\u002F02\u002F10",false,{"_path":545,"title":546,"description":547,"cover":539,"alt":539,"category":33,"categoryBasePath":540,"tags":548,"createDate":549,"homepage":543,"recommend":543,"showCover":543,"lang":534},"\u002Farticles\u002F2026\u002Ftidy-first\u002F","『Tidy First? ―個人で実践する経験主義的ソフトウェア設計』を読んだ","「Tidy First? ―個人で実践する経験主義的ソフトウェア設計」を読んだ。",[],"2026\u002F01\u002F31",{"_path":551,"title":552,"description":33,"cover":553,"alt":552,"category":554,"categoryBasePath":555,"tags":556,"createDate":557,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fcapacitor\u002F","Vueでスマホアプリ開発【Capacitor】","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_title_cover_001_lu3vq4\u002Fl_title_cover_001_lu3vq4\u002Fl_text:MPLUS1p-Black.ttf_88_bold:Vue.jsで%0Aスマホアプリ%0A開発,co_rgb:374151,w_720,c_fit\u002Fv1712091289\u002Fthumbnail__003_prznvl.webp","vuejs","\u002Farticles\u002Fcategory\u002Fvuejs\u002F",[],"2025\u002F12\u002F27",{"_path":559,"title":560,"description":561,"cover":562,"alt":560,"category":530,"categoryBasePath":531,"tags":563,"createDate":564,"updated":565,"homepage":543,"recommend":543,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fthe-land-of-playful-fellows\u002F","紅白もちのひみつ『めっきらもっきら どおん どん』","奥さんに言われて「はっ」としました。もんもんびゃっこ達は赤いおもちを食べていて、かんたは白いおもち。これはなんらかの意味がこめられてるのでは？と思い考えてみました。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fv1712091289\u002Fthe-land-of-playful-fellows_vgkvsf",[],"2025\u002F12\u002F20","2025\u002F12\u002F22",{"_path":567,"title":568,"description":569,"cover":570,"alt":568,"category":530,"categoryBasePath":531,"tags":571,"createDate":572,"updated":572,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fpixel-astrophotography\u002F","星空写真をAndroid Pixelでキレイに撮る","キャンプ場での夜空はやっぱりキレイでした。星がよく見れます。肉眼で見れるこのキレイな星空を写真に残せたら嬉しいなーと思いながら、タイマーが終わるのを待ちます。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_title_cover_001_lu3vq4\u002Fl_title_cover_001_lu3vq4\u002Fl_text:MPLUS1p-Black.ttf_88_bold:星空写真を%0APixelで%0Aキレイに撮る,co_rgb:374151,w_720,c_fit\u002Fv1712091289\u002Fpixel-astrophotography",[],"2025\u002F09\u002F29",{"_path":574,"title":575,"description":576,"cover":577,"alt":575,"category":578,"categoryBasePath":579,"tags":580,"createDate":581,"updated":581,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fhosting-storybook\u002F","Storybookのダッシュボードを公開する","以前から Vue の UI ライブラリを Storybook を使って作っていました。その UI ライブラリの Storybook を静的サイトにビルドしてホスティングしてみました。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_text:MPLUS1p-Black.ttf_88_bold:Storybookの%0Aダッシュボードを%0A公開する,co_rgb:fff,w_720,c_fit\u002Fv1712091289\u002Fcover_2025_rpwog8.png","storybook","\u002Farticles\u002Fcategory\u002Fstorybook\u002F",[],"2025\u002F05\u002F28",{"_path":583,"title":584,"description":585,"cover":586,"alt":584,"category":530,"categoryBasePath":531,"tags":587,"createDate":588,"updated":588,"homepage":543,"recommend":543,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fmemo\u002F","メモは脳の排水","紙、デジタルどちらでもなんでもメモに書き出します。書き出すことで考えが整理され、ネタ帳になってくれるので重宝しています。この「脳の排水」という言葉にグッときました。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_text:MPLUS1p-Black.ttf_88_bold:メモは脳の排水,co_rgb:fff,w_720,c_fit\u002Fv1712091289\u002Fcover_2025_rpwog8.png",[],"2025\u002F05\u002F27",{"_path":590,"title":591,"description":592,"cover":593,"alt":591,"category":594,"categoryBasePath":595,"tags":596,"createDate":598,"updated":598,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fa2a-guide\u002F","A2A 試してみた","A2AとはAIエージェントとAIエージェントが連携するための規格です。Googleが2025年4月に発表しました。Googleのサンプルコードを動かしてみます。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_text:MPLUS1p-Black.ttf_88_bold:A2A 試してみた,co_rgb:fff,w_720,c_fit\u002Fv1712091289\u002Fcover_2025_rpwog8.png","ai","\u002Farticles\u002Fcategory\u002Fai\u002F",[597],"AI","2025\u002F05\u002F01",{"_path":600,"title":601,"description":602,"cover":603,"alt":601,"category":604,"categoryBasePath":605,"tags":606,"createDate":607,"updated":608,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fdify-self-hosted-guide\u002F","Dify をセルフホストで立ち上げる","Dify をセルフホストで立ち上げる機会があったので、手順を紹介します。Dify（ディファイ）は、AIアプリを簡単に開発できるオープンソースのプラットフォームです。クラウド版とセルフホスト版があります。今回は Dify をセルフホストで立ち上げてみます。公式と同じ手順で実行する。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_text:MPLUS1p-Black.ttf_88_bold:Dify を%0Aセルフホストで%0A立ち上げる,co_rgb:fff,w_720,c_fit\u002Fv1712091289\u002Fcover_2025_rpwog8.png","dify","\u002Farticles\u002Fcategory\u002Fdify\u002F",[],"2025\u002F04\u002F29","2025-04-29",{"_path":610,"title":611,"description":612,"cover":613,"alt":611,"category":530,"categoryBasePath":531,"tags":614,"createDate":615,"updated":615,"homepage":543,"recommend":543,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fphysical-bookstore\u002F","リアル書店の選書体験","今回で改めて書店の良さに気付けたのが良かったです。ただ、ネット通販や電子書籍には手軽に買えるなど別の良さがあると思ってます。なのでうまく使い分けていきたいです。","https:\u002F\u002Fasset.hirameki.dev\u002Fimg%2Fblog%2Fjournal%2F2025%2F20250425%2F20250425_010.webp?alt=media",[],"2025\u002F04\u002F25",{"_path":617,"title":618,"description":619,"cover":620,"alt":618,"category":594,"categoryBasePath":595,"tags":621,"createDate":622,"updated":622,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fcline-guide\u002F","Cline やってみた","Clineは自分自身でコマンドを実行できるようになっています。暴走しても被害がコンテナの中だけで済むようにDevContainersを使って今回試してみました。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_text:MPLUS1p-Black.ttf_88_bold:Cline%20やってみた,co_rgb:fff,w_720,c_fit\u002Fv1712091289\u002Fcover_2025_rpwog8.png",[597],"2025\u002F04\u002F16",{"_path":624,"title":625,"description":626,"cover":627,"alt":625,"category":628,"categoryBasePath":629,"tags":630,"createDate":632,"updated":632,"homepage":118,"recommend":543,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fmy-oss-projects\u002F","今まで作った OSS プロジェクト","今まで、いくつか OSS プロジェクトを作ってきたので紹介します。番外編まで含めると全部で5つあります。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_text:MPLUS1p-Black.ttf_88_bold:今まで作った%0AOSS%20プロジェクト,co_rgb:fff,w_720,c_fit\u002Fv1712091289\u002Fcover_2025_rpwog8.png","oss","\u002Farticles\u002Fcategory\u002Foss\u002F",[631],"OSS","2025\u002F04\u002F02",{"_path":634,"title":635,"description":636,"cover":637,"alt":635,"category":530,"categoryBasePath":531,"tags":638,"createDate":639,"updated":639,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fbuilt-custom-keyboard\u002F","キーボードを自作した","ずっと興味のあった自作キーボードに挑戦した記録で、遊舎工房でキットやキーキャップを選び、秋葉原で工具を買い、久しぶりのはんだ付けに苦戦しながら完成させました。","https:\u002F\u002Fasset.hirameki.dev\u002Fimg%2Fblog%2Fjournal%2F2025%2F20250309_built-custom-keyboard%2F20250309_built-custom-keyboard_010.webp?alt=media",[],"2025\u002F03\u002F09",{"_path":641,"title":5,"description":511,"cover":509,"alt":5,"category":508,"categoryBasePath":642,"tags":643,"createDate":510,"updated":510,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Fcloudflare-workers-cache-layer\u002F","\u002Farticles\u002Fcategory\u002Fweb\u002F",[],{"_path":645,"title":646,"description":647,"cover":648,"alt":646,"category":649,"categoryBasePath":650,"tags":651,"createDate":652,"updated":653,"homepage":118,"recommend":543,"showCover":118,"lang":534},"\u002Farticles\u002F2022\u002Flearn-programming\u002F","プログラミング勉強のコツを調べてみた","エラーに対する態度は3パターンあります。上達が早いのはもちろん3番目のパターンです。事前に知っておくことで、エラーに直面した時に少し落ち着いて対処できそうです。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_title_cover_001_lu3vq4\u002Fl_title_cover_001_lu3vq4\u002Fl_text:MPLUS1p-Black.ttf_88_bold:プログラミング%0A勉強のコツを%0A調べてみた,co_rgb:374151,w_720,c_fit\u002Fv1642574453\u002Falfons-morales-YLSwjSy7stw-unsplash_2_1_xnt6z7.png","programming","\u002Farticles\u002Fcategory\u002Fprogramming\u002F",[],"2022\u002F05\u002F23","2025\u002F02\u002F12",{"_path":655,"title":656,"description":657,"cover":658,"alt":656,"category":530,"categoryBasePath":531,"tags":659,"createDate":660,"updated":660,"homepage":118,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2025\u002Flearn-9-years\u002F","９年間、毎日プログラミングの勉強をしてる話","仕事から帰ってきて、ご飯食べたりお風呂に入って、一息ついたらパソコンにむかって12時まで作業する。初めはビジネス書とか経済の本を読んだりしてた。それから9年経った。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_title_cover_001_lu3vq4\u002Fl_title_cover_001_lu3vq4\u002Fl_text:MPLUS1p-Black.ttf_88_bold:９年間、毎日%0Aプログラミングの勉強をしてる話,co_rgb:374151,w_720,c_fit\u002Fv1712091289\u002Fthumbnail__001_tdrr4g.webp",[],"2025\u002F02\u002F10",{"_path":662,"title":663,"description":664,"cover":665,"alt":663,"category":530,"categoryBasePath":531,"tags":666,"createDate":667,"updated":667,"homepage":543,"recommend":118,"showCover":118,"lang":534},"\u002Farticles\u002F2021\u002Fstudy-5-years\u002F","5年間ほぼ毎日プログラミングの勉強をするためにやったこと","人生の節目で一時的に勉強してない時期もありました。ですが、それ以外のほとんどの期間で毎日プログラミングを勉強しています。楽しいので、あまり勉強と思っていませんが。","https:\u002F\u002Fimage.hirameki.dev\u002Ftakasqr\u002Fimage\u002Fupload\u002Fl_text:MPLUS1p-Black.ttf_88_bold:5年間ほぼ毎日%0Aプログラミングの%0A勉強をする為に%0Aやったこと,co_rgb:fff,w_720,c_fit\u002Fv1642574453\u002Faaron-burden-QJDzYT_K8Xg-unsplash_1_xaxykh.png",[],"2021\u002F08\u002F01",1776498755838]