Skip to content

wip: vapor mode - #2509

Open
zhiyuanzmj wants to merge 30 commits into
vuejs:mainfrom
zhiyuanzmj:vapor
Open

wip: vapor mode#2509
zhiyuanzmj wants to merge 30 commits into
vuejs:mainfrom
zhiyuanzmj:vapor

Conversation

@zhiyuanzmj

@zhiyuanzmj zhiyuanzmj commented Jun 1, 2025

Copy link
Copy Markdown
Member

Description

This PR provide two vapor components: VaporRouterView and VaporRouterLink.
I'm not sure whether we should provide a vue-router/vapor for users to make migration easier.

import { RouterView } from 'vue-router/vapor'

export default () => <RouterView />

The access globalProperties warning should be remove.

Playground

https://repl.zmjs.dev/vuejs/vue-router

TODO

  • Unit tests

Summary by CodeRabbit

  • New Features

    • Added Vapor-mode router components for link/navigation and view rendering; apps now register and use these components.
  • Tests

    • Added extensive test suites covering link behavior, active-state detection, navigation handling, view rendering, slots and KeepAlive scenarios.
  • Chores

    • Aligned dependency versions across packages, moved some runtime packages to devDependencies, downgraded a dev type package, and set a playground package to module type.
  • Updates

    • Example playground apps updated to use Vapor setup and composition-route APIs in templates.

Review Change Stack

@netlify

netlify Bot commented Jun 1, 2025

Copy link
Copy Markdown

Deploy Preview for vue-router ready!

Name Link
🔨 Latest commit a5703dc
🔍 Latest deploy log https://app.netlify.com/projects/vue-router/deploys/6a96ad2d7975a50008e50f75
😎 Deploy Preview https://deploy-preview-2509--vue-router.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 85 (🟢 up 4 from production)
Accessibility: 97 (no change from production)
Best Practices: 100 (no change from production)
SEO: 92 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@pkg-pr-new

pkg-pr-new Bot commented Jun 1, 2025

Copy link
Copy Markdown

Open in StackBlitz

pnpm add https://pkg.pr.new/vue-router@2509
npm i https://pkg.pr.new/vue-router@2509
yarn add https://pkg.pr.new/vue-router@2509.tgz

commit: a5703dc

@zhiyuanzmj
zhiyuanzmj marked this pull request as draft June 27, 2025 13:43
@posva

posva commented Jul 11, 2025

Copy link
Copy Markdown
Member

Note for myself for refactoring and simplification: Playground

@github-project-automation github-project-automation Bot moved this to 🆕 Triaging in Vue Router Roadmap Jul 11, 2025
@posva posva moved this from 🆕 Triaging to 🧑‍💻 In progress in Vue Router Roadmap Jul 11, 2025
@Reinhard-Berger

Copy link
Copy Markdown

Is this already compatible with “3.6.0-alpha.1”?
Or is there still work required? I’d be happy to help if I can.

@zhiyuanzmj

Copy link
Copy Markdown
Member Author

Is this already compatible with “3.6.0-alpha.1”? Or is there still work required? I’d be happy to help if I can.

You can try it in vue@3.6.0-alpha.2

@absidue

absidue commented Aug 4, 2025

Copy link
Copy Markdown

The automatic global registration of the virtual DOM RouterView and RouterLink components in the install hook should probably be removed so that they can be tree-shaken when an app is only using the Vapor ones.

@posva

posva commented Aug 4, 2025

Copy link
Copy Markdown
Member

FYI this is planned after #2415 which will also allow to register a custom RouterView and RouterLink

@LittleSound LittleSound mentioned this pull request Oct 18, 2025
22 tasks
@nevmerzhitsky

Copy link
Copy Markdown

Is this a last blocker of the epic of embedding Vapor into the core?

@posva

posva commented Nov 13, 2025

Copy link
Copy Markdown
Member

No

Comment thread packages/router/src/VaporRouterLink.ts Outdated
Comment thread packages/router/src/VaporRouterLink.ts
Comment thread packages/router/src/VaporRouterView.ts Outdated
Comment thread packages/router/src/VaporRouterView.ts Outdated
@coderabbitai

coderabbitai Bot commented Dec 11, 2025

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Vapor-compatible RouterLink and RouterView components, test helpers and large Vitest suites, updates package manifests and playground files to use Vapor wiring, and prevents global $router/$route injection when app.vapor is true.

Changes

Vapor router feature

