プログラミング/svelte の履歴の現在との差分(No.3)

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
#author("2024-09-06T15:08:14+00:00","default:administrator","administrator")
[[公開メモ]]

* svelte や svelte kit を使いこなしたい [#o86663ca]

svelte や svelte kit は Web サイト構築用のライブラリ

Visual Studio Code を最大限活用するために作られた最新のエコシステムの恩恵を受けるために勉強してみよう

以下で学ぶこと:

- データベースの使い方を学ぶ (Prisma)
- フォームのバリデーション (SuperForms, Zod)
- サインアップ・ログイン・ログアウトのできる認証機能 (Lucia)
- その際にメールアドレスの確認を行う (nodemailer)
- css ライブラリを選定する (TailwindCSS, DaisyUI, svelte-french-toast)
- デプロイ方法を学ぶ (node build)
- テストを書く (Playwright, vitest)


* 目次 [#p0ab4c9c]

#contents

** いまのところ情報収集中 [#o6d339e1]
** いろいろ読んで勉強中 [#o6d339e1]

- SvelteKit+Superforms+Prisma+Luciaでログイン機能を爆速で実装する~
https://zenn.dev/gawarago/articles/f75f5113a3803d
- SvelteKitが正式リリースされたのでtRPCとPrismaを使ってWebアプリを開発してみた~
https://zenn.dev/kosei28/articles/d965f221a656fd
- Vitest / Playwrightを使ってSvelteのコンポーネントをテストする~
https://qiita.com/oekazuma/items/925ddbf48870fb999c19#vitest%E3%81%A8%E3%81%AF
- TypeScript 4.9のas const satisfiesが便利。型チェックとwidening防止を同時に行う~
https://zenn.dev/moneyforward/articles/typescript-as-const-satisfies
- コーディング不要でGraphQLサーバが作れるPrismaを触ってみて可能性を感じた - SMARTCAMP Engineer Blog~
https://tech.smartcamp.co.jp/entry/started-prisma
- worst password list~
https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10-million-password-list-top-100000.txt
- 5歳娘「パパ、余分なpropsいっぱい書くんだね!」~
https://qiita.com/Yametaro/items/814f40d08e9d30584e20#5%E6%AD%B3%E5%A8%98%E3%83%91%E3%83%91%E4%BD%99%E5%88%86%E3%81%AAprops%E3%81%84%E3%81%A3%E3%81%B1%E3%81%84%E6%9B%B8%E3%81%8F%E3%82%93%E3%81%A0%E3%81%AD
-- svelte での書き方 → https://stackoverflow.com/questions/76285794/svelte-components-intrinsicelements-or-sveltehtmlelements-for-extending-with-ht

* VS Code + Git Bash + nvm のインストール [#d5c705f1]
* いよいよやってみる [#s61d3616]

https://blog.css-net.co.jp/entry/dev-environment-windows#2-2-Git-for-Windows
ここでの作業内容を収めた GitHub プロジェクト:~
https://github.com/osamutake/svelte-authtest

に従った。
+ [[プログラミング/svelte/VSCodeの準備]]
+ [[プログラミング/svelte/テストの仕方を確認]]
+ [[プログラミング/svelte/Prisma と Lucia を使った認証システム]]
+ [[プログラミング/svelte/メールアドレスの確認を行う]]
+ [[プログラミング/svelte/認証機能のテストを追加]]
+ [[プログラミング/svelte/管理者権限を付与する]]
+ [[プログラミング/svelte/ブログ的なもの作り-投稿・表示・編集]]
+ [[プログラミング/svelte/コード配置の整理]]
+ [[プログラミング/svelte/記事の見た目をいじる]]
+ [[プログラミング/svelte/pukiwikiの記事を流し込む]]

** VS Code 上の GitBash で nvm が動かない [#tdc757ef]
* Svelte 5 [#g8e59aef]

VS Code を起動中に nvm をインストールすると、
- [[プログラミング/svelte/svelte5の$stateをexportする]]
- [[プログラミング/svelte/svelte5への移行]]
- [[プログラミング/svelte/svelte5手順覚書]]
- [[プログラミング/svelte/svelte5手抜き国際化]]
- [[プログラミング/svelte/svelte5ダイナミックコンポーネントを使ったテーマ変更]]

 LANG: console
 $ nvm
 bash: nvm: command not found
* 小ネタ [#vd27dac7]

とか、
** typescript + vitest で npm パッケージの開発 [#g7ba2712]

 LANG: console
 $ nvm install lts
 ERROR open \settings.txt: The system cannot find the file specified.
[[typescript + vitest で npm パッケージの開発 2024]]

となる。
** オンプレミスの GitLab サーバーで CI ランナーと npm パッケージサーバーを動かす [#h214d3d0]

これは環境変数の更新が VS Code に認識されていないためなので、
VS Code を一旦落として立ち上げなおすと動くようになる。
[[オンプレGitLabでgit+CI+npmサーバー2024]]

 LANG: console
 $ node
 bash: node: command not found
 $ nvm list
** svelte コンポーネントの Re-export [#b20fae61]

    18.16.0
default に名前を付けて Export すればいい

のような場合は、
 LANG:html
 <script lang='ts'>
   export { default as Component } from 'component.svelte';

 LANG: console
 $ nvm use 18.16.0
 Now using node v18.16.0 (64-bit)
 
 $ nvm list
 
  * 18.16.0 (Currently using 64-bit executable)
 
 $ node
  Welcome to Node.js v18.16.0.

のように nvm use する。
** +layout.server.ts からの PageData を +page.server.ts で使う [#hc48192a]

** pnpm を入れる [#dd20e999]
*** load 内で使うとき [#o751a952]

良いうわさを聞くので。
load 内で使えればよいのであれば event.parent() を使って

 LANG: console
 $ 'npm' install -g pnpm
 
 added 1 package in 6s
~+page.server.ts
 LANG:ts
 export const load = (async (event) => {
   const data = await event.parent();

そして ~/.bashrc に、
とすればよい。

 alias npm=pnpm
*** actions で使うとき [#kb762bb4]

としてしまう。
actions が呼ばれるときはページのレンダリングと違って API としての呼び出しになるため layout.server.ts は呼ばれない。

** VS Code 設定 [#u7dae213]
そういうデータはどうやら PageData ではなく Locals に保存されるべきで src/hooks.server.js で設定するのが筋らしい。

- フォント Myrica~
https://www.sejuku.net/blog/60345 を参考にした
- テーマファイルについて~
https://coliss.com/articles/build-websites/operation/work/best-of-visual-studio-code-themes.html
- アドオン
-- Japanese Language Pack for Visual Studio Code~
https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja
-- Keyboard Macro Beta~
https://marketplace.visualstudio.com/items?itemName=tshino.kb-macro
-- macro-commander (Command Runner)~
https://marketplace.visualstudio.com/items?itemName=jeff-hykin.macro-commander
-- GLSL Lint (WebGL をやる場合)~
https://marketplace.visualstudio.com/items?itemName=dtoplak.vscode-glsllint
-- Shader languages support for VS Code (WebGL をやる場合)~
https://marketplace.visualstudio.com/items?itemName=slevesque.shader
-- ESLint~
https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint
-- GitLens — Git supercharged~
https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens
-- npm Intellisense~
https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense
-- Playwright Test for VSCode~
https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright
-- Prettier - Code formatter~
https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode
-- Pretty TypeScript Errors~
https://marketplace.visualstudio.com/items?itemName=yoavbls.pretty-ts-errors
-- Prisma~
https://marketplace.visualstudio.com/items?itemName=Prisma.prisma
-- Svelte for VS Code~
https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode
- https://kit.svelte.jp/docs/types#app-locals
- https://kit.svelte.jp/docs/hooks

* テスト環境の確認 [#f1f86045]
** 呼び出し間隔の調整を行う [#t37e6d7d]

https://qiita.com/oekazuma/items/925ddbf48870fb999c19#vitest%E3%81%A8%E3%81%AF
主にイベントハンドラからの呼び出しを UI へフィードバックする際に使うことを想定している。

 LANG: console
 $ pnpm create svelte@latest testenv
 .../Local/pnpm/store/v3/tmp/dlx-41072    |   +6 +
 Packages are hard linked from the content-addressable store to the virtual store.
   Content-addressable store is at: C:\Users\osamu\AppData\Local\pnpm\store\v3
   Virtual store is at:             ../../Users/osamu/AppData/Local/pnpm/store/v3/tmp/dlx-41072/node_modules/.pnpm
 .../Local/pnpm/store/v3/tmp/dlx-41072    | Progress: resolved 6, reused 0, downloaded 6, added 6, done
 LANG: ts
 // const throttled = new Throttle(func, minInterval);
 // throttled.exec(arg1, arg2);
 // のように使うと、最低限 interval 空けて実行される
 // interval 未満の場合には interval だけ待ってから実行
 // 実行待ちがあって呼び出されればそちらをキャンセルして新しい方を実行待ちする
 export class Throttle {
   lastExecTime = 0;
   timerId: number | undefined;
 
 create-svelte version 4.2.0
   constructor(
     private func: (...args: unknown[]) => void,
     private millisec: number = 50
   ) {}
 
 ┌  Welcome to SvelteKit!

 ◇  Which Svelte app template?
 │  Skeleton project

 ◇  Add type checking with TypeScript?
 │  Yes, using TypeScript syntax

 ◇  Select additional options (use arrow keys/space bar)
│  Add ESLint for code linting, Add Prettier for code formatting, Add Playwright for browser testing, Add Vitest for unit testing

 └  Your project is ready!
   exec(...args: unknown[]) {
     // 実行待ちがあればキャンセル
     window.clearTimeout(this.timerId);
     this.timerId = undefined;
 
 ✔ Typescript
   Inside Svelte components, use <script lang="ts">
     const execute = () => {
       this.timerId = undefined;
       this.func(...args);
       this.lastExecTime = performance.now();
     };
 
 ✔ ESLint
   https://github.com/sveltejs/eslint-plugin-svelte
 
 ✔ Prettier
   https://prettier.io/docs/en/options.html
   https://github.com/sveltejs/prettier-plugin-svelte#options
 
 ✔ Playwright
   https://playwright.dev
 
 ✔ Vitest
   https://vitest.dev
 
 Install community-maintained integrations:
   https://github.com/svelte-add/svelte-add
 
 Next steps:
   1: cd testenv
   2: npm install (or pnpm install, etc)
   3: git init && git add -A && git commit -m "Initial commit" (optional)
   4: npm run dev -- --open
 
 To close the dev server, hit Ctrl-C
 
 Stuck? Visit us at https://svelte.dev/chat
 $ cd testenv
 $ pnpm install
 $ git init && git add -A && git commit -m "Initial commit"
 $ pnpm run dev
 
 > testenv@0.0.1 dev (home)\svelte\testenv
 > vite dev
 
 
 Forced re-optimization of dependencies
 
   VITE v4.3.9  ready in 1901 ms
 
   ➜  Local:   http://localhost:5173/
   ➜  Network: use --host to expose
   ➜  press h to show help
 
   Shortcuts
   press r to restart the server
   press u to show server url
   press o to open in browser
   press c to clear console
   press q to quit

ここで o を押すとブラウザが立ち上がって Welcome to SvelteKit が表示された。

&ref(vite-dev.png);

^C で抜けて、

 LANG: console
 $ cat package.json 
 {
         "name": "testenv",
         "version": "0.0.1",
         "private": true,
         "scripts": {
                 "dev": "vite dev",
                 "build": "vite build",
                 "preview": "vite preview",
                 "test": "playwright test",
                 "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
                 "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
                 "test:unit": "vitest",
                 "lint": "prettier --plugin-search-dir . --check . && eslint .",
                 "format": "prettier --plugin-search-dir . --write ."
         },
         "devDependencies": {
                 "@playwright/test": "^1.28.1",
                 "@sveltejs/adapter-auto": "^2.0.0",
                 "@sveltejs/kit": "^1.5.0",
                 "@typescript-eslint/eslint-plugin": "^5.45.0",
                 "@typescript-eslint/parser": "^5.45.0",
                 "eslint": "^8.28.0",
                 "eslint-config-prettier": "^8.5.0",
                 "eslint-plugin-svelte": "^2.26.0",
                 "prettier": "^2.8.0",
                 "prettier-plugin-svelte": "^2.8.1",
                 "svelte": "^3.54.0",
                 "svelte-check": "^3.0.1",
                 "tslib": "^2.4.1",
                 "typescript": "^5.0.0",
                 "vite": "^4.3.0",
                 "vitest": "^0.25.3"
         },
         "type": "module"
     // あとどれだけ待つ必要があるか
     const wait = this.lastExecTime + this.millisec - performance.now();
     if (wait < 0) {
       // 即実行
       execute();
     } else {
       // 実行予約
       this.timerId = window.setTimeout(execute, wait);
     }
   }
 }

** vitest [#seaa70b8]
** path へのエイリアスを tsconfig で利かす [#mfcee49f]

 LANG: console
 $ pnpm run test:unit
 
 > testenv@0.0.1 test:unit (home)\svelte\testenv
 > vitest
 
 
  DEV  v0.25.8 ~/svelte/testenv
 
  ✓ src/index.test.ts (1)
 
  Test Files  1 passed (1)
       Tests  1 passed (1)
    Start at  12:11:24
    Duration  2.21s (transform 720ms, setup 0ms, collect 77ms, tests 6ms)
 
 
  PASS  Waiting for file changes...
        press h to show help, press q to quit
 
   Watch Usage
   press a to rerun all tests
   press f to rerun only failed tests
   press u to update snapshot
   press p to filter by a filename
   press t to filter by a test name regex pattern
   press q to quit
tsx を使うと .ts ファイルを直接実行できて便利なのだけれど、そこから呼ばれる import に $lib などのパスエイリアスが含まれて入れるとエラーになる。

別の terminal から、
その場合には tsx に --tsconfig を指定して動かすといい

 LANG: console
 $ touch src/index.test.ts
 LANG:console
 $ ./node_modules/.bin/tsx --tsconfig tsconfig.json some-script.ts 

すると、再度テストが実行される。
** grep する [#a09ba0fc]

 LANG: console
 $ cat vite.config.ts 
 import { sveltekit } from '@sveltejs/kit/vite';
 import { defineConfig } from 'vitest/config';
 
 export default defineConfig({
         plugins: [sveltekit()],
         test: {
                 include: ['src/**/*.{test,spec}.{js,ts}']
         }
 });
~-r で再帰をかけておき、除外するディレクトリを exclude-dir で指定するといい

となっているので、src/ の下のすべての .test.ts および .spec.ts がテストの対象になる。
 LANG:console
 $ grep --exclude-dir={node_modules,assets,.svelte-kit,build,bower_components} -rl "検索対象"

** PlayWright [#n96c68b1]
~-l を付けることでファイル名のみを表示させている

 LANG: console
 $ pnpm run test
 
 > testenv@0.0.1 test (home)\svelte\testenv
 > playwright test
 
 
 Running 1 test using 1 worker
 
 [WebServer]
 [WebServer]
 [WebServer]
   ✘  1 test.ts:3:1 › index page has expected h1 (58ms)
 
 
   1) test.ts:3:1 › index page has expected h1  ──────────────────────────────────────────────────────
 
     Error: browserType.launch: Executable doesn't exist at C:\Users\osamu\AppData\Local\ms-playwright\chromium-1064\chrome-win\chrome.exe
     ╔═════════════════════════════════════════════════════════════════════════╗
     ║ Looks like Playwright Test or Playwright was just installed or updated. ║
     ║ Please run the following command to download new browsers:              ║
     ║                                                                         ║
     ║     npx playwright install                                              ║
     ║                                                                         ║
     ║ <3 Playwright Team                                                      ║
     ╚═════════════════════════════════════════════════════════════════════════╝
 
 
 
 
   1 failed
     test.ts:3:1 › index page has expected h1 
 ───────────────────────────────────────────────────────
  ELIFECYCLE  Test failed. See above for more details.
VSC の terminal なら表示されたファイル名の Ctrl+Click でファイルを開ける

ふむ。言われた通りにしよう。
** ZodObject の中身を見る [#b5d6e707]

 LANG: console
 $ npx playwright install
 Downloading Chromium 114.0.5735.35 (playwright build v1064) from https://playwright.azureedge.net/builds/chromium/1064/chromium-win64.zip
 113.5 Mb [====================] 100% 0.0s
 Chromium 114.0.5735.35 (playwright build v1064) downloaded to C:\Users\osamu\AppData\Local\ms-playwright\chromium-1064
 Downloading FFMPEG playwright build v1009 from https://playwright.azureedge.net/builds/ffmpeg/1009/ffmpeg-win64.zip
 1.4 Mb [====================] 100% 0.0s
 FFMPEG playwright build v1009 downloaded to C:\Users\osamu\AppData\Local\ms-playwright\ffmpeg-1009
 Downloading Firefox 113.0 (playwright build v1408) from https://playwright.azureedge.net/builds/firefox/1408/firefox-win64.zip79.7 Mb [====================] 100% 0.0s
 Firefox 113.0 (playwright build v1408) downloaded to C:\Users\osamu\AppData\Local\ms-playwright\firefox-1408
 Downloading Webkit 16.4 (playwright build v1848) from https://playwright.azureedge.net/builds/webkit/1848/webkit-win64.zip
 45.2 Mb [====================] 100% 0.0s
 Webkit 16.4 (playwright build v1848) downloaded to C:\Users\osamu\AppData\Local\ms-playwright\webkit-1848
 $ pnpm run test
 > testenv@0.0.1 test (home)\svelte\testenv
 > playwright test
 LANG:ts
 export const SettingScheme = z.object({
   param1: z.string().default('default1'),
   param2: z.string().default('default2'),
 });
  
 // データ型を得る
 type Setting = z.infer<typeof SettingScheme>;
 
 // z.object に渡した { param1: ..., param2: ... } を得る
 const objectDefinition = SettingScheme.shape;
 
 Running 1 test using 1 worker
 
 [WebServer]
 [WebServer]
 [WebServer]
   ✓  1 test.ts:3:1 › index page has expected h1 (967ms)
 
   1 passed (4.0s)
 $ ls -a test-results/
 ./  ../
 // objectDefinition['param1'] は ZodDefault<ZodString> のようなもの
 // ZodString を取り出すには
 let param1def: any = objectDefinition['param1];
 while(param1def?._def?.innerType) {
   // ZodDefault などでラップされているのを剥がす
   param1def = param1def_def.innerType;
 }

かなり時間がかかるけど、ちゃんと動いたと言っている。
test-results/ には何も入っていない。

上では 4.0s かかったと言っているけど実際にはテストが走り始めるまでに
20秒近くかかっていて、そっちの方がずっと長い。

 LANG: console
 $ time node_modules/.bin/playwright test
 
 Running 1 test using 1 worker
 
 [WebServer]
 [WebServer]
 [WebServer]
   ✓  1 test.ts:3:1 › index page has expected h1 (473ms)
 
   1 passed (3.0s)
 
 real    0m22.550s
 user    0m0.076s
 sys     0m0.247s

gui を使うことにして立ち上げっぱなしにすると、起動にかかる時間を待たずに済む。

 LANG: console
 $ node_modules/.bin/playwright test --ui
 
&ref(playwright-gui.png,,50%);

うまく行きそうだ。

 LANG: console
 $ cat playwright.config.ts 
 import type { PlaywrightTestConfig } from '@playwright/test';
 const config: PlaywrightTestConfig = {
         webServer: {
                 command: 'npm run build && npm run preview', 
                 port: 4173
         },
         testDir: 'tests',
         testMatch: /(.+\.)?(test|spec)\.[jt]s/
 };

tests/ フォルダの *.test.ts のようなファイルがテスト対象になる。

あーと、これを見ると ファイルを更新した場合には npm run build をし直さなければならないっぽいのでその点には注意が必要だ。

 LANG: console
 $ git status
 On branch master
 Untracked files:
   (use "git add <file>..." to include in what will be committed)
         test-results/
 
 nothing added to commit but untracked files present (use "git add" to track)

となってしまうので、.gitignore に /test-results を追加することも必要。

 LANG: console
 $ echo /test-results >> .gitignore
 $ git status
 On branch master
 Changes not staged for commit:
   (use "git add <file>..." to update what will be committed)
   (use "git restore <file>..." to discard changes in working directory)
         modified:   .gitignore
 
 no changes added to commit (use "git add" and/or "git commit -a")
 $ git commit -a -m "add /test-results to .gitignore"

何にしても、ユニットテストばかりでなく E2E テストまで Out of the box で簡単に行えるのはすごい。~
apache2 や nginx どころか WSL すらセットアップの必要がないとは。。。

* Prisma と Lucia を使った認証システム [#a42dca10]

https://zenn.dev/gawarago/articles/f75f5113a3803d を参考に。


Counter: 2312 (from 2010/06/03), today: 1, yesterday: 2