Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Fresh(Deno)で 画像投稿サイトを作ってみよう! with Cloudflare x Tora Viewer

Fresh(Deno)で 画像投稿サイトを作ってみよう! with Cloudflare x Tora Viewer

Deno のWebフレームワーク Freshを使用して、
画像投稿サイトの作成

キーワード
- Deno
- Fresh
- Cloudflare
- Tora Viewer
- esm.sh

虎の穴ラボ株式会社

December 16, 2022
Tweet

More Decks by 虎の穴ラボ株式会社

Other Decks in Technology

Transcript

  1. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. 2022/12/14
 toranoana.deno

    #10 
 
 虎の穴ラボ
 奥谷 一陽
 Fresh(Deno)で 画像投稿サイトを作ってみよう! with Cloudflare x Tora Viewer

  2. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. 自己紹介
 奥谷

    一陽
 所属:虎の穴ラボ株式会社
 担当:Fantiaなど新規事業系の開発
 興味:TypeScript、Deno
 おすすめコンテンツ:
   『暴太郎戦隊ドンブラザーズ』
   『STAR WARS 小説 』
 
 Twitter:@okutann88

  3. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. Freshで 画像投稿をやろう


    - Freshをベースに開発する
 - 機能
 - 画像のアップロード
 - 画像の一覧表示
 - 画像の詳細表示
 これらを実装する方針
 
 

  4. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. イメージが湧きにくいと思うので、先にできたものを
 -

    Freshをベースに開発する
 - 機能
 - 画像のアップロード
 - 画像の一覧表示
 - 画像の詳細表示
 これらを実装する方針
 
 

  5. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. イメージが湧きにくいと思うので、先にできたものを
 -

    Freshをベースに開発する
 - 機能
 - 画像のアップロード
 - 画像の一覧表示
 - 画像の詳細表示
 これらを実装する方針
 
 

  6. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. 利用技術サービス
 -

    Deno
 - Fresh 
 - Cloudflare
 - Tora Viewer ?

  7. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. Tora Viewer


    https://www.npmjs.com/package/@toralab/tora-viewer
  8. 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" }
  9. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. 全体構成
 deno

    cli APPサーバー 画像 アップロード ・ダウンロード ページアクセス 画像ID登録 APIサーバー DB
  10. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. その他追加導入しているモジュール
 -

    huid:文字列のハッシュをつくるのに使用
 - body-scroll-lock:ビューアーを開いたときのスクロールロック
 - simple-dropzone:画像ドラッグ&ドロップ操作用
 body-scroll-lock と simple-dropzone は、esm.sh経由での導入
 

  11. 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> ); }
  12. 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; };
  13. 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> ); }
  14. 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> ); }
  15. 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"
  16. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. まとめ
 -

    Fresh x Cloudflare x Tora Viewer で画像投稿サイトを作ってみました。
 - ユーザー認証、ローディングアニメーションなど拡張すれば、
 画像投稿サイトとして十分使えそうです。
 - 今回の実装は islands2つだけを使ったサイトでした。
 islandsを使いこなせるといろんなことができます。

  17. Copyright (C) 2021 Toranoana Inc. All Rights Reserved. お知らせ
 今回取り扱った

    画像投稿サイトの実装の詳細な解説が入ったブログが明日公開
 省略した箇所の解説も入ってますので、ご期待ください!!