Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Fresh(Deno)で 画像投稿サイトを作ってみよう! with Cloudflare x ...
Search
虎の穴ラボ株式会社
December 16, 2022
Technology
0
800
Fresh(Deno)で 画像投稿サイトを作ってみよう! with Cloudflare x Tora Viewer
Deno のWebフレームワーク Freshを使用して、
画像投稿サイトの作成
キーワード
- Deno
- Fresh
- Cloudflare
- Tora Viewer
- esm.sh
虎の穴ラボ株式会社
December 16, 2022
Tweet
Share
More Decks by 虎の穴ラボ株式会社
See All by 虎の穴ラボ株式会社
Tailwind CSSとAtomic Designで実現する効率的な Web 開発の事例
toranoana
1
570
Denoについて、同人誌記事を出しました+update
toranoana
0
200
【虎の穴ラボ Tech Talk #2】プロンプトエンジニアリング
toranoana
0
130
20241121_[TechTalk#2]虎の穴ラボでのLLMについて取り組み紹介
toranoana
0
120
社内チャットへRAG導入した話(Tech Talk #2)
toranoana
0
200
Deno Deploy で Web Cache API を 使えるようになったので試した知見
toranoana
1
630
【虎の穴ラボ Tech Talk】虎の穴ラボTech Talk説明資料
toranoana
0
440
虎の穴ラボ Tech Talk_CDKでFargate環境構築
toranoana
1
490
虎の穴ラボスキルアップ支援制度の利用例
toranoana
0
9.4k
Other Decks in Technology
See All in Technology
Context Engineeringの取り組み
nutslove
0
380
外部キー制約の知っておいて欲しいこと - RDBMSを正しく使うために必要なこと / FOREIGN KEY Night
soudai
PRO
12
5.6k
Agile Leadership Summit Keynote 2026
m_seki
1
680
顧客の言葉を、そのまま信じない勇気
yamatai1212
1
370
AIエージェントを開発しよう!-AgentCore活用の勘所-
yukiogawa
0
190
AIが実装する時代、人間は仕様と検証を設計する
gotalab555
1
630
Bill One急成長の舞台裏 開発組織が直面した失敗と教訓
sansantech
PRO
2
410
AWS Network Firewall Proxyを触ってみた
nagisa53
1
250
顧客との商談議事録をみんなで読んで顧客解像度を上げよう
shibayu36
0
340
(技術的には)社内システムもOKなブラウザエージェントを作ってみた!
har1101
0
340
マネージャー視点で考えるプロダクトエンジニアの評価 / Evaluating Product Engineers from a Manager's Perspective
hiro_torii
0
190
ECS障害を例に学ぶ、インシデント対応に備えたAIエージェントの育て方 / How to develop AI agents for incident response with ECS outage
iselegant
4
450
Featured
See All Featured
Leading Effective Engineering Teams in the AI Era
addyosmani
9
1.6k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
1.9k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
9.6k
Ethics towards AI in product and experience design
skipperchong
2
200
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1k
Building Adaptive Systems
keathley
44
2.9k
Skip the Path - Find Your Career Trail
mkilby
0
60
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
270
Believing is Seeing
oripsolob
1
59
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
750
Reality Check: Gamification 10 Years Later
codingconduct
0
2k
Color Theory Basics | Prateek | Gurzu
gurzu
0
200
Transcript
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. 2022/12/14 toranoana.deno
#10 虎の穴ラボ 奥谷 一陽 Fresh(Deno)で 画像投稿サイトを作ってみよう! with Cloudflare x Tora Viewer
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. 自己紹介 奥谷
一陽 所属:虎の穴ラボ株式会社 担当:Fantiaなど新規事業系の開発 興味:TypeScript、Deno おすすめコンテンツ: 『暴太郎戦隊ドンブラザーズ』 『STAR WARS 小説 』 Twitter:@okutann88
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. Fresh 使ってますか?
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. さっと作って、 Deno
Deployに上げるのもカンタン
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. ですが、あえてFreshを使って ちょっと込み入ったことをしてみました
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. Freshで 画像投稿をやろう
- Freshをベースに開発する - 機能 - 画像のアップロード - 画像の一覧表示 - 画像の詳細表示 これらを実装する方針
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. イメージが湧きにくいと思うので、先にできたものを -
Freshをベースに開発する - 機能 - 画像のアップロード - 画像の一覧表示 - 画像の詳細表示 これらを実装する方針
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. イメージが湧きにくいと思うので、先にできたものを -
Freshをベースに開発する - 機能 - 画像のアップロード - 画像の一覧表示 - 画像の詳細表示 これらを実装する方針
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. 利用技術/サービス -
Deno - Fresh - Cloudflare - Tora Viewer
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. 利用技術サービス -
Deno - Fresh - Cloudflare - Tora Viewer ?
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. Tora Viewer
https://www.npmjs.com/package/@toralab/tora-viewer
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. Tora Viewer
- 漫画、写真集など画像一覧を閲覧できるビューアー - 虎の穴ラボ発のOSSです - Freshでも使えます。 // import_map.json { "imports": { "$fresh/": "https://deno.land/x/
[email protected]
/", "preact": "https://esm.sh/
[email protected]
", "preact/": "https://esm.sh/
[email protected]
/", "preact-render-to-string": "https://esm.sh/*
[email protected]
", "@preact/signals": "https://esm.sh/*@preact/
[email protected]
", "@preact/signals-core": "https://esm.sh/*@preact/
[email protected]
", "twind": "https://esm.sh/
[email protected]
", "twind/": "https://esm.sh/
[email protected]
/", "dotenv/": "https://deno.land/
[email protected]
/dotenv/", "huid/": "https://deno.land/x/
[email protected]
/", "tora-viewer": "https://esm.sh/v99/@toralab/
[email protected]
/es2022/tora-viewer.js", "body-scroll-lock": "https://esm.sh/body-scroll-lock", "simple-dropzone": "https://esm.sh/simple-dropzone" }
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. 全体構成 deno
cli APPサーバー 画像 アップロード ・ダウンロード ページアクセス 画像ID登録 APIサーバー DB
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. その他追加導入しているモジュール -
huid:文字列のハッシュをつくるのに使用 - body-scroll-lock:ビューアーを開いたときのスクロールロック - simple-dropzone:画像ドラッグ&ドロップ操作用 body-scroll-lock と simple-dropzone は、esm.sh経由での導入
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. ソースコード //
routes/index.tsx import Uploader from "../islands/Uploader.tsx"; import Images from "../islands/Images.tsx"; export default function Home() { return ( <div class="p-4 mx-auto max-w-screen-md"> <Uploader /> <Images /> </div> ); }
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. ソースコード //
app/islands/Uploader.tsx (前半) import { JSX } from "preact"; import { useEffect, useRef } from "preact/hooks"; import { mode } from "../util/signal.ts"; import { SimpleDropzone } from "simple-dropzone"; import UploaderIcon from "../components/UpLoadIcon.tsx"; export default function Uploader(_props: JSX.HTMLAttributes) { const inputRef = useRef<HTMLInputElement>(null); const dropzoneRef = useRef<HTMLDivElement>(null); const upload = async (file: File) => { if (!inputRef.current) return; const result = await fetch("/api/get_temp_post_url"); const resultJson = await result.json(); const formData = new FormData(); formData.append("file", file); const uploadResult = await fetch(resultJson.url, { method: "POST", body: formData, }); const uploadedResultJson = await uploadResult.json(); await fetch("/api/image_updated", { method: "POST", body: JSON.stringify(uploadedResultJson), }); inputRef.current.value = ""; mode.value = 1; };
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. ソースコード //
app/islands/Uploader.tsx (後半) useEffect(() => { const dropCtrl = new SimpleDropzone(dropzoneRef.current, inputRef.current); dropCtrl.on("drop", ({ files }: { files: Map<number, File> }) => { for (const [_key, value] of files) { upload(value); } }); }, []); return ( <div class="container"> <div id="dropzone" ref={dropzoneRef}> <label class="flex justify-center w-full h-32 px-4 transition bg-white border-4 border-gray-300 border-dashed rounded-lg hover:border-gray-600"> <div class="flex flex-col items-center m-2"> <div> <UploaderIcon /> </div> <div> <span class="font-medium text-gray-600">Drop or Select</span> </div> </div> <input type="file" ref={inputRef} class="hidden" multiple /> </label> </div> </div> ); }
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. ソースコード //
app/islands/Images.tsx (tora-viewer部分抜粋) import toraViewer from "tora-viewer"; export default function Images(_props: JSX.HTMLAttributes) { const openViewer = (index: number) => { const viewer = toraViewer( originalImages.map((image: Image, index: number) => { return { url: image.url, thumbnailUrl: miniImages[index].url }; }), { pageStyle: "normal"}, ); viewer.goTo(index); const originDispose = viewer.dispose; const boundDispose = originDispose.bind(viewer); const newDispose = () => { clearAllBodyScrollLocks(); boundDispose(); }; viewer.dispose = newDispose; }; return ( <div class="flex justify-center container"> <div class="flex flex-wrap w-full justify-center container"> {!miniImages ? "" : miniImages.map((image: Image, index: number) => ( <div class="my-2 px-1 w-32 w-full" key={`key-${image.key}`} style="background-image: url(/logo.svg); background-repeat: no-repeat; background-position: center center;" > <img src={image.url} onClick={() => openViewer(index)} /> </div> ))} </div> </div> ); }
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. esm.sh 小ネタ
開発中のこと - esm.sh経由で Tora Viewer を読み込むと、どうも毎回ビルドをしているような動 きをしていて動きが遅かった - ビルド結果を直接インポートするようにすると改善 同じように、esm.shから読み込みが遅いものは同じ対応ができるかも "https://esm.sh/v99/@toralab/
[email protected]
/es2022/tora-viewer.js" "https://esm.sh/@toralab/tora-viewer"
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. まとめ -
Fresh x Cloudflare x Tora Viewer で画像投稿サイトを作ってみました。 - ユーザー認証、ローディングアニメーションなど拡張すれば、 画像投稿サイトとして十分使えそうです。 - 今回の実装は islands2つだけを使ったサイトでした。 islandsを使いこなせるといろんなことができます。
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. お知らせ 今回取り扱った
画像投稿サイトの実装の詳細な解説が入ったブログが明日公開 省略した箇所の解説も入ってますので、ご期待ください!!
Copyright (C) 2021 Toranoana Inc. All Rights Reserved. ありがとうございました