example: add cross-package SharedTree schema consumption example #26522
example: add cross-package SharedTree schema consumption example #26522WillieHabi wants to merge 23 commits intomicrosoft:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new examples/utils/cross-package-schema two-package example intended to demonstrate consuming SharedTree objectAlpha() schemas across package boundaries by using TypeScript customConditions: ["source"] and a "source" export condition to bypass problematic .d.ts path normalization under TS 5.9 + moduleResolution: "bundler".
Changes:
- Add a new
schema-providerpackage exporting SharedTree schema classes with a"source"export condition and a TS 5.9 “bundler” build mode to reproduce the.d.tsissue. - Add a new
schema-consumerpackage that imports the provider’s schemas and demonstrates success/failure with and withoutcustomConditions: ["source"]. - Add documentation and lockfile updates to wire the new example packages into the repo.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Adds new workspace importers for the provider/consumer example packages and updates a dependency resolution entry. |
| examples/utils/cross-package-schema/README.md | Documents the problem, the "source"-condition workaround, and verification steps. |
| examples/utils/cross-package-schema/schema-provider/package.json | Defines the provider package exports (including "source"), build scripts, and dependencies. |
| examples/utils/cross-package-schema/schema-provider/tsconfig.json | Provider baseline TS config for Node16 resolution output to lib. |
| examples/utils/cross-package-schema/schema-provider/tsconfig.bundler.json | Provider TS 5.9+ bundler-resolution config to reproduce .d.ts normalization. |
| examples/utils/cross-package-schema/schema-provider/src/schema.ts | Declares a small set of objectAlpha()-based schema classes to export. |
| examples/utils/cross-package-schema/schema-provider/src/index.ts | Re-exports the provider schema classes as the public entrypoint. |
| examples/utils/cross-package-schema/schema-provider/eslint.config.mts | Adds local ESLint flat-config wiring consistent with other examples. |
| examples/utils/cross-package-schema/schema-consumer/package.json | Defines the consumer package scripts for the “with source condition” pass and “without source condition” failure demonstration. |
| examples/utils/cross-package-schema/schema-consumer/tsconfig.json | Enables customConditions: ["source"] for the success-path typecheck. |
| examples/utils/cross-package-schema/schema-consumer/tsconfig.no-source.json | Consumer TS config variant that omits customConditions to reproduce the failure. |
| examples/utils/cross-package-schema/schema-consumer/src/consume.ts | Imports provider schemas and constructs a TreeViewConfiguration to validate compatibility. |
| examples/utils/cross-package-schema/schema-consumer/src/index.ts | Re-exports the consumer example entrypoint/types. |
| examples/utils/cross-package-schema/schema-consumer/eslint.config.mts | Adds local ESLint flat-config wiring consistent with other examples. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
examples/utils/cross-package-schema/schema-consumer/src/consume.ts
Outdated
Show resolved
Hide resolved
examples/utils/cross-package-schema/schema-provider/package.json
Outdated
Show resolved
Hide resolved
examples/utils/cross-package-schema/schema-consumer/package.json
Outdated
Show resolved
Hide resolved
relying on tree exports being setup for normal consumption patterns - no special setup to share schema across packages
Stage tree entrypoint files such that none reference index.js directly that may result in consumer packages generating .d.ts files with incorrect tree imports. tree entrypoints are no longer generated during build. Changes for exposed API surface require updating files under src/entrypoints, which may use ` generate:entrypoint-sources` script. Update entrypoint linting to use new sources, but keep them from being formatted or linted. Until 0.64 build-tools are used, legacy.d.ts Node10 file won't be generated and is temporarily checked in.
Stage tree entrypoint files such that none reference index.js directly that may result in consumer packages generating .d.ts files with incorrect tree imports. tree entrypoints are no longer generated during build. Changes for exposed API surface require updating files under src/entrypoints, which may use ` generate:entrypoint-sources` script. Update entrypoint linting to use new sources, but keep them from being formatted or linted. Until 0.64 build-tools are used, legacy.d.ts Node10 file won't be generated and is temporarily checked in.
This reverts commit 292b58b.
…nto cross-package-schema
cb3ee9f to
703cb3f
Compare
Tree's generate:entrypoint-sources script produces files that overlap with tsc output, causing policy check failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This reverts commit a989191.
into a bash script that policy checker doesn't understand.
jason-ha
left a comment
There was a problem hiding this comment.
Looks pretty good - you'll obviously need another review since I have decent contributions in here.
Do update the PR title and description.
Apologies if this posts with seemingly irrelevant comments. I apparently never submitted notes I had from last week. I tried to cleanup things that I could see to be accurate.
| "types": "./src/index.ts", | ||
| "default": "./lib/index.js" |
There was a problem hiding this comment.
Should only support "import" condition - like is used in ".".
examples/utils/cross-package-schema/schema-provider/tsconfig.bundler.json
Outdated
Show resolved
Hide resolved
| "compilerOptions": { | ||
| "rootDir": "./src", | ||
| "outDir": "./lib", | ||
| "exactOptionalPropertyTypes": false, |
There was a problem hiding this comment.
Do you need this? We prefer to not have this setting when possible.
I think you do - should comment on the need.
| ## The Problem | ||
|
|
||
| When SharedTree schema classes are defined using `objectAlpha()` and compiled with | ||
| TypeScript 5.9+ using `moduleResolution: "bundler"`, the `.d.ts` emitter normalizes import |
There was a problem hiding this comment.
Is using bundler resolution a part of the problem? I didn't think that was part of the issue. The only issue as I understood it was working with generated .d.ts files.
There was a problem hiding this comment.
Whoa. I'm reading step 1 below. That suggests bundler is part of the problem. So, the solution is maybe is don't use bundler resolution for your schema package? (office-bohemia doesn't require bundler resolution. It is largely used because it has relaxed rules. But should be easy to build schema package with node16 resolution.)
| }, | ||
| "scripts": { |
There was a problem hiding this comment.
For completeness, there should be a "files" block in here. "files" says what files are actually part of a published package. See presence package for an example. In this case, we want to call out src explicitly as some or all of it is needed. (Even if there aren't test files, I would exclude those paths to set a good example.)
The above is an old comment that was never apparently published. It matters more and less now that we don't need to publish src. More because a proper package wouldn't have to publish them. Less because this is super simple now.
biome.jsonc
Outdated
| "!**/src/**/test/types/**/*.generated.ts", | ||
| "!**/src/packageVersion.ts", | ||
| "!**/src/layerGenerationState.ts", | ||
| "!**/src/entrypoints/*.ts", |
There was a problem hiding this comment.
We do not want a broad disable of src/entrypoints from biome. The disable in tree should be temporary. If the package level biome config is a problem, then make this "absolute" just for tree with a comment.
| minimatch: 10.1.1 | ||
| minimatch: 10.2.1 |
There was a problem hiding this comment.
okay, I think, but rogue unrelated change
| // Need to skip lib check since some .d.ts from provider are invalid. | ||
| "skipLibCheck": true, |
There was a problem hiding this comment.
No longer the case. All builds should be good.
Do borrow liberally from jason-ha@4c04950 description. I am not planning on submitting those separately as we want to have tests in place. You get the credit. :) |
|
If possible, do testing of stuff like this in the Realistically I believe what you want to test is d.ts generation and consumption, which can be done with two ts projects in a single package, which is how import-testing is setup. This approach should be able to test what we need, as well as serve as examples of how to do it, while not requiring extra packages. Note that this package already has tests/example for a lot of schema related APIs. |
| */ | ||
|
|
||
| /* | ||
| * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. |
There was a problem hiding this comment.
I'd prefer we don't commit auto generated files, and instead have them produces as part of the build, unless it is intended for human auditing like API reports. As we already have an API report for these, I don't think we want this as well for the same purpose.
There was a problem hiding this comment.
This is exactly the plan. The API report files give us one thing, but they don't tell us what is exactly happening and we can miss things.
InternalTypes is an example of that. Our current "generate entrypoints" actually emits and error for InternalTypes but you don't see it when run as part of the task infrastructure - run it on its own to see. You can also look at the current lib/public.d.ts to see the funkiness.
In the future (see AB#14504), we'll be able to review API surface changes more easily (easier to understand) than with API reports. (Though we'll likely keep one API report to keep track of documented/undocumented and tags.)
In some cases, we may want to temporarily or permanently handcraft parts of the entrypoint files.
This result is not exactly what we want, but it is sufficient.
I think testing can be relocated. I don't know that need (see below) to bother with two ts projects, though I know you can test that way as one form of setup in my personal iterations had observed that. I do know that these cases need to be isolated. I observed too many things that would avoid recreating the issue. Maybe separate project is the best to help ensure that. I don't think it is bad to have a clear example of practical use. Multiple ts projects does complicate the build a bit and is a lot less obvious. I'm okay with this or rolled into |
|
@WillieHabi, to fix the build break probably should apply this diff to fluidBuild.config.cjs: - "build:api-reports:current": ["api-extractor:esnext"],
- "build:api-reports:legacy": ["api-extractor:esnext"],
- "ci:build:api-reports:current": ["api-extractor:esnext"],
- "ci:build:api-reports:legacy": ["api-extractor:esnext"],
+ // Depend on "build:esnext" in case there is no "api-extractor:esnext".
+ "build:api-reports:current": ["api-extractor:esnext", "build:esnext"],
+ "build:api-reports:legacy": ["api-extractor:esnext", "build:esnext"],
+ "ci:build:api-reports:current": ["api-extractor:esnext", "build:esnext"],
+ "ci:build:api-reports:legacy": ["api-extractor:esnext", "build:esnext"], |
|
🔗 No broken links found! ✅ Your attention to detail is admirable. linkcheck output |
Description
Adds a minimal two-package example (schema-provider + schema-consumer) demonstrating cross-package consumption of SharedTree schemas defined with objectAlpha().
Also merges the tree entrypoint fix from jason-ha@4c04950, which restructures @fluidframework/tree's package.json exports so each API tier (., ./alpha, ./beta, etc.) has its own JS entrypoint.
With this fix, the example consumer imports schemas through standard imports with no workarounds needed.