Preact 使う
#React #Node
Preact | Preact: Fast 3kb React alternative with the same ES6 API. Components & Virtual DOM.
Alias でやる作戦
Getting Started | Preact: Fast 3kb React alternative with the same ES6 API. Components & Virtual DOM.
webpack や jest で react の alias として使う設定例がある
楽したいわけでもないし、まず素直に使えるようにしてみる
import
普段使うやつどこにあるか
https://preactjs.com/guide/v10/api-reference/
code:import.ts
import {h, render, createContext, Fragment, VNode} from 'preact';
import {useState, useEffect, useContext, useCallback useRef, useReducer} from 'preact/hooks';
import {memo} from 'preact/compat';
import type {ComponentChildren} from 'preact';
jsxFactory
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.ts(2686)
javascript - React + TypeScript: 'React' refers to a UMD global but the current file is a module. Consider adding an import instead. (Justification) - Stack Overflow
コードに import {h} from 'preact'; を追加
tsconfig.json
compilerOptions に "jsxFactory": "h" を設定する
デフォルトは React.createElement なので JSX を変換する際スコープに React が必要
2021/6/26 TypeScript >= 4.1.1 では以下の設定に
TypeScript | Preact: Fast 3kb React alternative with the same ES6 API. Components & Virtual DOM.
React の eslint 設定が残っていると怒られるので
eslint-plugin-react は普通に使う
"react/react-in-jsx-scope": "off"
eslint-plugin-react/react-in-jsx-scope.md at e3e767bd041988d9acb7713874c0632c68408347 · yannickcr/eslint-plugin-react なんか引数で h にできないかと思ったけどだめ
settings.react.pragma を "h" にする
これで h の no-unused-vars も消える
settings.react.fragment も "Fragment" にするとよい
対応表: https://www.typescriptlang.org/docs/handbook/jsx.html#basic-usage
? h である必要あるかな?
Preact は createElement もあるので import React, {...} from 'preact' とかのが楽だったりしないかな?
実際どうなのか、型とか合うのかは見てない
? Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.
settings.react.version が "detect" なら react がないと言われるし、消せば書けと言われる
"latest" とすると黙るけどウソじゃん
Fragment
https://preactjs.com/guide/v10/components/#fragments
jsxFactory を指定している時 <>...</> の JSX fragment は使えない
import { Fragment } from 'preact'; があるので代わりに使う
<Fragment>...</Fragment>
Announcing TypeScript 4.0 Beta | TypeScript
TypeScript 4.0 で jsxFragmentFactory が compilerOptions に入る
tsconfig.json で "jsxFragmentFactory": "Fragment" を指定するとよい
VNode
たぶん ReactNode の代わり
イベントの型が合わない
10.0.0-rc.3 preact/compat typescript incompatibilities · Issue #1930 · preactjs/preact
Typescript types for onInput, onBlur etc.. · Issue #2301 · preactjs/preact
Context
https://preactjs.com/guide/v10/context/
createContext は preact
useContext は preact/hooks
styled-component
react 一式を削除して build した際に出た
Preact X, Preact render to string & Styled Components · Issue #1417 · preactjs/preact
code:styled-component.error
ERROR in ./node_modules/styled-components/dist/styled-components.browser.esm.js
Module not found: Error: Can't resolve 'react' in '/Users/pokutuna/.ghq/github.com/pokutuna/chrome-cocopy/node_modules/styled-components/dist'
styled-components が React を参照している
うーん結局 alias しないといけなさそう
code:webpack.config.js
resolve: {
extensions: '.js', '.ts', '.tsx', '.json',
alias: {
react: 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react-dom': 'preact/compat',
},
},
...
jsx-runtime 対応
Announcing TypeScript 4.1 | TypeScript
新しい JSX トランスフォーム – React Blog
preact では
preact-jsx-runtime - npm を入れる
jest では alias する
code:jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
setupFilesAfterEnv: './src/jest.setup.js',
moduleNameMapper: {
'^react$': 'preact/compat',
'^react-dom$': 'preact/compat',
'^react-dom/test-utils$': 'preact/test-utils',
'^react/jsx-runtime$': 'preact-jsx-runtime',
},
};
test & lint
eslint-config-preact
preactjs/eslint-config-preact: Unopinionated baseline ESLint config for Preact and Preact CLI codebases.
なんか強いな、plugin とかじゃない、gts や ts と組み合せられなさそうだし使わない
install せず index.js 見て必要なところだけ真似ようかと思ったけど、そんなにないかな
(普通に React として lint とかを設定してればだいたいよさそう)
jest-preset-preact
preactjs/jest-preset-preact: Jest preset for testing Preact apps
まだみてない、テスト中の JSX を preact の h にしてくれそう
みた
ts-jest と同時に使うのだるいので必要なところ(モジュール名のマッピング)だけ参考にする
code:jest.config.js
module.exports = {
...
moduleNameMapper: {
'^react$': 'preact/compat',
'^react-dom$': 'preact/compat',
'^.+\\.(css|sass|scss|less)$': 'identity-obj-proxy',
},
};
preact-render-to-string
preactjs/preact-render-to-string: Universal rendering for Preact: render JSX and Preact components to HTML.
Server-Side Rendering | Preact: Fast 3kb React alternative with the same ES6 API. Components & Virtual DOM.
snapshot テストするときに
デフォルトは pretty な出力じゃなくて diff がまともに見れないのでオプションを渡す
code:App.test.tsx
import {h} from 'preact';
import render from 'preact-render-to-string';
import {App} from './App';
test('render App', () => {
expect(render(<App />, {}, {pretty: true})).toMatchSnapshot();
});
非同期に取得する値とか待ってくれない?
2020/12/21 使ってない
@testing-library/pract
Testing with Preact Testing Library | Preact: Fast 3kb React alternative with the same ES6 API. Components & Virtual DOM.
これぐらいでなんとかなっている
code:imports
import {render, screen, waitFor} from '@testing-library/preact';
import '@testing-library/jest-dom';
import 'jest-styled-components';
---.icon
サイズ差
スカスカのブラウザ拡張でみてみる
React
code:build-react
$ webpack
Hash: 63ac109e35f56a48c91f
Version: webpack 4.43.0
Time: 3849ms
Built at: 2020-07-16 10:11:08
Asset Size Chunks Chunk Names
eventpage.html 184 bytes emitted
eventpage.js 22.1 KiB eventpage emitted eventpage
img/icon/128.png 1.61 KiB emitted
img/icon/16.png 488 bytes emitted
img/icon/32.png 694 bytes emitted
img/icon/48.png 880 bytes emitted
manifest.json 608 bytes emitted
options.html 155 bytes emitted
options.js 2.63 MiB options emitted options
popup.html 228 bytes emitted
popup.js 2.38 MiB popup emitted popup
sandbox.html 117 bytes emitted
sandbox.js 12.4 KiB sandbox emitted sandbox
Entrypoint eventpage = eventpage.js
Entrypoint sandbox = sandbox.js
Entrypoint popup = popup.js
Entrypoint options = options.js
./src/config.ts 1.3 KiB {popup} built
./src/eventpage.ts 3.67 KiB {eventpage} built
./src/options.tsx 629 bytes {options} built
./src/popup.tsx 2.81 KiB {popup} built
./src/sandbox.ts 1.09 KiB {sandbox} built
./src/util.ts 801 bytes {eventpage} {popup} built
+ 23 hidden modules
Preact
code:build-preact
$ webpack
Hash: 39688f882396dc42a4a8
Version: webpack 4.43.0
Time: 2955ms
Built at: 2020-07-16 10:10:38
Asset Size Chunks Chunk Names
eventpage.html 184 bytes emitted
eventpage.js 22.1 KiB eventpage emitted eventpage
img/icon/128.png 1.61 KiB emitted
img/icon/16.png 488 bytes emitted
img/icon/32.png 694 bytes emitted
img/icon/48.png 880 bytes emitted
manifest.json 614 bytes emitted
options.html 155 bytes emitted
options.js 518 KiB options emitted options
popup.html 228 bytes emitted
popup.js 63.5 KiB popup emitted popup
sandbox.html 117 bytes emitted
sandbox.js 12.4 KiB sandbox emitted sandbox
Entrypoint eventpage = eventpage.js
Entrypoint sandbox = sandbox.js
Entrypoint popup = popup.js
Entrypoint options = options.js
./src/config.ts 1.3 KiB {popup} built
./src/eventpage.ts 3.67 KiB {eventpage} built
./src/options.tsx 348 bytes {options} built
./src/popup.tsx 2.48 KiB {popup} built
./src/sandbox.ts 1.09 KiB {sandbox} built
./src/util.ts 801 bytes {eventpage} {popup} built
+ 20 hidden modules
見づらいので差
code:js-sizes-with-react
eventpage.js 22.1 KiB eventpage emitted eventpage
options.js 2.63 MiB options emitted options
popup.js 2.38 MiB popup emitted popup
sandbox.js 12.4 KiB sandbox emitted sandbox
code:js-sizes-with-preact
eventpage.js 22.1 KiB eventpage emitted eventpage
options.js 346 KiB options emitted options
popup.js 63.5 KiB popup emitted popup
sandbox.js 12.4 KiB sandbox emitted sandbox
sanbox や eventpage は react 使ってないので差が出てない