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


    View Slide

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

    奥谷 一陽

    所属:虎の穴ラボ株式会社

    担当:Fantiaなど新規事業系の開発

    興味:TypeScript、Deno

    おすすめコンテンツ:

      『暴太郎戦隊ドンブラザーズ』

      『STAR WARS 小説 』


    Twitter:@okutann88


    View Slide

  3. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    Fresh 使ってますか?


    View Slide

  4. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    さっと作って、

    Deno Deployに上げるのもカンタン


    View Slide

  5. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    ですが、あえてFreshを使って

    ちょっと込み入ったことをしてみました


    View Slide

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

    - Freshをベースに開発する

    - 機能

    - 画像のアップロード

    - 画像の一覧表示

    - 画像の詳細表示

    これらを実装する方針



    View Slide

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

    - Freshをベースに開発する

    - 機能

    - 画像のアップロード

    - 画像の一覧表示

    - 画像の詳細表示

    これらを実装する方針



    View Slide

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

    - Freshをベースに開発する

    - 機能

    - 画像のアップロード

    - 画像の一覧表示

    - 画像の詳細表示

    これらを実装する方針



    View Slide

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

    - Deno

    - Fresh 

    - Cloudflare

    - Tora Viewer


    View Slide

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

    - Deno

    - Fresh 

    - Cloudflare

    - Tora Viewer ?


    View Slide

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

    https://www.npmjs.com/package/@toralab/tora-viewer

    View Slide

  12. 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"
    }

    View Slide

  13. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    全体構成

    deno cli
    APPサーバー
    画像 アップロード
    ・ダウンロード
    ページアクセス
    画像ID登録 APIサーバー
    DB

    View Slide

  14. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    その他追加導入しているモジュール

    - huid:文字列のハッシュをつくるのに使用

    - body-scroll-lock:ビューアーを開いたときのスクロールロック

    - simple-dropzone:画像ドラッグ&ドロップ操作用

    body-scroll-lock と simple-dropzone は、esm.sh経由での導入


    View Slide

  15. 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 (




    );
    }

    View Slide

  16. 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(null);
    const dropzoneRef = useRef(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;
    };

    View Slide

  17. 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 }) => {
    for (const [_key, value] of files) {
    upload(value);
    }
    });
    }, []);
    return (








    Drop or Select






    );
    }

    View Slide

  18. 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 (


    {!miniImages ? "" : miniImages.map((image: Image, index: number) => (
    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;"
    >
    openViewer(index)} />

    ))}


    );
    }

    View Slide

  19. 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"

    View Slide

  20. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    まとめ

    - Fresh x Cloudflare x Tora Viewer で画像投稿サイトを作ってみました。

    - ユーザー認証、ローディングアニメーションなど拡張すれば、

    画像投稿サイトとして十分使えそうです。

    - 今回の実装は islands2つだけを使ったサイトでした。

    islandsを使いこなせるといろんなことができます。


    View Slide

  21. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    お知らせ

    今回取り扱った 画像投稿サイトの実装の詳細な解説が入ったブログが明日公開

    省略した箇所の解説も入ってますので、ご期待ください!!


    View Slide

  22. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    ありがとうございました


    View Slide