社内向けに、フロントエンド関連のニュースや業務で発生したQ&A、利用しているライブラリなどの情報を定期的に書いています。
社内の開発部メンバーに向けて直近でリリースされたライブラリなどの情報をMatsuri-tech Frontend Weeklyとしてまとめています。内容は実務や趣味で使えそうなものを中心に扱っており、網羅的ではなく偏りがあります。
2024年2月22日にDeno 1.41がリリースされました。deno compileで生成されるバイナリがかなり小さくなりました。
2024年2月20日にRemix 2.7.0がリリースされました。SPAモードが安定版になった他、Remix ViteがCloudflare Pagesをサポート、Viteとの互換性の改善などが行われています。
MetaがReact Strict DOM(RSD)を公開しました。これはWeb およびネイティブ用のスタイル付きReactコンポーネントの開発の改善および標準化を目的としたReact DOMとStyleXの実験的な統合とのことです。
React Native for WebはReact NativeのAPIをWeb上で補完しようするものでしたが、RSDはWeb APIをReact Nativeに組み込んでいこうとする試みです。
既にかなりの機能が実装されています。
import { css, html } from 'react-strict-dom';
const styles = css.create({
container: { borderTopWidth: 1 },
h1: { padding: 10, backgroundColor: '#eee' },
content: { padding: 10 },
})
export default function Example(props) {
const { title, children } = props
return (
<html.div style={styles.container}>
<html.h1 style={styles.h1}>{title}</html.h1>
<html.div style={styles.content}>{children}</html.div>
</html.div>
)
}
htmzは標準のHTMLを利用してページの部分更新を行う数行のスニペットです。
<script>
function htmz(frame) {
setTimeout(() =>
document
.querySelector(frame.contentWindow.location.hash || null)
?.replaceWith(...frame.contentDocument.body.children)
);
}
</script>
<iframe hidden name="htmz" onload="window.htmz(this)"></iframe>
実用的かはともかく、かなり面白いアイデアだと思います。リンクをクリックされると、iframeに対応したコンテンツが描画され、そのコンテンツをhashのidが付いた要素の中身と置換する仕組みになっています。
<base target="htmz" />
<div role="tablist">
<a class="tab" href="dog.html#my-tab-panel">Dog</a>
<a class="tab" href="cat.html#my-tab-panel">Cat</a>
<a class="tab" href="horse.html#my-tab-panel">Horse</a>
</div>
<div id="my-tab-panel" role="tabpanel"></div>
<iframe hidden name="htmz" onload="window.htmz(this)"></iframe>
Safetestは、Netflixの開発したPlaywrightやVitest/Jestを組みわせたテストライブラリです。
従来のフロントエンドのテスト手法である単体/統合テストやE2Eテストの欠点を、両方を組み合わせることで補完することを目的としています。アプリケーションの起動時にテスト用のフックをインジェクトする仕組みのため、ブラウザとテストコンテキスト間の双方向通信や、PlaywrightやJest/Vitestの機能へのアクセスも可能になっています。
テストの記述方法は、見慣れたものです。
// Header.tsx
export const Header = ({ admin }: { admin: boolean }) => (
<div className="header">
<div className="header-title">The App</div>
<div className="header-user">
<div className="header-user-name">admin</div>
{admin && <div className="header-user-admin">admin</div>}
<div className="header-user-logout">Logout</div>
</div>
</div>
);
// Header.safetest.tsx
import { describe, it, expect } from 'safetest/jest';
import { render } from 'safetest/react';
import { Header } from './Header';
describe('Header', () => {
it('can render a regular header', async () => {
const { page } = await render(<Header />);
await expect(page.locator('text=Logout')).toBeVisible();
await expect(page.locator('text=admin')).not.toBeVisible();
expect(await page.screenshot()).toMatchImageSnapshot();
});
it('can render an admin header', async () => {
const { page } = await render(<Header admin={true} />);
await expect(page.locator('text=Logout')).toBeVisible();
await expect(page.locator('text=admin')).toBeVisible();
expect(await page.screenshot()).toMatchImageSnapshot();
});
});
なお、実験的ですがPlaywrightにもComponent単位でのテストを可能にする似たようなことが出来る機能が入っています。