【免费下载链接】porsche-design-system
The official Porsche Design System repository, offering fundamental UXI guidelines and a library of reusable web components to enable designers and developers to build consistent, intuitive, and high-quality digital products that reflect the Porsche brand.
Porsche Design System 是保时捷官方的开源设计系统,它基于 Stencil 框架开发了一套标准的 Web Components(Web 组件),让设计师和开发者能在任意前端框架中构建风格一致、体验统一的数字产品。本文带你深入浅出地看懂这些核心 Web 组件背后的代码实现原理——不用啃完整个仓库,只需 10 分钟。
一、先认识项目:一套组件,多种框架共用
Porsche Design System 的核心理念是"一次编写,处处使用":
- 组件以 原生 HTML 标签 的形式存在,比如
<p-button>、<p-select>、<p-modal>,前缀统一为p- - 通过 Web Components 标准(Custom Elements + Shadow DOM),不依赖 React、Vue 或 Angular 也能独立运行
- 再为三大框架生成对应的 Wrapper 包装层,让组件拥有完整的类型提示和框架生态体验
这张架构图(来自 pds-architecture.png)揭示了它的分发模型:所有组件资产(core 和 component chunks、字体、图标)托管在 CDN 上,各框架包只需调用 components-manager-cli 中的 load() 注册前缀并加载 core 块,组件即可按需注入页面。
二、为什么选择 Stencil?
Stencil 是一个将 TypeScript + JSX 编译为原生 Web Components 的编译工具链。Porsche Design System 选择它,正是看中三点能力:
| Stencil 能力 | 在 PDS 中的用途 |
|---|---|
| 编译原生 Custom Element | <p-button> 等组件无需运行时框架 |
| 声明式生命周期钩子 | componentWillLoad、componentDidLoad 管理表单状态 |
按 bundles 自动分包 | 组件拆成多个 chunk,随 CDN 按需加载 |
全局的构建配置非常精炼,集中在 stencil.config.ts 中,关键选项包括:
namespace: 'porsche-design-system':构建产物的命名空间bundles:引入自 bundles.ts,定义哪些组件打进同一个 chunkglobalScript: 'src/setup.ts':页面加载后最先执行的初始化脚本rollupPlugins:构建时把版本号、CDN 地址等占位符替换为真实值
三、解剖一个组件:以 p-button 为例 🧩
每个组件都遵循统一的文件结构(详见 AGENTS.md):
src/components/button/
├── button.tsx # Stencil 组件主体
├── button-styles.ts # JSS 样式定义
├── button-utils.ts # 工具函数
└── button.spec.ts # 单元测试
以 button.tsx 为例,一个组件的实现由几块"乐高积木"拼成:
1. 装饰器声明(button.tsx#L44-L48)
@Component({
tag: 'p-button',
shadow: { delegatesFocus: true },
formAssociated: true,
})
tag:注册原生标签名shadow:启用 Shadow DOM 隔离样式,delegatesFocus让焦点能透传给内部元素formAssociated:让组件参与 HTML 表单校验,这是现代表单组件的关键特性
2. Props 即属性:用 @Prop() 声明,如 variant(primary/secondary/destructive)、loading、compact。加 reflect: true 的 Prop 会同步回 HTML 属性,方便 React Wrapper 等框架读取。
3. 生命周期管理状态:componentWillLoad 中设置表单值,componentDidLoad 中增强按钮行为,@Watch('value') 监听属性变化实时同步到表单。
4. render() 返回 JSX:Shadow DOM 内部渲染原生 <button>,再用 <slot /> 把用户传入的按钮文案"投射"进来——这就是 Web Components 的 Slots 插槽 机制,让用户可以在标签内容中自定义文案。
样式方面,PDS 采用 JSS(JavaScript 样式对象)而非 CSS 文件,并通过 applyConstructableStylesheetStyle.ts 利用 Constructable Stylesheets API 把样式一次性注入 Shadow Root,避免重复注入、提升渲染性能。
四、分包与按需加载:bundles 的巧妙设计 🔍
一个按钮只需要几 KB,但整个设计系统有上百个组件。如果全部加载,性能不可接受。
PDS 的解法在 bundles.ts 中:它声明了必须绑在同一 chunk 的组件组,例如:
p-table家族(p-table-body、p-table-row等 7 个标签)p-select+p-select-optionp-tabs+p-tabs-item
规则很直观:父组件先列出(决定 chunk 命名),子组件不可脱离父组件单独使用。这样用户只用 <p-button> 时,p-table 的代码一行都不会下载。结合 CDN 分发(见 docs/bundling.md 的分包策略),实现了真正的按需加载。
五、SSR 与 Declarative Shadow Root:首屏不闪烁的关键
服务端渲染(SSR)时,浏览器拿到的是"已渲染好"的组件。Stencil 的解法是 Declarative Shadow Root(DSR):服务端直接输出 <template shadowrootmode="open"> 结构,浏览器无需等待 JS 执行即可显示完整组件。
- DSR 模板由 generateDSRComponents.ts 自动生成
- 客户端 hydrate 时的细节处理见 stencil.config.ts 中的
invisiblePrehydration: false注释 - 页面何时"全部组件就绪"?由 components-ready.ts 导出的
componentsReady()提供 Promise 接口,它会遍历 DOM 收集所有组件的componentOnReady()并统一等待,业务代码只需await一个 Promise 即可安全操作组件
六、给 Stencil 打"针":三个补丁的实战意义 💉
开源框架很少能 100% 满足所有需求。PDS 团队用 patch-package 给 Stencil 定制了补丁,文件位于 patches/@stencil+core+4.45.1.patch,背景与更新方法完整记录在 docs/stencil-patch.md。三个补丁分别解决:
| 补丁 | 解决的问题 |
|---|---|
| attachInternals | 在不支持 ElementInternals API 的旧浏览器中避免报错 |
| SSR patch | 客户端重渲染前清空服务端已渲染的 shadowRoot,防止内容重复 |
| clonable shadow root | 让 cloneNode(true) 能复制 shadow root 内容,修复 AG Grid 列宽自动计算等工具链问题 |
这是一个很好的参考实践:当核心框架行为不合预期时,小而聚焦的补丁 + 详细文档,比 fork 整个框架更可维护。
七、框架 Wrapper:同一份组件,三种体验
组件的核心逻辑只写一遍(packages/components/),然后由 generateWrappers.ts 脚本自动生成 React、Vue、Angular 三套包装层:
- React Wrapper:projects/react-wrapper/,通过 props 同步到 element ref
- Vue Wrapper:projects/vue-wrapper/
- Angular Wrapper:projects/angular-wrapper/
由于生成器是模板化的,新增一个 Stencil 组件后,三套框架包装自动跟上——这就是"单一事实来源"带来的巨大维护优势。
八、阅读源码路线图 🗺️
想深入探索?建议按这个顺序阅读:
- stencil.config.ts — 构建入口,理解全局配置
- button.tsx — 最典型的完整组件
- bundles.ts — 分包规则
- docs/stencil-patch.md — 框架定制的思维方式
- packages/components/AGENTS.md — 团队内部的组件开发规范(无障碍、焦点样式、高对比模式要求一应俱全)
总结
Porsche Design System 的 Web 组件实现可以浓缩为 6 个关键词:Stencil 编译、Shadow DOM 隔离、Slots 投射、bundles 分包、DSR 服务端渲染、补丁定制。它用 Web Components 标准实现了框架无关,又用自动化生成抹平了各框架的差异——这正是企业级设计系统值得学习的地方。
如果你想在自己的项目中实践类似思路,不妨从"选一个组件,从它的 .tsx 读起"开始。
【免费下载链接】porsche-design-system
The official Porsche Design System repository, offering fundamental UXI guidelines and a library of reusable web components to enable designers and developers to build consistent, intuitive, and high-quality digital products that reflect the Porsche brand.
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考






