Deno で npmで提供されている UI コンポーネントを使いたかったが、これまでいろいろと試してきた。 限定された状況で、唯一ある程度できる方法がわかったのでまとめておきたい。
参考
動作できないパターン 一旦動作ができないパターンについて記しておきたい。
Packupでの環境の準備です。
以下のように構築します。
1 2 3 4 5 $ tree . |-- index.html `-- src `-- script.tsx
index.html 1 2 3 4 5 6 7 8 9 10 <html > <head > <title > packup-React-cloud-scape</title > <link rel ="stylesheet" href ="https://esm.sh/@cloudscape-design/global-styles/index.css" /> <script src ="src/script.tsx" > </script > </head > <body > <div id ="main" > </div > </body > </html >
src/script.tsx 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import React from "https://esm.sh/react@17.0.2" ;import ReactDOM from "https://esm.sh/react-dom@17.0.2" ;import { Button } from "https://esm.sh/@cloudscape-design/components" ;function App ( ) { return ( <div > <Button variant ="primary" onClick ={() => console.log(123)}>button</Button > </div > ); } function main ( ) { ReactDOM .render (React .createElement (App ), document .querySelector ("#main" )); } addEventListener ("DOMContentLoaded" , () => { main (); });
実行してみると次のようにエラーになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ packup -p 8080 index.html Server running at http://localhost:8080 Using "static" as static directory Download https://esm.sh/v91/@cloudscape-design/components@3.0.25/internal/base-component/styles.css Download https://esm.sh/v91/@cloudscape-design/components@3.0.25/internal/base-component/styles.css > deno:file:///usr/src/app/packup-cloud-scape/src/script.tsx:3:23: error: [plugin: deno] Unreachable. 3 │ import { Button } from "https://esm.sh/@cloudscape-design/components" ; ╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Error: Build failed with 1 error: deno:file:///usr/src/app/packup-cloud-scape/src/script.tsx:3:23: error: [plugin: deno] Unreachable. at failureErrorWithLog (https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:1428:15) at https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:1110:28 at runOnEndCallbacks (https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:900:63) at buildResponseToResult (https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:1108:7) at https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:1215:14 at https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:588:9 at handleIncomingPacket (https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:685:9) at readFromStdout (https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:555:7) at Object.worker.onmessage (https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:2276:36) at https://deno.land/x/esbuild_loader@v0.12.8/vendor/browser.js:2267:41
ということで esm.sh で変換したものが動かない。 このエラーで、実は2カ月ほどいろいろ試していた。
対策する ということで対策する。 この対策方法、きっかけは同僚との雑談なので感謝しかない。
環境構築 Node.jsの環境とDenoの環境を別のコンテナで用意から始めます。
最終的なディレクトリ構成は以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 . |-- DockerfileDeno |-- DockerfileNode |-- docker-compose.yml |-- packup-cloud-scape | |-- builded-cloud-scape | | |-- dist | | | |-- builded-cloud-scape.es.js | | | |-- builded-cloud-scape.umd.js | | | |-- style.css | | | `-- vite.svg | | |-- index.html | | |-- lib | | | `-- main.ts | | |-- node_modules | | |-- package-lock.json | | |-- package.json | | |-- public | | | `-- vite.svg | | |-- src | | | |-- counter.ts | | | |-- main.ts | | | |-- style.css | | | |-- typescript.svg | | | `-- vite-env.d.ts | | |-- tsconfig.json | | `-- vite.config.js | |-- index.html | |-- src | | `-- script.tsx | `-- static `-- tsconfig.json
DockerfileDeno 1 2 3 4 5 6 7 FROM denoland/deno:1.24 .0 RUN apt-get update && apt-get install -y wget RUN mkdir /usr/src/app WORKDIR /usr/src/app EXPOSE 8080
DockerfileNode 1 2 3 4 5 6 7 8 FROM node:18 RUN apt-get update && apt-get install -y wget RUN mkdir /usr/src/app WORKDIR /usr/src/app EXPOSE 8080
docker-compose.yml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 version: "3" services: app: build: context: . dockerfile: DockerfileDeno privileged: true command: tail -f /dev/null ports: - "8080:8080" - "35729:35729" volumes: - .:/usr/src/app:cached tty: true node: build: context: . dockerfile: DockerfileNode privileged: true command: tail -f /dev/null ports: - "8081:8080" volumes: - .:/usr/src/app:cached tty: true
以上の設定で Node と Deno で同じディレクトリをマウントさせる。
@cloudscape-design をビルドする 以下の手順で vite の環境を構築する。(この作業はNodeのコンテナで実施)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ pwd /usr/src/app/packup-cloud-scape $ mkdir builded-cloud-scape $ cd builded-cloud-scape $ npm create vite@latest ✔ Project name: › . ✔ Select a framework: › vanilla ✔ Select a variant: › vanilla-ts $ npm install $ @cloudscape-design/components $ mkdir lib $
ここまで出来たら、 vite.config.js と main.ts を作成。
vite.config.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import { resolve } from "path" ;import { defineConfig } from "vite" ;export default defineConfig ({ build : { lib : { entry : resolve (__dirname, "lib/main.ts" ), name : "builded-cloud-scape" , fileName : (format ) => `builded-cloud-scape.${format} .js` , }, rollupOptions : { external : ["react" ], output : { globals : { react : "React" , }, }, }, }, });
main.ts 1 2 import "@cloudscape-design/global-styles/index.css" ;export { Button } from "@cloudscape-design/components" ;
用意できたら、以下のコマンドでビルドを実行。
1 2 3 4 5 6 7 8 9 $ npm run build > builded-cloud-scape@0.0.0 build > tsc && vite build vite v3.0.8 building for production... ✓ 1359 modules transformed. dist/style.css 304.13 KiB / gzip: 150.98 KiB dist/builded-cloud-scape.es.js 610.90 KiB / gzip: 145.15 KiB dist/builded-cloud-scape.umd.js 409.03 KiB / gzip: 126.98 KiB
これで Cloudscape をビルドできた。
改めて packup で取り込み Cloudscape をesm.shからの読み込みからビルド結果へ変更する。(ここからはDenoのコンテナ)
src/script.tsx 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import React from "https://esm.sh/react@17.0.2" ;import ReactDOM from "https://esm.sh/react-dom@17.0.2" ;import { Button } from "../builded-cloud-scape/dist/builded-cloud-scape.es.js" ; function App ( ) { return ( <div > <Button variant ="primary" onClick ={() => console.log(123)}>button</Button > </div > ); } function main ( ) { ReactDOM .render (React .createElement (App ), document .querySelector ("#main" )); } addEventListener ("DOMContentLoaded" , () => { main (); });
index.html 1 2 3 4 5 6 7 8 9 10 <html > <head > <title > packup-React-cloud-scape</title > <link rel ="stylesheet" href ="./builded-cloud-scape/dist/style.css" /> <script src ="src/script.tsx" > </script > </head > <body > <div id ="main" > </div > </body > </html >
そしてビルド結果の dist/builded-cloud-scape.es.js
を少し変換。
from "react"
を from "https://esm.sh/react@17.0.2"
に書き換える。
1 $ cat ./builded-cloud-scape/dist/builded-cloud-scape.es.js| sed -e 's/from "react"/from "https:\/\/esm.sh\/react@17.0.2"/g' 1<> ./builded-cloud-scape/dist/builded-cloud-scape.es.js
書き換えたら、再度packupを実行。
1 2 3 4 $ packup -p 8080 index.html Server running at http://localhost:8080 Using "static" as static directory index.html bundled in 1344ms
以上で、アクセスしてみると、コンポーネントが表示されている。onClick に定義した動作も行われる。
ということで、動作できた方法は次のようになる。
vite でコンポーネントの使いたい要素を ライブラリモードでビルドする。 そしてそれを使う。
である。
補足 React が使われている MUI
も試したが使えなかった。react-bootstrap
semantic-ui-react
react-bulma-components
は使えた。(いくつか抜粋でコンポーネントを動かしてみただけ、全体の保証はできない)
なんとなく、@emotion のインストールが必要なものは、この方法ではコケる気がする。
また、この方法で作った @cloudscape-design/components
のビルド結果は、Packup では使えたが、Ultra などの他のフレームワークでは上手く動作しなかった。 SSRされるものは怪しい動作になっているように見える。
Packup はあくまでクライアント向けのjsのビルドなので問題はない様子。
今後Denoは Node互換性 npmの互換性 の向上を見込めるので、こういったものも動くようになればいいなぁ。
ということで、いろいろ試して見たが、冒頭の記述の通りかなり限定的な状況でだけ、使用できそうな方法だった。
上手く行かないので deno-ja のコミュニティに、「Deno でフロントを触っている皆さんは、どういう風にスタイリングしてますか」と質問を投げた。 Deno本体だと twind unocss を使っていることらしい。
twind unocss に馴染みは無かったが便利な書き方も共有いただいたので、この記事を一旦のまとめとして書きながら、そちらも調べていた。
そのうちこちらも書いておきたい。
では。