基于 preact-cli 构建 Preact 应用并零配置部署到 Vercel:framework-boilerplates/preact 实战指南
【免费下载链接】examplesEnjoy our curated collection of examples and solutions. Use these patterns to build your own robust and scalable applications.项目地址: https://gitcode.com/GitHub_Trending/examples1/examples
本指南以仓库中的 framework-boilerplates/preact 为骨架,完整讲解一个 Preact 示例应用从本地开发、生产构建、单元测试到零配置部署到 Vercel 的完整链路。读完本文,你将掌握 preact-cli 脚手架的项目结构、preact-router 路由与代码分割、Jest + Enzyme 测试体系的组织方式,以及如何将同类项目一键部署到 Vercel。
项目概览:一个零配置可部署的 Preact 应用
正如 README 所描述的,这是一个可在 Vercel 上零配置部署的 Preact 示例应用。所谓"零配置",是指项目自带完整的脚手架配置(preact-cli、sirv-cli、jest-preset-preact、eslint-config-preact),开发者不需要在 Vercel 控制台额外配置构建命令或输出目录,导入仓库即可完成部署。
该示例同时是一个麻雀虽小五脏俱全的演示应用:包含基于preact-router的多页面路由、基于 Hooks 的交互逻辑(定时器、计数器)、PWA 相关的 manifest 与 Service Worker、以及一套 Jest + Enzyme 单元测试。以下从项目结构、本地命令、源码实现、测试体系和部署流程五个维度展开。
项目结构与工程化配置
目录结构
framework-boilerplates/preact/ ├── src/ │ ├── index.js # 应用入口 │ ├── components/ │ │ ├── app.js # 根组件,注册路由 │ │ └── header/ # 顶部导航组件(含 style.css) │ ├── routes/ │ │ ├── home/ # 首页路由组件(含 style.css) │ │ └── profile/ # 个人页路由组件(含 style.css) │ ├── assets/icons/ # PWA 图标资源 │ ├── style/index.css # 全局样式 │ ├── sw.js # Service Worker │ ├── manifest.json # PWA manifest │ └── template.html # HTML 模板 ├── tests/ │ ├── __mocks__/ # Jest 全局 mock 与 setup │ └── header.test.js # Header 组件测试 ├── package.json └── size-plugin.json # 构建体积统计入口与依赖
入口文件 src/index.js 只做两件事:导入全局样式./style,然后导出根组件App:
import './style'; import App from './components/app'; export default App;根组件 src/components/app.js 负责组装页面骨架并注册路由:
import { h } from 'preact'; import { Router } from 'preact-router'; import Header from './header'; // Code-splitting is automated for `routes` directory import Home from '../routes/home'; import Profile from '../routes/profile'; const App = () => ( <div id="app"> <Header /> <Router> <Home path="/" /> <Profile path="/profile/" user="me" /> <Profile path="/profile/:user" /> </Router> </div> ) export default App;注意源码中的注释Code-splitting is automated for 'routes' directory:这是 preact-cli 的一个关键工程化特性——routes目录下的组件会自动做按路由代码分割(code splitting),无需手动配置动态import()。这一点从 src/components/app.js 的注释可以直接印证。
依赖方面,package.json 中声明了三个运行时依赖:
preact(^10.15.0):核心框架,体积约 3KB 的 React 替代实现;preact-router(^4.1.1):哈希/历史路由库,本示例中负责/、/profile/、/profile/:user三条路由;preact-render-to-string(6.0.3):服务端渲染/字符串渲染工具,为 SSG/SSR 场景预留。
本地开发与构建命令详解
README 给出了完整的本地运行命令,结合 package.json 中的 scripts 可以逐条对照其底层实现:
# 安装依赖 npm install # 开发模式:热重载,监听 localhost:8080 npm run dev # 生产构建(压缩混淆) npm run build # 本地预览生产构建产物 npm run serve # 运行 Jest + Enzyme 单元测试 npm run testdev:preact watch
npm run dev实际执行preact watch(见 package.json)。preact-cli内置开发服务器,默认端口 8080,提供模块热替换(HMR),修改源码后浏览器即时刷新,无需手动重启。
build:preact build与 openssl 兼容开关
npm run build实际执行:
NODE_OPTIONS=--openssl-legacy-provider preact build这里有两个值得注意的细节:
preact build是生产构建命令,产物输出到build/目录,自动完成压缩(minification)、代码分割、资源指纹(fingerprinting)等优化;NODE_OPTIONS=--openssl-legacy-provider是 OpenSSL 兼容开关:由于preact-cli的 Webpack 4 依赖旧版 OpenSSL 算法(如 MD4 哈希),在较新的 Node.js 版本(17+)下必须启用 legacy provider 才能正常构建。这与 package.json 中声明的engines.node: "22.x"环境约束直接相关——在 Node 22 上构建本项目时,该开关是必需的。
构建产物可直接交给任意静态托管服务(如 Vercel、CDN)发布。
serve:sirv本地预览
npm run serve实际执行:
sirv build --port 8080 --cors --singleserve是构建完成后的验证步骤:sirv是一个轻量静态文件服务器,--port 8080指定端口,--cors开启跨域响应头,--single开启 SPA 单页模式(所有未匹配路径回退到index.html,保证preact-router的客户端路由在直接访问深链接时也能正常渲染)。注意serve预览的是build/产物,因此在执行前需要先运行npm run build。
lint 与 test:质量保障
package.json 中还包含两个质量命令(README 未列出,但同样可用):
npm run lint # 执行 eslint src npm run test # 执行 jestlint基于eslint-config-preact预设(见 package.json),并对build/目录做了 ignore 排除;test使用jest-preset-preact预设,并通过setupFiles加载 browserMocks.js 与 setupTests.js,为测试环境补齐浏览器 API 与 Enzyme 适配器。
路由与组件实现剖析
Header 导航组件
src/components/header/index.js 使用preact-router/match提供的Link组件渲染导航,并通过activeClassName在路由命中时自动添加激活样式:
import { h } from 'preact'; import { Link } from 'preact-router/match'; import style from './style.css'; const Header = () => ( <header class={style.header}> <h1>Preact App</h1> <nav> <Link activeClassName={style.active} href="/">Home</Link> <Link activeClassName={style.active} href="/profile">Me</Link> <Link activeClassName={style.active} href="/profile/john">John</Link> </nav> </header> ); export default Header;这里体现的是preact-router的两大能力:声明式链接(Link拦截点击并执行客户端导航)与激活态管理(activeClassName自动对比当前 URL)。
动态路由参数与 Hooks 交互
src/routes/profile/index.js 演示了动态路由参数 + Hooks 状态管理的组合用法:
import { h } from 'preact'; import {useEffect, useState} from "preact/hooks"; import style from './style.css'; // Note: `user` comes from the URL, courtesy of our router const Profile = ({ user }) => { const [time, setTime] = useState(Date.now()); const [count, setCount] = useState(10); useEffect(() => { let timer = setInterval(() => setTime(Date.now()), 1000); return () => clearInterval(timer); }, []); return ( <div class={style.profile}> <h1>Profile: {user}</h1> <p>This is the user profile for a user named { user }.</p> <div>Current time: {new Date(time).toLocaleString()}</div> <p> <button onClick={() => setCount((count) => count + 1)}>Click Me</button> {' '} Clicked {count} times. </p> </div> ); } export default Profile;注释user comes from the URL, courtesy of our router说明了关键机制:<Profile path="/profile/:user" />中的 URL 参数:user会作为 props 自动注入组件。在根组件 app.js 中,/profile/还通过user="me"提供了默认参数。
组件内部则示范了 Preact Hooks 的典型写法:
useState管理time与count两个状态;useEffect启动每秒一次的定时器更新当前时间,并在组件卸载时通过返回的清理函数clearInterval释放定时器(防止内存泄漏);- 点击按钮通过函数式更新
setCount((count) => count + 1)递增计数。
PWA 能力:模板、Manifest 与 Service Worker
HTML 模板
src/template.html 是 preact-cli 的 HTML 模板,使用<% preact.title %>、<% preact.headEnd %>、<% preact.bodyEnd %>三个占位符分别注入标题、head 尾部资源(如样式、manifest 链接)与 body 尾部脚本(如打包后的 JS)。同时声明了移动端相关的 meta 与apple-touch-icon:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title><% preact.title %></title> <meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes"> <link rel="apple-touch-icon" href="/assets/icons/apple-touch-icon.png"> <% preact.headEnd %> </head> <body> <% preact.bodyEnd %> </body> </html>Web App Manifest
src/manifest.json 提供了 PWA 安装所需的基础清单:应用名、start_url: "/"、display: "standalone"(独立窗口运行)、主题色#673ab8,并声明了 192x192 与 512x512 两档启动图标(位于 src/assets/icons)。这使应用具备被浏览器识别为可安装 Web App 的资格。
Service Worker
src/sw.js 借助 preact-cli 的 SW 工具函数,用三行代码完成离线缓存配置:
import { getFiles, setupPrecaching, setupRouting } from 'preact-cli/sw/'; setupRouting(); setupPrecaching(getFiles());setupRouting():为路由导航提供离线回退支持;getFiles():收集构建产物的文件清单;setupPrecaching(getFiles()):对全部构建产物做预缓存(precaching),使应用在二次访问时具备离线可用能力。
测试体系:Jest + Enzyme
测试采用 Jest 作为运行器、Enzyme 作为组件渲染与断言工具,配置集中在 package.json:
"jest": { "preset": "jest-preset-preact", "setupFiles": [ "<rootDir>/tests/__mocks__/browserMocks.js", "<rootDir>/tests/__mocks__/setupTests.js" ] }jest-preset-preact:官方预设,负责 JSX 转译(通过 Babel 将h()作为 JSX pragma)与 CSS 模块 mock;browserMocks.js:为 Node 测试环境补齐localStorage、matchMedia等浏览器 API;setupTests.js:用enzyme-adapter-preact-pure配置 Enzyme 适配器(见 tests/mocks/setupTests.js);fileMocks.js:将图片、字体等静态资源 mock 为字符串路径。
示例测试 tests/header.test.js 验证 Header 组件的渲染结果:
import { h } from 'preact'; import Header from '../src/components/header'; // See: https://github.com/preactjs/enzyme-adapter-preact-pure import { shallow } from 'enzyme'; describe('Initial Test of the Header', () => { test('Header renders 3 nav items', () => { const context = shallow(<Header />); expect(context.find('h1').text()).toBe('Preact App'); expect(context.find('Link').length).toBe(3); }); });该测试使用shallow浅渲染 Header,断言两点:h1文本为 "Preact App",且渲染出 3 个Link导航项(对应 Home、Me、John 三个链接)。这为后续修改导航结构提供了回归保障——新增或删除导航项时,运行npm run test即可发现断言失效。
部署到 Vercel:零配置一键发布
README 的 "Deploy Your Own" 部分说明了核心部署方式:
- 点击部署按钮(
Deploy with Vercel),进入 Vercel 的 New Project 流程,系统会直接以本仓库framework-boilerplates/preact目录为模板创建一个新项目; - Vercel 会自动检测项目类型并采用 Preact 模板的默认配置:构建命令为
npm run build,输出目录为build/,无需任何手工配置; - 部署完成后即获得一个可访问的线上地址,此后每次推送代码到仓库,Vercel 会自动触发重新构建与发布。
这正是"零配置"的含义所在:项目的 package.json 已经完整声明了构建脚本、运行环境(engines.node: "22.x")与静态产物目录,Vercel 的框架预设可以直接读取这些约定完成部署,开发者只需关心业务代码本身。
将本模板迁移到自有项目的要点
如果你打算以该示例为基础搭建自己的 Preact 应用,可以按以下顺序操作:
- 复制工程骨架:保留
src/、tests/、package.json、size-plugin.json等文件,替换src/assets/icons/下的图标为自有资源; - 调整 PWA 元信息:修改 src/manifest.json 中的应用名、主题色,以及 src/template.html 中的标题与描述;
- 扩展路由:在 src/routes/ 下新增目录,并在 src/components/app.js 的
<Router>中注册对应 path,代码分割由 preact-cli 自动完成; - 沿用开发链路:本地用
npm run dev开发、npm run build && npm run serve验证生产产物、npm run test跑回归、npm run lint检查代码风格; - 部署:推送到 Git 仓库后在 Vercel 导入项目,或直接使用 Deploy 按钮创建新项目,均无需额外配置。
小结
通过本示例可以清晰看到 Preact 应用在 Vercel 生态中的完整工程范式:preact-cli承担构建与开发服务器,preact-router解决客户端路由与按路由代码分割,preact/hooks提供状态与副作用管理,jest-preset-preact+ Enzyme 构成测试闭环,而manifest.json与sw.js则赋予了 PWA 安装与离线能力。这套结构既是可运行的演示,也是可直接复用的生产级工程模板——从本地npm install到线上零配置部署,全程无需任何平台定制。
【免费下载链接】examplesEnjoy our curated collection of examples and solutions. Use these patterns to build your own robust and scalable applications.项目地址: https://gitcode.com/GitHub_Trending/examples1/examples
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考