入門
不熟悉 Preact?不熟悉虛擬 DOM?請查看教學。
本指南協助您快速上手,開始使用 3 個熱門選項開發 Preact 應用程式。如果您不熟悉 Preact,我們建議從Vite開始。
無建置工具路徑
Preact 的封裝可直接在瀏覽器中使用,不需要任何建置或工具
<script type="module">
import { h, render } from 'https://esm.sh/preact';
// Create your app
const app = h('h1', null, 'Hello World!');
render(app, document.body);
</script>
使用這種方式開發的主要缺點是缺乏 JSX,這需要建置步驟。下一個區段記載了 JSX 的人體工學且效能良好的替代方案。
JSX 的替代方案
撰寫原始的 h
或 createElement
呼叫可能會很繁瑣。根據我們的經驗,JSX 的優點在於它看起來很像 HTML,這讓許多開發人員更容易理解。不過 JSX 需要建置步驟,因此我們強烈推薦使用稱為 HTM 的替代方案。
HTM 是一種類似 JSX 的語法,可在標準 JavaScript 中運作。它不需要建置步驟,而是使用 JavaScript 本身的 標記範本 語法,該語法於 2015 年新增,並受 所有現代瀏覽器 支援。這是一種越來越流行的撰寫 Preact 應用程式的方式,因為與傳統的前端建置工具設定相比,它需要理解的活動部分較少。
<script type="module">
import { h, render } from 'https://esm.sh/preact';
import htm from 'https://esm.sh/htm';
// Initialize htm with Preact
const html = htm.bind(h);
function App (props) {
return html`<h1>Hello ${props.name}!</h1>`;
}
render(html`<${App} name="World" />`, document.body);
</script>
提示:HTM 也提供方便的單一匯入 Preact 版本
import { html, render } from 'https://esm.sh/htm/preact/standalone'
如需更完整的範例,請參閱 使用 Preact 搭配 HTM 和 ImportMaps,如需 HTM 的更多資訊,請查看其 文件。
建立一個 Vite 驅動的 Preact 應用程式
Vite 在過去幾年已成為一個非常受歡迎的工具,用於在許多架構中建立應用程式,而 Preact 也不例外。它建立在流行的工具之上,例如 ES 模組、Rollup 和 ESBuild。Vite,透過我們的初始化器或他們的 Preact 範本,不需要任何設定或先備知識即可開始,而這種簡潔性使其成為使用 Preact 的非常受歡迎的方式。
要快速使用 Vite 並執行,你可以使用我們的初始化器 create-preact
。這是一個互動式命令列介面 (CLI) 應用程式,可以在你機器上的終端機中執行。使用它,你可以透過執行以下指令來建立一個新的應用程式
npm init preact
這將引導你建立一個新的 Preact 應用程式,並提供一些選項,例如 TypeScript、路由(透過 preact-iso
)和 ESLint 支援。
提示:這些決定都不需要是最終的,如果你改變主意,你隨時可以將它們新增或從你的專案中移除。
準備好開發
現在我們準備好啟動我們的應用程式了。要啟動開發伺服器,請在你的新產生專案資料夾中執行以下指令
# Go into the generated project folder
cd my-preact-app
# Start a development server
npm run dev
伺服器啟動後,它會列印一個本機開發 URL,以便在你的瀏覽器中開啟。現在你準備好開始編寫你的應用程式了!
建立一個生產版本
總會遇到你需要在某處部署應用程式的時刻。Vite 附帶一個方便的 build
指令,它將產生一個高度最佳化的生產版本。
npm run build
完成後,您將有一個新的 dist/
資料夾,可以直接部署到伺服器。
如需所有可用指令及其選項的完整清單,請查看 Vite CLI 文件。
整合到現有管線
如果您已經設定現有的工具管線,很可能會包含一個打包器。最受歡迎的選擇有 webpack、rollup 或 parcel。Preact 可與所有這些工具順利搭配使用,無需進行重大變更!
設定 JSX
若要轉譯 JSX,您需要一個 Babel 外掛程式,將其轉換為有效的 JavaScript 程式碼。我們所有人都在使用 @babel/plugin-transform-react-jsx。安裝後,您需要指定應使用的 JSX 函式
{
"plugins": [
["@babel/plugin-transform-react-jsx", {
"pragma": "h",
"pragmaFrag": "Fragment",
}]
]
}
Babel 擁有目前最好的文件。我們強烈建議您查看有關 Babel 及其設定方式的問題。
將 React 別名設為 Preact
在某個時間點,您可能會想要利用廣大的 React 生態系統。最初為 React 編寫的函式庫和元件可與我們的相容性層無縫搭配使用。若要使用它,我們需要將所有 react
和 react-dom
匯入指向 Preact。此步驟稱為別名設定。
注意:如果您使用 Vite、Preact CLI 或 WMR,這些別名會在預設情況下自動為您處理。
在 Webpack 中設定別名
要在 Webpack 中設定任何套件別名,你需要在設定檔中新增 resolve.alias
區段。根據你使用的設定,這個區段可能已經存在,但缺少 Preact 的別名。
const config = {
//...snip
"resolve": {
"alias": {
"react": "preact/compat",
"react-dom/test-utils": "preact/test-utils",
"react-dom": "preact/compat", // Must be below test-utils
"react/jsx-runtime": "preact/jsx-runtime"
},
}
}
在 Node 中設定別名
在 Node 中執行時,套件管理工具別名(Webpack、Rollup 等)將無法運作,如 NextJS 所見。若要修正這個問題,我們可以在 package.json
中直接使用別名。
{
"dependencies": {
"react": "npm:@preact/compat",
"react-dom": "npm:@preact/compat",
}
}
在 Parcel 中設定別名
Parcel 使用標準的 package.json
檔案,在 alias
鍵下讀取設定選項。
{
"alias": {
"react": "preact/compat",
"react-dom/test-utils": "preact/test-utils",
"react-dom": "preact/compat",
"react/jsx-runtime": "preact/jsx-runtime"
},
}
在 Rollup 中設定別名
要在 Rollup 中設定別名,你需要安裝 @rollup/plugin-alias。這個外掛程式需要放在 @rollup/plugin-node-resolve 之前。
import alias from '@rollup/plugin-alias';
module.exports = {
plugins: [
alias({
entries: [
{ find: 'react', replacement: 'preact/compat' },
{ find: 'react-dom/test-utils', replacement: 'preact/test-utils' },
{ find: 'react-dom', replacement: 'preact/compat' },
{ find: 'react/jsx-runtime', replacement: 'preact/jsx-runtime' }
]
})
]
};
在 Jest 中設定別名
Jest 允許重新寫入模組路徑,類似於套件管理工具。這些重新寫入會在你的 Jest 設定檔中使用正規表示法設定。
{
"moduleNameMapper": {
"^react$": "preact/compat",
"^react-dom/test-utils$": "preact/test-utils",
"^react-dom$": "preact/compat",
"^react/jsx-runtime$": "preact/jsx-runtime"
}
}
在 TypeScript 中設定別名
TypeScript 即使與套件管理工具一起使用,也有自己的類型解析程序。為了確保使用 Preact 的類型取代 React 的類型,你會希望在 tsconfig.json
(或 jsconfig.json
)中新增下列設定:
{
"compilerOptions": {
...
"skipLibCheck": true,
"baseUrl": "./",
"paths": {
"react": ["./node_modules/preact/compat/"],
"react-dom": ["./node_modules/preact/compat/"]
}
}
}
此外,您可能需要啟用 skipLibCheck
,就像我們在上述範例中所做的一樣。某些 React 函式庫會使用 preact/compat
可能未提供的類型(儘管我們會盡力修正這些問題),因此,這些函式庫可能會導致 TypeScript 編譯錯誤。透過設定 skipLibCheck
,您可以告訴 TS 它不需要對所有 .d.ts
檔案執行完整檢查(通常這些檔案僅限於 node_modules
中的函式庫),這將修正這些錯誤。
搭配 HTM 和 ImportMaps 使用 Preact
Import Map 是一項較新的功能,可讓您控制瀏覽器如何解析模組指定項,通常用於將 preact
等基本指定項轉換為 CDN URL,例如 https://esm.sh/preact
。雖然許多人偏好 Import Maps 可提供的美學,但使用它們也有實際優點,例如更能控制模組解析(繼續閱讀以了解如何設定別名)以及解決從檔案複製 CDN URL 所帶來的負擔(以及可能的錯誤)。
以下為 Import Map 使用範例
<script type="importmap">
{
"imports": {
"preact": "https://esm.sh/preact@10.19.2",
"preact/": "https://esm.sh/preact@10.19.2/",
"htm/preact": "https://esm.sh/htm@3.1.1/preact?external=preact"
}
}
</script>
<script type="module">
import { render } from 'preact';
import { useReducer } from 'preact/hooks';
import { html } from 'htm/preact';
export function App() {
const [count, add] = useReducer((a, b) => a + b, 0);
return html`
<button onClick=${() => add(-1)}>Decrement</button>
<input readonly size="4" value=${count} />
<button onClick=${() => add(1)}>Increment</button>
`;
}
render(html`<${App} />`, document.body);
</script>
注意:我們在上述範例中使用
?external=preact
,因為許多 CDN 會貼心地提供您要求的模組及其相依項。然而,這可能會讓 Preact 出錯,因為它(以及 React)預期會以單例方式載入(一次只有一個執行個體)。使用?external
會告訴esm.sh
它不需要提供preact
的副本,我們可以使用 Import Map 自行處理
您甚至可以使用 Import Maps 來支援別名
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/preact@10.19.2/compat",
"react-dom": "https://esm.sh/preact@10.19.2/compat"
}
}
</script>