Deno FreshでPanda CSSを使う
Fresh
Deno公式のWeb Framework
SSR & Island Architectureを採用している
Panda CSS
Zero Runtime CSS in JS
ビルド時に明示的にコマンドを実行してプロジェクト内のファイルを解析することで必要最低限の静的CSSを出力する
様々なフレームワークへのインストール方法が書いてあるがFresh (Deno)に関する記述はない (Bunは少しだけある)
FreshでPanda CSSを使う
ここに書いていきます
https://github.com/ras0q/deno-fresh-pandacss-sample
- Deno 1.45.4
- Fresh 1.6.8 (もうすぐv2が出るらしいので方法が変わるかも)
- Panda CSS 0.44.0
Freshのセットアップ (Denoはインストールしている前提)
$ deno run -A -r https://fresh.deno.dev .
🍋 Fresh: The next-gen web framework.
Let's set up your new Fresh project.
Do you want to use a styling library? [y/N]
Do you use VS Code? [y/N]
The manifest has been generated for 5 routes and 1 islands.
Project initialized!
Run deno task start to start the project. CTRL-C to stop.
Stuck? Join our Discord https://discord.gg/deno
Happy hacking! 🦕
$ /bin/ls -a
. .git README.md deno.json fresh.config.ts islands routes
.. .gitignore components dev.ts fresh.gen.ts main.ts static
Panda CSSを依存に追加
$ deno add npm:@pandacss/dev
Add @pandacss/dev - npm:@pandacss/dev@^0.44.0
panda.config.mjs
のセットアップ
設定ファイル--node-modules-dir
を付ける or deno.json
にnodeModulesDir: true
を設定する必要がある
Panda CSSがローカルのnode_modules/
を読みに行くため
参考: https://docs.deno.com/runtime/manual/node/npm_specifiers/#--node-modules-dir-flag
$ deno run -A --node-modules-dir npm:@pandacss/dev init
warning: Packages contained npm lifecycle scripts (preinstall/install/postinstall) that were not executed.
This may cause the packages to not work correctly. To run them, use the `--allow-scripts` flag with `deno cache`
(e.g. `deno cache --allow-scripts=pkg1,pkg2 <entrypoint>`):
npm:esbuild@0.20.2
🐼 info [cli] Panda v0.44.0
🐼 info [init:config] creating panda config file: `panda.config.mjs`
🚀 Thanks for choosing Panda to write your css.
...
panda.config.mjs
が作成された
import { defineConfig } from "@pandacss/dev";
export default defineConfig({
// Whether to use css reset
preflight: true,
// Where to look for your css declarations
include: ["./src/**/*.{js,jsx,ts,tsx}", "./pages/**/*.{js,jsx,ts,tsx}"],
// Files to exclude
exclude: [],
// Useful for theme customization
theme: {
extend: {},
},
// The output directory for your css system
outdir: "styled-system",
});
解析対象を変更する
- include: ["./src/**/*.{js,jsx,ts,tsx}", "./pages/**/*.{js,jsx,ts,tsx}"],
+ include: ["./{components,islands,routes}/**/*.{js,jsx,ts,tsx}"],
Freshは静的ファイルを/static
以下で配信するので合わせる
- outdir: "styled-system",
+ outdir: "./static/styled-system",
Denoはimportの拡張子が必須なので拡張子を強制する
+ forceConsistentTypeExtension: true,
Panda CSSをFreshに組み込む
routes/_app.tsx
に生成ファイルの参照を追加
最終的には/styles.css
(static/styles.css
) は消して完全にPanda CSSに移行したい
<link rel="stylesheet" href="/styles.css" />
+ <link rel="stylesheet" href="/styled-system/styles.css" />
一旦走らせて確認
お好みでこれをdeno task
に追加する (がdeno.json
に入れた@pandacss/dev
とバージョンが同期できない?)
$ deno run -A --node-modules-dir npm:@pandacss/dev
🐼 info [css] /path/to/deno-fresh-pandacss-sample/static/styled-system/styles.css
🐼 info [hrtime] Successfully extracted css from 7 file(s) ✨ (179.34ms)
まだ何も入れていないので普通にFreshプロジェクトの初期画面が表示される
$ deno task start
Task start deno run -A --watch=static/,routes/ dev.ts
Watcher Process started.
The manifest has been generated for 5 routes and 1 islands.
🍋 Fresh ready
Local: http://localhost:8000/
TODO: このままだとスタイルを変更してもPanda CSSのホットリロードが走らないのでmain.ts
とdev.ts
に処理を組み込む
Panda CSSを使う
試しにcomponents/Button.tsx
を変更する
変更前はこれ
ここに書いてあるutility classは/static/styles.css
に直接記述されている
import { JSX } from "preact";
import { IS_BROWSER } from "$fresh/runtime.ts";
export function Button(props: JSX.HTMLAttributes<HTMLButtonElement>) {
return (
<button
{...props}
disabled={!IS_BROWSER || props.disabled}
class="px-2 py-1 border-gray-500 border-2 rounded bg-white hover:bg-gray-200 transition-colors"
/>
);
}
import時にmjsの方をimportした上でd.mtsを@deno-typesに指定しないと正しく型が付く&動く状態にならないので注意
毎回2行書くの辛くて別ファイルからexportしてみたが解析が上手くいかなかった
import { IS_BROWSER } from "$fresh/runtime.ts";
+// @deno-types="../static/styled-system/css/index.d.mts"
+import { css } from "../static/styled-system/css/index.mjs";
- class="px-2 py-1 border-gray-500 border-2 rounded bg-white hover:bg-gray-200 transition-colors"
+ class={css({
+ px: 2,
+ py: 1,
+ borderColor: "gray.500",
+ borderWidth: 2,
+ borderRadius: "sm",
+ bg: "white",
+ _hover: {
+ bg: "gray.200",
+ },
+ transitionProperty: "background-color, border-color, color, fill, stroke",
+ transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
+ transitionDuration: "150ms",
+ })}
transitionのところとかはstatic/styles.css
から直接持ってきた
もちろん設定ファイルにスタイルをまとめてこれらをtransition-colors
として定義することもできるはず
余談
Panda CSSを使うのは初めてだったがここでPanda CSS自体がちょっと微妙か、、?と思い始める
生成されるクラスはこんな感じ
使わない色のCSS Variablesなども用意されるため(これはpresetを編集すればいいらしい)、元のstatic/styles.css
よりもサイズがかなり大きくなってしまった、、、
<button class="px_2 py_1 bd-c_gray.500 bd-w_2 bdr_sm bg_white hover:bg_gray.200 trs-prop_background-color,_border-color,_color,_fill,_stroke trs-tmf_cubic-bezier(0.4,_0,_0.2,_1) trs-dur_150ms">-1</button>
@layer utilities {
.px_2 {
padding-inline: var(--spacing-2);
}
.py_1 {
padding-block: var(--spacing-1);
}
.bdr_sm {
border-radius: var(--radii-sm);
}
.bg_white {
background: var(--colors-white);
}
.bd-c_gray\.500 {
border-color: var(--colors-gray-500);
}
.bd-w_2 {
border-width: 2px;
}
.trs-prop_background-color\,_border-color\,_color\,_fill\,_stroke {
--transition-prop: background-color, border-color, color, fill, stroke;
transition-property: background-color, border-color, color, fill, stroke;
}
.trs-tmf_cubic-bezier\(0\.4\,_0\,_0\.2\,_1\) {
--transition-easing: cubic-bezier(0.4, 0, 0.2, 1);
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.trs-dur_150ms {
--transition-duration: 150ms;
transition-duration: 150ms;
}
.trs-dur_1500ms {
--transition-duration: 1500ms;
transition-duration: 1500ms;
}
.hover\:bg_gray\.200:is(:hover, [data-hover]) {
background: var(--colors-gray-200);
}
}