feat(migrate): cover the remaining v9 breaking changes - #31355
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
codeCraft-Ritik
left a comment
There was a problem hiding this comment.
Really thorough PR, @ShaneK. A few things I appreciated while going through this:
The vanilla app gap fix — detectFrameworks() excluding core meant every framework: 'core' migration was dead code for the apps it was written for. Adding @ionic/core to the detection map and introducing sourceMajor() is the right solution. The binding-over-core priority prevents the corruption scenario where a v9 Angular app with a stale @ionic/core@^8 pin would re-select destructive migrations.
core-modal-handle's brace-balancing — Scoping handleBehavior checks to the enclosing options object (via enclosingObject()) is a thoughtful touch. Without it, one opted-out sheet modal would silence every other sheet in the file. The Vue .vue test case (template opt-out shouldn't suppress script block findings) is a great edge case to cover.
core-form-structure's rule ordering — Putting the slot rules before the broader wrapper rule so the guide's own example selector (ion-input .input-wrapper .native-wrapper [slot="start"]) gets the .input-start answer instead of .input-control shows attention to the developer experience of the report output.
ScanMatch union type — Letting a single migration emit per-finding docsUrl overrides is a clean abstraction. core-select-events linking ionChange findings to one anchor and selected role findings to another is exactly the kind of granularity that saves someone's debugging time.
Minor note: the core-textarea-height scan for 56px scoped to files mentioning ion-textarea is a pragmatic tradeoff — 56px is too common to flag globally, but it does mean a stylesheet that sets the height on a selector like .my-textarea-wrapper without the tag name would be missed. Probably fine for real-world usage though.
Solid work taking the registry to 29 with full fixture-backed tests. 👏
major-9.0 removed the IONIC_V9_VERSION dev build pin in favor of the numeric major target. Resolved react-deps.ts to keep the new React 18 bumps alongside the numeric Ionic targets, and engine.test.ts to keep the sourceMajor import without versions.js. Also updated core-deps.ts and two migrations.test.ts references, which git auto-merged clean but still pointed at the deleted module.
| What `npx @ionic/migrate` covers for the Ionic 8 to Ionic 9 upgrade, and what it | ||
| leaves to you. The full list of breaking changes, with before/after examples, is |
There was a problem hiding this comment.
The first sentence sounds a bit weird to me. Maybe: "This page covers what npx @ionic/migrate handles for the Ionic 8 to Ionic 9 upgrade, and what it leaves to you."
There was a problem hiding this comment.
Yeah, that was a fragment. Done!
|
|
||
| ## Coverage | ||
|
|
||
| | Change | Framework | Mode | |
There was a problem hiding this comment.
Might be worth creating separate tables for each framework and each table would have it's own title. It would be beneficial to devs who just want to review specific frameworks that are relevant to them.
### Angular
"table for angular"
### React
....
There was a problem hiding this comment.
Good call! Split into Angular, React, Vue, and All frameworks, and dropped the Framework column since the heading covers it now. There's a line up top pointing people at their framework's table plus the core one, since the core changes apply on top.
| * works, and the rewrite is structural (the entry moves from a module's | ||
| * `imports` to its `providers`, with any `forRoot()` config). | ||
| * | ||
| * See https://ionicframework.com/docs/updating/9-0#ionicmodule-deprecation |
There was a problem hiding this comment.
| * See https://ionicframework.com/docs/updating/9-0#ionicmodule-deprecation | |
| * Refer to https://ionicframework.com/docs/updating/9-0#ionicmodule-deprecation |
| * `tsconfig.json` carries `//` comments, which are valid JSONC but not JSON, and | ||
| * round-tripping through `JSON.parse`/`stringify` would silently drop them. | ||
| * | ||
| * See https://ionicframework.com/docs/updating/9-0#module-resolution |
There was a problem hiding this comment.
| * See https://ionicframework.com/docs/updating/9-0#module-resolution | |
| * Refer to https://ionicframework.com/docs/updating/9-0#module-resolution |
| * Pinned with a tilde: Angular's peer ranges are narrow (18 accepts `>=5.4 <5.6`), | ||
| * and `^5.4.0` resolves to 5.9.x, which nothing below Angular 20 accepts. | ||
| * | ||
| * See https://ionicframework.com/docs/updating/9-0#typescript |
There was a problem hiding this comment.
| * See https://ionicframework.com/docs/updating/9-0#typescript | |
| * Refer to https://ionicframework.com/docs/updating/9-0#typescript |
| detect(ctx) { | ||
| return scanLines(ctx, SOURCE_GLOBS, (line) => | ||
| SWIPE_BACK.test(line) | ||
| ? 'in React and Vue, swipeBackEnabled is read once at outlet mount now. If you toggle it at runtime, use the swipeGesture property' |
There was a problem hiding this comment.
| ? 'in React and Vue, swipeBackEnabled is read once at outlet mount now. If you toggle it at runtime, use the swipeGesture property' | |
| ? 'In React and Vue, swipeBackEnabled is read once at outlet mount now. If you toggle it at runtime, use the swipeGesture property.' |
There was a problem hiding this comment.
This one's the same as the toolkit finding: the details print as annotations after the path:line - prefix, and none of the ~30 in the registry ends in a period, so I'd rather keep them uniform.
| * common enough that flagging it everywhere would be noise. A stylesheet that | ||
| * never names the element is missed. | ||
| * | ||
| * See https://ionicframework.com/docs/updating/9-0#minimum-height-change |
There was a problem hiding this comment.
| * See https://ionicframework.com/docs/updating/9-0#minimum-height-change | |
| * Refer to https://ionicframework.com/docs/updating/9-0#minimum-height-change |
| findings.push({ | ||
| filePath, | ||
| line: i + 1, | ||
| detail: 'ion-textarea is 72px tall in md mode now, not 56px. Update or override this value', |
There was a problem hiding this comment.
| detail: 'ion-textarea is 72px tall in md mode now, not 56px. Update or override this value', | |
| detail: 'ion-textarea is 72px tall in md mode now, not 56px. Update or override this value.', |
There was a problem hiding this comment.
I've left the period off here for the same reason as the toolkit finding, the details print as annotations and none of the ~30 in the registry ends in one.
| docsUrl: `${V9_DOCS}#route-definition-changes`, | ||
| }; | ||
| const CHILDREN_REMOVED: ReportedChange = { | ||
| detail: `Route content passed as children no longer renders. Move it into the "element" prop`, |
There was a problem hiding this comment.
| detail: `Route content passed as children no longer renders. Move it into the "element" prop`, | |
| detail: `Route content passed as children no longer renders. Move it into the "element" prop.`, |
There was a problem hiding this comment.
Leaving this one as-is too, same reason as the toolkit thread.
| Each major upgrade has its own page, listing every change the tool covers, which | ||
| kind it is, and what it leaves to you: |
There was a problem hiding this comment.
Sounds weird to me, maybe:
| Each major upgrade has its own page, listing every change the tool covers, which | |
| kind it is, and what it leaves to you: | |
| Each major upgrade has its own page, listing every change the tool covers, how it is classified, and the changes left for you to make manually: |
There was a problem hiding this comment.
Reworded, though I went with "whether it is auto-fixed or report-only" since those are the two names the section right above defines.
Issue number: internal
What is the current behavior?
Currently,
@ionic/migratecovers 15 of the breaking changes in the v9 upgrade guide. The AngularmoduleResolutionchange and@ionic/core's newexportsfield aren't in there, and neither are about a dozen others.There's also a gap for vanilla apps:
detectFrameworksonly knows@ionic/angular,@ionic/react, and@ionic/vue, so a vanilla app prints "No @ionic/{angular,react,vue} dependency found" and exits. Every migration markedframework: 'core'is unreachable for the apps it was written for.What is the new behavior?
This PR adds 14 migrations, taking the registry to 29 (12 auto-fix, 17 report-only). The full table is in the new
packages/migrate/docs/v9.md. The README is version-agnostic now, so the next major gets its own page instead of a rewrite.We also detect
@ionic/coreas a framework, so vanilla apps run thecoremigrations and get their pin bumped. We gate the version check on the binding package when there's one, because an app on a v9 binding with a stale@ionic/corepin is already migrated, and taking the lowest major would re-run the single-shot import rewrite and corrupt it.Does this introduce a breaking change?
Other information
Note: this PR is based off of the end result of ionic-docs#4620. Ten of the docs anchors these migrations link to only exist on that branch.
Two v9 changes stay uncovered on purpose, with the reasoning in
docs/v9.md: React Router's/*suffix for nested routes, and which components Angular 22'sOnPushdefault affects. We do flag the Angular 22 version itself.