feat(deploy:lwc): Metadata API fallback for Tooling schema-ref bug#441
Conversation
Automatically retries an LWC bundle save through the Metadata API when the Tooling API rejects it with FIELD_INTEGRITY_EXCEPTION / "Invalid reference... of type sobjectField" (a known Salesforce bug on @salesforce/schema custom-field imports). The Tooling path is still attempted first.
|
Thanks for the thorough PR — the detection is appropriately narrow, the timeout path is safe, and the test coverage is solid. A few things I'd like addressed before merge: 1. Create-then-fallback drops When a bundle doesn't yet exist, This is a narrow case (brand-new bundle and schema-ref bug on the very first save) and the originally reported scenario in #434 (editing an existing bundle) is unaffected, since 2. In the single-file path, org resources are queried and their 4. No spinner feedback during the (multi-second) fallback The spinner keeps spinning through the Metadata deploy + polling but the text stays |
|
@msrivastav13 thanks for the review. I'll make these changes tonight. For point 1, for the new-bundle path, I'll put in a guard that detects the incompletle bundle and returns a message e.g. "Please re-run against the full bundle directory". This'll happen before the deploy. For point 2, the save will still fail, but we'll get a more useful Metadata API error instead of a TypeError from the JavaScript. For your last point, I personally would skip the spinner and leave this retry hidden from the user. Errors will still surface, but they'll be blind to the fact that we're retrying with the Metadata API. We can leave the debug breadcrumb for devs. Let me know if you feel differently. |
|
Yes sure |
Previously the fallback only covered Tooling resource update/create on an existing bundle. A first-time save of an LWC that imports a custom field hits the same schema-ref bug during LightningComponentBundle creation, which escaped to the outer catch with no fallback. createLWCBundle is now wrapped so a schema-ref bug re-reads the full bundle from disk (including js-meta.xml) and deploys via the Metadata API, which creates the bundle. Genuine create errors (e.g. LWC1503) still surface immediately. Create and update paths share a runMetadataFallback helper; metadataFallbackDeploy is unchanged. Confirmed E2E against a scratch org (API 66): the bug surfaces as AURA_COMPILE_ERROR (not FIELD_INTEGRITY_EXCEPTION), and the message regex distinguishes it from genuine compile errors that share the same errorCode. 50 unit tests passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@msrivastav13, I made additional changes beyond what we discussed. The previous work only addressed fallbacks for updates. The fallback now also covers bundle creation. While testing against a scratch org, I hit the gap you'd expect from the earlier discussion: a first-time save of an LWC importing a custom field fails the same way, but the error was thrown during LightningComponentBundle creation, so it surfaced the Tooling API error with no retry. Two findings from my testing drove the fix: The jsforce path surfaces the bug as AURA_COMPILE_ERROR, not the FIELD_INTEGRITY_EXCEPTION previously documented from raw REST. A genuine parse error (LWC1503) carries that same errorCode — so it's the message regex, not the code, that correctly tells them apart. Both cases are now pinned by unit tests. A failed Tooling bundle-create is atomic (no orphan shell), so no cleanup is needed. Implementation: createLWCBundle is wrapped so a schema-ref bug re-reads the full bundle from disk (incl. js-meta.xml) and deploys via the Metadata API, which creates the bundle; genuine errors still fail fast. Create/update now share one helper, and metadataFallbackDeploy is unchanged. Verified create + update end-to-end; 50 unit tests passing. |
msrivastav13
left a comment
There was a problem hiding this comment.
Thanks @jprichter — pulled the branch, built it, and ran the suite locally. tsc --noEmit clean, 57 passing, posttest clean. All three review points are addressed, and I confirmed the verifying tests:
- meta.xml on create-then-fallback — early bail with re-run guidance when
js-meta.xmlis absent, never builds an incomplete zip (test 4b). - null
Source— coalesced to'', noBuffer.from(null)TypeError (test 5b). - spinner — kept hidden per our discussion, debug breadcrumb retained.
Nice catch extending the fallback to bundle creation (test 4c), and the AURA_COMPILE_ERROR vs LWC1503 finding is a good one — agreed that the message regex, not the errorCode, is what correctly discriminates, and the regression guard pins that down.
Approving. 🚀
Closes #434
Summary
deploy:lwcfast-saves bundles via the Tooling API. A Tooling API Salesforce bug rejects any source importing a custom field via@salesforce/schema/withFIELD_INTEGRITY_EXCEPTION, even though the identical source deploys fine through the Metadata API.This PR makes
deploy:lwcautomatically retry through the Metadata API when a Toolingcreate/updatefails with that specific signature. The Tooling path is still attempted first; the fallback is transparent (spinner continues, normal success/failure shown).What changed
src/service/metadataDeployLwc.ts:isToolingSchemaRefBug(signature detection; genuine compile errors are not matched),buildLwcPackageXml, andmetadataFallbackDeploy(zips the bundle, deploys via Metadata API, polls to completion).src/commands/deploy/lwc.ts: the innercatchnow checks the predicate and delegates to the service; non-matching errors keep the original behavior.README.md: documents the fallback.Directory deploys zip the local files; single-file deploys query the rest of the
bundle from the org and overlay the changed file so only the single-file changes on the org. Resource paths are validated (
lwc/…, no..) before zipping.Testing
New unit tests in
test/commands/deploy/lwc.test.tscover detection, both fallback paths, both-fail messaging, timeout, path-safety, and the no-fallback regression guard.npm test→ 45 passing;npm run posttestclean.Additionally, you can test against this sample project by deploying it first using
sf project deploy startthen editingforce-app/main/default/lwc/ccdxSample/ccdxSample.jsand using this plugin to save.The save will fail againstmaster` and succeed against this branch.