Layer / File(s) Summary
Manifests and playground wiring
package.json, packages/*/package.json, packages/playground-file-based/src/*
Adjust root and package devDependencies (@types/node, playwright, Vue pins/overrides), add type: "module" for an e2e playground, move Vue/router to devDependencies in playgrounds, and switch app code to createVaporApp, VaporRouterLink, VaporRouterView, and setup vapor script usage.
VaporRouterLink & VaporRouterView implementation
packages/router/src/VaporRouterLink.ts, packages/router/src/VaporRouterView.ts, packages/router/src/RouterLink.ts, packages/router/src/index.ts, packages/router/src/router.ts
Add exported VaporRouterLink and VaporRouterView components (props, slots, link/view logic, depth/props mapping, lazy instantiation, guard copying), export getLinkClass, add exports to index, and guard globalProperties assignment behind if (!app.vapor).
Test helpers & suites
packages/router/__tests__/mount.ts, packages/router/__tests__/VaporRouterLink.spec.ts, packages/router/__tests__/VaporRouterView.spec.ts
Add createVaporMount() helper and large Vitest suites covering link hrefs, active/exact-active logic, slot behavior, click/navigation, nested view rendering, props handling, KeepAlive, and related cases.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant VaporRouterLink
  participant Router
  participant VaporRouterView
  participant Component

  User->>VaporRouterLink: click (on link)
  VaporRouterLink->>Router: navigate (push/replace)
  Router->>Router: update current location / matched records
  Router->>VaporRouterView: notify view depth / matchedRoute change
  VaporRouterView->>Component: instantiate/render matched component (with props)
  Component-->>VaporRouterView: mounted/rendered
  VaporRouterView-->>User: DOM updated
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Custom Route Resolvers #2415: Adds experimental resolver/matcher system and related exports that overlap router infrastructure and APIs in this change.

Poem

🐰
Soft hops on new routes I sow,
Links that point and views that know,
Vapor-mode keeps globals light,
Tests that prove each jump is right,
I nibble bugs and watch them go ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title "wip: vapor mode" is vague and uses non-descriptive terminology ("wip" and "vapor mode") that doesn't clearly convey the specific changes made in the changeset. Consider using a more descriptive title that specifies the main changes, such as: "Add VaporRouterLink and VaporRouterView components" or "Implement Vapor-compatible router components".
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Dec 17, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.12195% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.17%. Comparing base (0e91ac8) to head (a5703dc).

Files with missing lines Patch % Lines
packages/router/src/VaporRouterView.ts 93.33% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2509      +/-   ##
==========================================
+ Coverage   86.05%   86.17%   +0.11%     
==========================================
  Files          74       76       +2     
  Lines        5896     5973      +77     
  Branches     1874     1898      +24     
==========================================
+ Hits         5074     5147      +73     
- Misses        726      728       +2     
- Partials       96       98       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@luvletterldl

Copy link
Copy Markdown

Is there any progress?

@zhiyuanzmj

Copy link
Copy Markdown
Member Author

It works, You can try it:

pnpm i https://pkg.pr.new/vue-router@ef302bd

@dsine-de

dsine-de commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Will the next step be to make this available in a beta version tag or will it simply be a new release when vue 3.6 is out of beta?

@jl-a

jl-a commented Feb 3, 2026

Copy link
Copy Markdown

When using a vapor only app with createVaporApp, the full vue virtual DOM runtime is still pulled in when using vue router because RouterView and RouterLink are automatically registered, even if nothing uses them, as @absidue mentioned above. Maybe a createVaporRouter function is needed where only the vapor view and link components are automatically registered.

@posva

posva commented Feb 3, 2026

Copy link
Copy Markdown
Member

The experimental (and future) router already stopped registering those components because of that

Comment thread packages/router/vitest.config.ts Outdated
resolve: {
alias: {
// cjs does not export vapor runtime, use esm instead.
vue: 'vue/dist/vue.esm-bundler.js',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you manage to add any test? That would be great to iterate on details

Comment thread packages/router/src/VaporRouterView.ts Outdated
@zhiyuanzmj
zhiyuanzmj marked this pull request as ready for review February 6, 2026 12:15
Copilot AI review requested due to automatic review settings February 6, 2026 12:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds experimental Vapor mode support to vue-router by introducing two new components: VaporRouterView and VaporRouterLink. The implementation conditionally disables global properties ($router and $route) in Vapor mode and includes comprehensive test coverage for both components.

Changes:

  • Added Vapor-compatible VaporRouterView and VaporRouterLink components with full functionality
  • Conditionally disabled global properties injection for Vapor apps
  • Updated Vue dependency to a pre-release version that includes Vapor support

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/router/src/VaporRouterView.ts New Vapor-compatible RouterView component implementation
packages/router/src/VaporRouterLink.ts New Vapor-compatible RouterLink component implementation
packages/router/src/router.ts Added conditional check to skip global properties in Vapor mode
packages/router/src/RouterLink.ts Exported getLinkClass function for reuse in VaporRouterLink
packages/router/src/index.ts Exported new Vapor components
packages/router/tests/VaporRouterView.spec.ts Comprehensive test suite for VaporRouterView
packages/router/tests/VaporRouterLink.spec.ts Comprehensive test suite for VaporRouterLink
packages/router/tests/mount.ts Added test mounting utilities for Vapor components
packages/router/package.json Updated dependencies to pre-release versions
packages/router/tsconfig.json Removed Playwright types reference
package.json Added pnpm overrides and new script

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/router/src/router.ts (1)

1013-1025: ⚠️ Potential issue | 🟠 Major

Tree-shaking concern: components registered unconditionally for Vapor apps.

The global property injection is correctly guarded by !app.vapor, but RouterLink and RouterView are still registered via app.component() on lines 1014-1015 regardless of the app type. As noted in PR discussion, this causes Vapor-only apps to pull in the full virtual DOM runtime.

Consider extending the vapor check to also skip component registration:

💡 Suggested approach
 install(app: App) {
-  app.component('RouterLink', RouterLink)
-  app.component('RouterView', RouterView)
+  if (!app.vapor) {
+    app.component('RouterLink', RouterLink)
+    app.component('RouterView', RouterView)
+  }

   // TODO: move this part for composition API only
   if (!app.vapor) {

Alternatively, a separate createVaporRouter entry point could handle Vapor-specific registration as suggested in the PR comments.

🤖 Fix all issues with AI agents
In `@package.json`:
- Around line 68-70: The package entries for "vue", "@vue/runtime-dom", and
"@vue/server-renderer" currently point to pkg.pr.new commit URLs; replace those
URL overrides with proper npm version specifiers (for example "3.6.0-beta.5") or
remove the overrides entirely so package.json uses standard npm versions; update
the three keys ("vue", "@vue/runtime-dom", "@vue/server-renderer") to the chosen
semver strings and run npm install / yarn install to verify dependency
resolution.

In `@packages/router/__tests__/mount.ts`:
- Around line 52-84: The test helper createVaporMount mounts a Vapor app but
never calls app.unmount(), risking leaks; modify createVaporMount so the created
app instance is stored in an outer-scope variable and then call app.unmount() in
the afterEach cleanup before removing the DOM element. Specifically, keep the
existing const app = createVaporApp(...) inside the returned mount function but
also assign it to an outer let mountedApp variable (or return an unmount
function), and ensure afterEach calls mountedApp?.unmount() (and clears
mountedApp) so Vapor lifecycle hooks run and state is not retained between
tests.

In `@packages/router/package.json`:
- Line 153: Remove the "vue" entry from the dependencies block in package.json
(the dependency key "vue": "https://pkg.pr.new/vue@d3fca3b") so the package does
not ship a hard-coded PR URL; leave/ensure "vue" only exists in peerDependencies
and devDependencies (the existing "peerDependencies" and "devDependencies"
entries) to keep Vue as a peer and development-only dependency.
🧹 Nitpick comments (6)
packages/router/src/router.ts (1)

1018-1019: Track type definition for app.vapor.

The @ts-expect-error suppression is reasonable while Vapor is experimental. Once Vue 3.6 stabilizes the Vapor API, ensure the App interface is properly augmented to include the vapor property, or import the correct types from Vue.

packages/router/__tests__/VaporRouterView.spec.ts (1)

300-300: Consider renaming describe block to match component name.

The test suite is named 'RouterView' but tests VaporRouterView. For clarity and test output readability, consider renaming to 'VaporRouterView'.

-describe('RouterView', () => {
+describe('VaporRouterView', () => {
packages/router/__tests__/VaporRouterLink.spec.ts (4)

15-34: Several Vue imports appear unused in this test file.

Many Vapor primitives imported from vue (e.g., PropType, VaporDirective, setInsertionState, txt) are used in specific inline component definitions within tests. However, consider verifying all imports are necessary. For instance, createComponentWithFallback appears on line 953 but some others may be unnecessary.


54-59: Inconsistent aliasOf initialization pattern.

Lines 54-58 reassign records with aliasOf properties using object spread, while line 59 mutates records.childEmptyAlias directly. This inconsistency could cause confusion.

♻️ Suggested fix for consistency
 records.homeAlias = { aliasOf: records.home } as RouteRecordNormalized
 records.parentAlias = {
   aliasOf: records.parent,
 } as RouteRecordNormalized
 records.childAlias = { aliasOf: records.child } as RouteRecordNormalized
-records.childEmptyAlias.aliasOf = records.childEmpty
+records.childEmptyAlias = { aliasOf: records.childEmpty } as RouteRecordNormalized

406-443: Inconsistent prop binding syntax across tests.

Some tests use getter functions { to: () => locations.basic.string } (line 409), while others pass values directly { to: locations.basic.string } (line 441). While both patterns may work, this inconsistency could mask issues with reactive vs static prop handling.

Consider documenting which pattern is intended for which scenario, or standardizing on one approach for clarity.


1012-1013: Consider adding a brief comment explaining the $evtclick pattern.

The @ts-ignore on line 1012 suppresses a type error for the Vapor-specific event binding pattern. A brief comment explaining this is Vapor's internal event delegation mechanism would help future maintainers.

📝 Suggested documentation
-                    // `@ts-ignore`
-                    n6.$evtclick = e => slotProps0.navigate(e)
+                    // Vapor's event delegation: $evt{eventname} binds click handler
+                    // `@ts-ignore` - internal Vapor API
+                    n6.$evtclick = e => slotProps0.navigate(e)

Comment thread package.json Outdated
Comment thread packages/router/__tests__/mount.ts
Comment thread packages/router/package.json Outdated
@FlameWolf

Copy link
Copy Markdown

If I include this in a vue-jsx-vapor project and use only VaporRouterView and VaporRouterLink, will the VDom runtime get pulled into the build output?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🧑‍💻 In progress

Development

Successfully merging this pull request may close these issues.