Skip to content

Conversation

@zhiyuanzmj
Copy link
Member

@zhiyuanzmj zhiyuanzmj commented Jun 1, 2025

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-compatible router components to improve routing and view rendering in Vapor apps.
  • Tests

    • Introduced comprehensive test suites and a new mounting helper to strengthen routing and link/view behavior coverage.
  • Chores

    • Updated manifest entries and bumped several development dependencies; added an npm script to support code formatting.

@netlify
Copy link

netlify bot commented Jun 1, 2025

Deploy Preview for vue-router canceled.

Name Link
🔨 Latest commit b8b0bd5
🔍 Latest deploy log https://app.netlify.com/projects/vue-router/deploys/6985ddec2b44dd0008924102

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jun 1, 2025

Open in StackBlitz

npm i https://pkg.pr.new/vue-router@2509

commit: 555f3ab

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

posva commented Jul 11, 2025

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

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
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 [email protected]

@absidue
Copy link

absidue commented Aug 4, 2025

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
Copy link
Member

posva commented Aug 4, 2025

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

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

@posva
Copy link
Member

posva commented Nov 13, 2025

No

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 11, 2025

📝 Walkthrough

Walkthrough

Adds Vapor-compatible router components (VaporRouterLink, VaporRouterView), new comprehensive Vitest tests and a mount helper, exposes getLinkClass, updates router install to skip global props in Vapor apps, and adjusts monorepo/package dependency pins to an external Vue registry plus several dependency bumps.

Changes

Cohort / File(s) Summary
Vapor Router Components & Exports
packages/router/src/VaporRouterLink.ts, packages/router/src/VaporRouterView.ts, packages/router/src/RouterLink.ts, packages/router/src/index.ts
Adds VaporRouterLink and VaporRouterView components, exports them from the package, and makes getLinkClass a public export.
Router Installation Logic
packages/router/src/router.ts
Guards global property injection ($router, $route) when app.vapor is truthy to avoid augmenting Vapor apps.
Router Tests & Test Utilities
packages/router/__tests__/VaporRouterLink.spec.ts, packages/router/__tests__/VaporRouterView.spec.ts, packages/router/__tests__/mount.ts
Adds extensive Vitest suites for VaporRouterLink/View covering rendering, navigation, active-state rules, slots, aliases, nested routing, KeepAlive behavior, and a new createVaporMount test helper.
Package Manifests (root & packages)
package.json, packages/router/package.json, packages/experiments-playground/package.json, packages/playground-file-based/package.json, packages/playground/package.json, packages/router/e2e/unplugin/hmr/playground/package.json
Pins Vue to an external registry URL across several manifests, adds fmt script at root, bumps dev/build dependencies (devtools-api, rollup, playwright, vite-plugin-vue-devtools), moves Vue deps to devDependencies in playgrounds, and sets type: "module" for an e2e playground.
TypeScript config
packages/router/tsconfig.json
Removes @vitest/browser/providers/playwright from compilerOptions.types.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant App as App (Vapor-enabled)
participant Router as Router (installation & matcher)
participant View as VaporRouterView
participant Link as VaporRouterLink
App->>Router: initialize (app.vapor = true)
Router-->>App: skip global $router/$route assignment
App->>View: render -> requests matched component
View->>Router: resolve route & matched record
Router-->>View: matched component + route props
View->>View: instantiate/render component (with KeepAlive support)
App->>Link: render link (to prop)
Link->>Router: useLink -> compute href/isActive
Router-->>Link: href, isActive, navigate()

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Custom Route Resolvers #2415 — touches experimental router resolver/matcher surface and likely overlaps with routing internals and matchers used by the new components.

Poem

🐰 I hopped through routes with a jaunty tune,
Vapor links glowing beneath the moon.
Tests all in order, components align,
KeepAlive cuddles each nested design.
A tiny rabbit applauds—code looks fine! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 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 generic. It uses 'wip' (work in progress) and 'vapor mode' without conveying what specific changes were made or their primary purpose. Provide a more descriptive title that captures the main change, such as 'Add Vapor-compatible RouterView and RouterLink components' or 'Support Vue Vapor mode in router'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

@codecov
Copy link

codecov bot commented Dec 17, 2025

Codecov Report

