学习目标
完成本单元后,你将能够:
- 描述企业客户如何使用 unlocked packages。
- 描述包开发与 change set 开发的不同。
- 描述如何使用包来部署元数据。
为什么包开发是未来
如果你完成了 Package Development Model 模块,就知道模块化、基于包的开发是游戏规则的改变者。你可能在想:如何把这些原则付诸实践?
无论你是平台新手还是老手,打包都适合你。作为长期客户,你在平台上定制和构建得越多,org 中的复杂度就越高——你的单一 Salesforce org 成了所有元数据的巨大容器,我们称之为「happy soup(快乐汤)」。如果你最近推出过 Salesforce 定制,你是用 change set 甚至非托管包把元数据部署到生产 org 的,这种传统开发模式就是 change set 开发,其「事实来源」是生产 org。
但在包开发模型中,新的「事实来源」是版本控制系统。你用 Salesforce DX 项目把源代码组织到包目录中,最终目标是用这些目录创建可版本化、易维护、易更新、易安装、易升级的包。转向包开发不是「全有或全无」的选择,你可以从小处着手、逐步采纳。
什么是包?
如果你刚接触打包,可以把包(package)想象成一个装满元数据的容器,是可分发的功能单元。
想象你为员工构建了一个费用追踪应用,包含自定义对象、Apex 类、Lightning 组件等。在 change set 模型中,这些元数据都在 org 里,但并未以易升级维护的方式隔离组织。在包开发模型中,你把元数据组织到定义清晰的容器——即包中。最令人信服的理由归结为:组织你的元数据。没有包,元数据会变得难以驾驭。
Unlocked Packages 来救援
Salesforce 提供几种不同类型的包。我们先使用一种特别的包类型——unlocked package,特别适合内部业务应用。
Unlocked packages 让你以可追踪的方式在 org 中添加、编辑、删除元数据,从而更轻松快速地复用组件、升级应用。为追踪变化,你需要创建包的版本(version)——每个版本都是不可变产物(immutable artifact),是包内容的快照。在生产 org 中,你可以检查哪些元数据来自哪个包版本。
不再用电子表格追踪元数据变化,不再用便签!
什么是 Unlocked Package?
Unlocked package 给了你很大的灵活性:
- 灵活性:管理员可以响应紧急变更请求直接在生产 org 中修改,因为 unlocked package 中的元数据可在生产 org 中修改。
- 责任:unlocked packages 是开发者控制的——安装任何新包版本都会覆盖直接在生产 org 中所做的更改。关键是管理员必须把生产中的直接更改告知开发团队,以便相应地更新包。
你能往 unlocked package 里放什么?好消息——几乎所有类型的 Salesforce 元数据和组件都可以。Metadata Coverage 报告是各渠道元数据覆盖信息的权威来源,见 developer.salesforce.com/docs/metadata-coverage。
如何开始?
采用 Salesforce DX 工具和开发原则不是「全有或全无」的事。你可以小步走,也可以直接跳进深水区。
- 如果你刚接触 Salesforce 或开始新项目,可以从一开始就遵循包开发模型。
- 如果你有大量未区分的源代码,可以逐步采纳打包,开始把元数据切分到逻辑容器中。
你可以先从打包可复用的组件和 schema 开始,时机成熟时再定义包之间的依赖。速度多快、复杂度多高,由你决定——这就是 unlocked packages 的威力。
用 Salesforce DX 进行包开发
看看打包工作流(假设你是唯一的开发者兼发布经理,另一位同事负责 QA):
- 开发:创建一个与 DX 项目中目录关联的包,修改元数据,用 scratch org 开发和单元测试。
- 构建与测试:创建包版本,QA 安装测试,修复 bug、加功能,再创建新版本——迭代。
- 发布:把好版本安装到沙箱做用户验收测试(UAT),最终安装到生产。
安装包版本类似于部署元数据,可安装到任何 org(scratch org、沙箱、生产)。这就是包开发模型的基本应用生命周期。
发布第一个包之后
软件开发的脚步从不停歇,下一个版本很快就到。你可以在添加、修改、删除包元数据时创建所需的新版本。每个包版本都有版本号(如 1.3.0.2),用包升级(package upgrade)把更改应用到已安装的版本上。
「修改元数据 → 创建包版本 → 测试包版本 → 部署到生产」这个过程可以无限重复。准备好试试了吗?来构建你的第一个 unlocked package。
构建你的第一个 Unlocked Package
本单元动手实践:配置环境、克隆 DreamHouse LWC 源代码、配置并创建 unlocked package、在 scratch org 中测试、安装到 Trailhead Playground。
学习目标
完成本单元后,你将能够:
- 熟悉打包的 CLI 命令。
- 描述基本的打包用例。
- 打包 DreamHouse LWC 示例应用并安装到 Trailhead Playground。
为什么我们爱包开发
包开发遵循软件开发生命周期的最佳实践,与 Salesforce DX 的项目、CLI 命令和 scratch org 兼容;把生命周期阶段间的所有变更封装到版本化产物中;更易接纳新功能请求;提供更好的审计历史;组织源代码;促进迭代和模块化开发;支持包间依赖;支持持续集成和持续交付。
典型用例:财务部的费用报销应用、HR 的推荐(Referral)应用——任何内部业务应用都适合用 unlocked packages 交付。每个应用都从全新项目开始,源代码以 source format 存于 DX 项目并提交到版本控制,交付时创建 unlocked package,在 scratch org 或沙箱测试后安装到生产。
配置环境
- 创建新的 Trailhead Playground(全新 org)。
- 在 Setup 中启用 Dev Hub。
- 启用 Unlocked Packages and Second-Generation Managed Packages。
- 创建 GitHub 账号(如没有)。
- 安装 Salesforce CLI。
全新 playground 确保干净环境;Dev Hub 是创建包的必要条件;CLI 提供打包命令。
获取 DreamHouse 源代码
以 DreamHouse LWC 应用为例(一个使用 Lightning Web Components、Apex 等的独立房地产应用)。在命令行中切到想放源代码的目录,运行:
git clone https://github.com/trailheadapps/dreamhouse-lwc
git clone 命令用 Salesforce DX 项目结构创建 dreamhouse-lwc 文件夹,包含 DX 项目文件和 scratch org 定义文件。一个 DX 项目可以有多个包,通过目录结构隔离不同包,在合适处共享组件。
配置你的包
- 授权 Dev Hub org 并登录:
sf org login web --set-default-dev-hub --alias DevHub
- 确认 Dev Hub 已连接:
sf org list
- 切到 dreamhouse-lwc 目录。
- 打开 sfdx-project.json,记下 sourceApiVersion,然后用干净配置替换:
{ "packageDirectories": [ { "path": "force-app", "default": true } ], "namespace": "", "sfdcLoginUrl": "https://login.salesforce.com", "sourceApiVersion": "61.0" } - 确保 sourceApiVersion 与原文件一致,否则更新。
为什么不用命名空间?
包命名空间对 unlocked packages 是可选的。包含命名空间有助于组织包组件,但需要额外的设置和规划,所以本单元跳过。
重要:如果你正把元数据从 happy soup 迁移到 unlocked package,请创建不带命名空间的 unlocked packages——这样元数据从未打包状态移到 unlocked package 时,元数据元素的 API 名称不会改变,无需重命名。
创建包
克隆 DreamHouse 后,从 dreamhouse-lwc 目录创建无命名空间的 unlocked package:
sf package create --name dreamhouse --description "My Package" --package-type Unlocked --path force-app --no-namespace --target-dev-hub DevHub
参数说明:--name 是包名(别名,供后续命令使用);--path 是包含包内容的目录;--package-type 指定包类型(unlocked)。
打开 sfdx-project.json,packageDirectories 里会看到包名和版本占位符,命令还创建了 packageAliases 段,把包名(别名)映射到包 ID(0Ho)。若忘了别名,运行 sf package list 列出 Dev Hub 关联的所有包。
创建 Scratch Org 测试
创建一个 scratch org(别名 MyScratchOrg)来安装 unlocked package。测试用的 scratch org 是执行打包开发生命周期单元测试阶段的便捷方式。该命令用默认 scratch org 定义文件,创建与 Trailhead Playground 同版本的 Developer Edition scratch org,时长 30 天。
sf org create scratch --definition-file config/project-scratch-def.json --alias MyScratchOrg --duration-days 30
创建包版本并安装
准备发布时,创建包的快照——包版本(package version)。先更新 sfdx-project.json 的 versionName 为 Version 1.0、versionNumber 为 1.0.0.NEXT,然后在 dreamhouse-lwc 目录创建包版本:
sf package version create --package dreamhouse --installation-key test1234 --wait 10 --target-dev-hub DevHub
创建完成后,packageAliases 段会新增条目 "dreamhouse@1.0.0-1": "04txxx"。用版本别名安装到 scratch org:
sf package install --wait 10 --publish-wait 10 --package dreamhouse@1.0.0-1 --installation-key test1234 --no-prompt --target-org MyScratchOrg
安装完成后打开 scratch org 验证:sf org open --target-org MyScratchOrg,再到 Setup → Installed Packages 查看。unlocked package 中的 Apex 代码必须满足最低 75% 代码覆盖率才能安装到生产 org(本例 DreamHouse 示例仓库覆盖率不足,故未计算)。
发布并安装包版本
包刚创建时是 beta 状态,不能安装到生产 org。当版本准备好发布时,可以把它提升(promote)为 released:
sf package version promote --package dreamhouse@1.0.0-1
(需要满足 75% 代码覆盖率,DreamHouse 示例可能不满足,所以我们跳过提升,继续用 beta 版本。)
最后安装到 Trailhead Playground:
- 把 playground 加入授权 org 列表:
sf org login web --alias MyTP
- 安装包版本:
sf package install --wait 10 --publish-wait 10 --package dreamhouse@1.0.0-1 --installation-key test1234 --no-prompt --target-org MyTP
- 打开 playground:
sf org open --target-org MyTP
- Setup → Installed Packages 查看,点击 dreamhouse → View Components,再从 App Launcher 打开 DreamHouse 应用。
组织你的元数据
本单元学习把未打包元数据组织到包中的策略、三种拆解模型,以及包依赖的处理方式。
学习目标
完成本单元后,你将能够:
- 列出把未打包元数据组织到包中的关键策略。
- 识别 unlocked packages 如何相互依赖。
- 描述 3 种包开发模型及各自适用场景。
把包开发原则付诸实践
把元数据组织到包中往往是个迭代过程,不是「全有或全无」。通过打包 DreamHouse,我们展示了:把 CLI、项目和 unlocked packages 集成到应用生命周期;采纳组织元数据和创建包边界的最佳实践;在构建新应用时使用 unlocked packages。
现在你可以:独立测试和部署应用源代码、把应用 schema 与其他元数据隔离、通过重复流程添加新功能、为应用版本化、把新版本作为升级安装到现有版本。
为新建或现有应用组织元数据
DreamHouse 的元数据按类型组织:
- Schema:自定义对象(Broker__c、Property__c、Favorite__c)。
- Lightning 应用和组件:Property Explorer、Property Record Page。
- 流程(Flows):新房源通知、价格变动推送。
- Einstein 服务:上传图片的图像处理。
- Bots:通过 Facebook Messenger、Slack、Alexa 搜索房源。
一个 unlocked package 包含所有这些元数据,作为一个可部署、可版本化的单元。包边界就是应用边界——自包含、完整、可独立部署。
拆分 org 现有元数据
对用了多年 change set 开发的现有客户来说,怎么解开 happy soup?没有唯一的处方——一半是科学、一半是艺术,你才是判断哪些元数据属于哪些 DX 项目的最佳人选。
开始先回答这些问题:开发团队能否独立发布应用/新功能/定制?能否识别代表某个应用的元数据?能否把元数据组织成不同功能的模块?创建非托管包时看到了哪些依赖?
如果 org 里有多个应用和定制,预计会看到 DX 项目之间的一些依赖——这是正常的,也是 unlocked packages 依赖管理的意义所在。
拆解元数据的三种模型
实际场景中,你可能会组合使用这些策略并按业务需求调整:
- 基于应用(App-based):识别代表某个应用的元数据,类似 DreamHouse 的做法,但元数据已存在于 org 中。
- 基于定制(Customizations-based):组织生产 org 中对标准对象的定制和功能变更,如对 Sales Cloud、Service Cloud 或 AgentExchange 应用的定制。
- 共享库(Shared library):存在相互依赖时,用一个公共 DX 包组织一组 Apex 类或常用自定义对象,其他包依赖这个公共包。
用非托管包作为起点
把未托管元数据组织到多个包的一个好起点工作流:
- 从生产 org 选一小部分自包含的未打包元数据。
- 创建非托管包隔离这些元数据,观察系统自动拉入了哪些依赖元数据(帮你发现隐藏依赖)。
- 用
sf project retrieve start从非托管包检索源代码。 - 建立 Salesforce DX 项目和 git 仓库管理包元数据。
- 用
sf project deploy start推到 scratch org,验证元数据。 - 用
--no-namespace标志创建 unlocked package。 - 测试并部署 unlocked package。
- 通过所有 CI 和沙箱 UAT 后,提升包版本。
- 在生产 org 安装 unlocked package。
一旦为该元数据创建包,它就会自动移入包中,并覆盖 org 中已有元数据、更新内部引用。
关于包依赖
Unlocked packages 支持丰富的依赖链:
- Unlocked → AgentExchange 包:你对某个 AgentExchange 包的定制可放在 unlocked package 中,安装时 AgentExchange 包必须已存在。
- Unlocked → Unlocked:例如费用报销包与现有 Payroll 包共享后端集成,费用报销包依赖 Payroll 包。
- 多层依赖:包 A → 包 B → 包 C,支持多级依赖。
依赖在 sfdx-project.json 的 packageDirectories 段中表达。如果拆分 org 元数据非常困难,可以考虑 org-dependent unlocked packages——允许包依赖安装 org 中未打包的元数据。


