❌ Patch coverage is 28.48837% with 123 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.32%. Comparing base (424c735) to head (555f3ab).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
packages/router/src/VaporRouterView.ts 15.74% 91 Missing ⚠️
packages/router/src/VaporRouterLink.ts 42.85% 32 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2509      +/-   ##
==========================================
- Coverage   85.32%   84.32%   -1.00%     
==========================================
  Files          84       86       +2     
  Lines        9769     9935     +166     
  Branches     2220     2220              
==========================================
+ Hits         8335     8378      +43     
- Misses       1422     1545     +123     
  Partials       12       12              

☔ View full report in Codecov by Sentry.
📢 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

Is there any progress?

@zhiyuanzmj
Copy link
Member Author

It works, You can try it:

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

@dsine-de
Copy link
Contributor

dsine-de commented Feb 2, 2026

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
Copy link

jl-a commented Feb 3, 2026

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
Copy link
Member

posva commented Feb 3, 2026

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

resolve: {
alias: {
// cjs does not export vapor runtime, use esm instead.
vue: 'vue/dist/vue.esm-bundler.js',
Copy link
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

@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
Copy link

Copilot AI left a comment

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 on lines +68 to +70
"vue": "https://pkg.pr.new/vue@d3fca3b",
"@vue/runtime-dom": "https://pkg.pr.new/@vue/runtime-dom@d3fca3b",
"@vue/server-renderer": "https://pkg.pr.new/@vue/server-renderer@d3fca3b"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

latest Vue 3.6 version npm registry

💡 Result:

Latest Vue 3.6.x published on the npm registry (prerelease) is 3.6.0-beta.5, published Jan 30, 2026. [1]


🏁 Script executed:

# Check if this is a known temporary state and find any related context
cd /dev/null
# First, let's look at the full package.json to understand the broader context
head -100 package.json

Repository: vuejs/router

Length of output: 2732


Replace pkg.pr.new URLs with proper npm version specifiers before merging.

These pkg.pr.new URLs are appropriate for WIP testing against unreleased Vue 3.6 features, but should not be included in production branches. Vue 3.6.0-beta.5 is now available on npm (published Jan 30, 2026) and can be used instead of the commit-pinned URLs (d3fca3b), or remove these overrides entirely once Vue 3.6 reaches stable release.

🤖 Prompt for AI Agents
In `@package.json` around lines 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.

"tinyglobby": "^0.2.15",
"unplugin": "^3.0.0",
"unplugin-utils": "^0.3.1",
"vue": "https://pkg.pr.new/vue@d3fca3b",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

vue should not be a production dependency.

Having vue in dependencies (line 153) rather than only in devDependencies and peerDependencies is problematic. When this package is published, it would bundle or require a specific Vue build from pkg.pr.new, which is a PR-specific URL that may become unavailable.

For a router library, Vue should only be:

  • A peerDependency (already present at line 195)
  • A devDependency for development/testing (already present at line 189)
🛠️ Suggested fix

Remove vue from the dependencies block:

   "dependencies": {
     "@babel/generator": "^7.28.6",
     "@vue-macros/common": "^3.1.1",
     "@vue/devtools-api": "^8.0.6",
     "ast-walker-scope": "^0.8.3",
     "chokidar": "^5.0.0",
     "json5": "^2.2.3",
     "local-pkg": "^1.1.2",
     "magic-string": "^0.30.21",
     "mlly": "^1.8.0",
     "muggle-string": "^0.4.1",
     "pathe": "^2.0.3",
     "picomatch": "^4.0.3",
     "scule": "^1.3.0",
     "tinyglobby": "^0.2.15",
     "unplugin": "^3.0.0",
     "unplugin-utils": "^0.3.1",
-    "vue": "https://pkg.pr.new/vue@d3fca3b",
     "yaml": "^2.8.2"
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"vue": "https://pkg.pr.new/vue@d3fca3b",
"dependencies": {
"@babel/generator": "^7.28.6",
"@vue-macros/common": "^3.1.1",
"@vue/devtools-api": "^8.0.6",
"ast-walker-scope": "^0.8.3",
"chokidar": "^5.0.0",
"json5": "^2.2.3",
"local-pkg": "^1.1.2",
"magic-string": "^0.30.21",
"mlly": "^1.8.0",
"muggle-string": "^0.4.1",
"pathe": "^2.0.3",
"picomatch": "^4.0.3",
"scule": "^1.3.0",
"tinyglobby": "^0.2.15",
"unplugin": "^3.0.0",
"unplugin-utils": "^0.3.1",
"yaml": "^2.8.2"
},
🤖 Prompt for AI Agents
In `@packages/router/package.json` at 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.

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.

9 participants