@esmx/router-vue 3.0.0-rc.87 → 3.0.0-rc.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@ export const RouterView = defineComponent({
9
9
  return () => {
10
10
  const matchedRoute = route.matched[depth];
11
11
  const component = matchedRoute ? resolveComponent(matchedRoute.component) : null;
12
- return component ? h(component) : null;
12
+ return component ? h(component, { key: matchedRoute.compilePath }) : null;
13
13
  };
14
14
  }
15
15
  });
@@ -287,9 +287,7 @@ describe("router-view.ts - RouterView Component", () => {
287
287
  return () => h("div", [
288
288
  h("span", "App"),
289
289
  h(RouterView),
290
- // This renders Home component at depth 0
291
290
  h(DeepRouterView)
292
- // This tries to render at depth 1, but no match
293
291
  ]);
294
292
  }
295
293
  });
@@ -342,7 +340,6 @@ describe("router-view.ts - RouterView Component", () => {
342
340
  {
343
341
  path: "/",
344
342
  component: null
345
- // Initial route with null component
346
343
  }
347
344
  ],
348
345
  mode: RouterMode.memory,
@@ -456,4 +453,224 @@ describe("router-view.ts - RouterView Component", () => {
456
453
  app.unmount();
457
454
  });
458
455
  });
456
+ describe("compilePath as Key", () => {
457
+ it("should use compilePath as key for component rendering", async () => {
458
+ let mountCount = 0;
459
+ const TrackedComponent = defineComponent({
460
+ name: "TrackedComponent",
461
+ setup() {
462
+ mountCount++;
463
+ return () => h(
464
+ "div",
465
+ { class: "tracked" },
466
+ "Mounted ".concat(mountCount, " times")
467
+ );
468
+ }
469
+ });
470
+ const routes = [
471
+ {
472
+ path: "/route1",
473
+ component: TrackedComponent
474
+ },
475
+ {
476
+ path: "/route2",
477
+ component: TrackedComponent
478
+ }
479
+ ];
480
+ const testRouter = new Router({
481
+ root: "#test-app",
482
+ routes,
483
+ mode: RouterMode.memory,
484
+ base: new URL("http://localhost:8000/")
485
+ });
486
+ await testRouter.replace("/route1");
487
+ await new Promise((resolve) => setTimeout(resolve, 10));
488
+ const TestApp = defineComponent({
489
+ setup() {
490
+ useProvideRouter(testRouter);
491
+ return () => h("div", [h(RouterView)]);
492
+ }
493
+ });
494
+ const app = createApp(TestApp);
495
+ app.mount(testContainer);
496
+ await nextTick();
497
+ expect(mountCount).toBe(1);
498
+ expect(testContainer.textContent).toContain("Mounted 1 times");
499
+ await testRouter.push("/route2");
500
+ await nextTick();
501
+ expect(mountCount).toBe(2);
502
+ expect(testContainer.textContent).toContain("Mounted 2 times");
503
+ await testRouter.push("/route1");
504
+ await nextTick();
505
+ expect(mountCount).toBe(3);
506
+ expect(testContainer.textContent).toContain("Mounted 3 times");
507
+ app.unmount();
508
+ testRouter.destroy();
509
+ });
510
+ it("should force re-render when compilePath changes for same route", async () => {
511
+ let mountCount = 0;
512
+ const TrackedComponent = defineComponent({
513
+ name: "TrackedComponent",
514
+ setup() {
515
+ mountCount++;
516
+ return () => h("div", { class: "tracked" }, "Mount #".concat(mountCount));
517
+ }
518
+ });
519
+ const routes = [
520
+ {
521
+ path: "/test",
522
+ component: TrackedComponent
523
+ }
524
+ ];
525
+ const testRouter = new Router({
526
+ root: "#test-app",
527
+ routes,
528
+ mode: RouterMode.memory,
529
+ base: new URL("http://localhost:8000/")
530
+ });
531
+ await testRouter.replace("/test");
532
+ await new Promise((resolve) => setTimeout(resolve, 10));
533
+ const TestApp = defineComponent({
534
+ setup() {
535
+ useProvideRouter(testRouter);
536
+ return () => h("div", [h(RouterView)]);
537
+ }
538
+ });
539
+ const app = createApp(TestApp);
540
+ app.mount(testContainer);
541
+ await nextTick();
542
+ expect(mountCount).toBe(1);
543
+ expect(testContainer.textContent).toContain("Mount #1");
544
+ const newRoutes = [
545
+ {
546
+ path: "/test",
547
+ component: TrackedComponent,
548
+ meta: { updated: true }
549
+ }
550
+ ];
551
+ const newRouter = new Router({
552
+ root: "#test-app",
553
+ routes: newRoutes,
554
+ mode: RouterMode.memory,
555
+ base: new URL("http://localhost:8000/")
556
+ });
557
+ await newRouter.replace("/test");
558
+ await new Promise((resolve) => setTimeout(resolve, 10));
559
+ app.unmount();
560
+ const NewTestApp = defineComponent({
561
+ setup() {
562
+ useProvideRouter(newRouter);
563
+ return () => h("div", [h(RouterView)]);
564
+ }
565
+ });
566
+ const newApp = createApp(NewTestApp);
567
+ newApp.mount(testContainer);
568
+ await nextTick();
569
+ expect(mountCount).toBe(2);
570
+ expect(testContainer.textContent).toContain("Mount #2");
571
+ newApp.unmount();
572
+ newRouter.destroy();
573
+ });
574
+ it("should handle same component with same compilePath without unnecessary re-renders", async () => {
575
+ let mountCount = 0;
576
+ const TrackedComponent = defineComponent({
577
+ name: "TrackedComponent",
578
+ setup() {
579
+ mountCount++;
580
+ return () => h("div", { class: "tracked" }, "Component");
581
+ }
582
+ });
583
+ const routes = [
584
+ {
585
+ path: "/test",
586
+ component: TrackedComponent
587
+ }
588
+ ];
589
+ const testRouter = new Router({
590
+ root: "#test-app",
591
+ routes,
592
+ mode: RouterMode.memory,
593
+ base: new URL("http://localhost:8000/")
594
+ });
595
+ await testRouter.replace("/test");
596
+ await new Promise((resolve) => setTimeout(resolve, 10));
597
+ const TestApp = defineComponent({
598
+ setup() {
599
+ useProvideRouter(testRouter);
600
+ return () => h("div", [h(RouterView)]);
601
+ }
602
+ });
603
+ const app = createApp(TestApp);
604
+ app.mount(testContainer);
605
+ await nextTick();
606
+ expect(mountCount).toBe(1);
607
+ await testRouter.push("/");
608
+ await nextTick();
609
+ await testRouter.push("/test");
610
+ await nextTick();
611
+ expect(mountCount).toBe(1);
612
+ app.unmount();
613
+ testRouter.destroy();
614
+ });
615
+ it("should work with nested routes and compilePath keys", async () => {
616
+ let parentMountCount = 0;
617
+ let childMountCount = 0;
618
+ const ParentComponent = defineComponent({
619
+ name: "ParentComponent",
620
+ setup() {
621
+ parentMountCount++;
622
+ return () => h("div", [
623
+ h("h1", "Parent Mount #".concat(parentMountCount)),
624
+ h(RouterView)
625
+ ]);
626
+ }
627
+ });
628
+ const ChildComponent = defineComponent({
629
+ name: "ChildComponent",
630
+ setup() {
631
+ childMountCount++;
632
+ return () => h(
633
+ "div",
634
+ { class: "child" },
635
+ "Child Mount #".concat(childMountCount)
636
+ );
637
+ }
638
+ });
639
+ const nestedRoutes = [
640
+ {
641
+ path: "/parent",
642
+ component: ParentComponent,
643
+ children: [
644
+ {
645
+ path: "child",
646
+ component: ChildComponent
647
+ }
648
+ ]
649
+ }
650
+ ];
651
+ const nestedRouter = new Router({
652
+ root: "#test-app",
653
+ routes: nestedRoutes,
654
+ mode: RouterMode.memory,
655
+ base: new URL("http://localhost:8000/")
656
+ });
657
+ await nestedRouter.replace("/parent/child");
658
+ await new Promise((resolve) => setTimeout(resolve, 10));
659
+ const TestApp = defineComponent({
660
+ setup() {
661
+ useProvideRouter(nestedRouter);
662
+ return () => h("div", [h(RouterView)]);
663
+ }
664
+ });
665
+ const app = createApp(TestApp);
666
+ app.mount(testContainer);
667
+ await nextTick();
668
+ expect(parentMountCount).toBe(1);
669
+ expect(childMountCount).toBe(1);
670
+ expect(testContainer.textContent).toContain("Parent Mount #1");
671
+ expect(testContainer.textContent).toContain("Child Mount #1");
672
+ app.unmount();
673
+ nestedRouter.destroy();
674
+ });
675
+ });
459
676
  });
package/package.json CHANGED
@@ -50,7 +50,7 @@
50
50
  "vue": "^3.5.0 || ^2.7.0"
51
51
  },
52
52
  "dependencies": {
53
- "@esmx/router": "3.0.0-rc.87"
53
+ "@esmx/router": "3.0.0-rc.93"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@biomejs/biome": "2.3.7",
@@ -62,7 +62,7 @@
62
62
  "vue": "3.5.23",
63
63
  "vue2": "npm:vue@2.7.16"
64
64
  },
65
- "version": "3.0.0-rc.87",
65
+ "version": "3.0.0-rc.93",
66
66
  "type": "module",
67
67
  "private": false,
68
68
  "exports": {
@@ -81,5 +81,5 @@
81
81
  "template",
82
82
  "public"
83
83
  ],
84
- "gitHead": "1f79a73438c2193fd06ebaa3dc6a4ec420e6b026"
84
+ "gitHead": "680b3b3549c50a2817d7e8ab72b3bb84d07966ce"
85
85
  }
@@ -7,7 +7,6 @@ import { createApp, defineComponent, h, inject, nextTick, provide } from 'vue';
7
7
  import { RouterView } from './router-view';
8
8
  import { useProvideRouter } from './use';
9
9
 
10
- // Mock components for testing
11
10
  const HomeComponent = defineComponent({
12
11
  name: 'HomeComponent',
13
12
  setup() {
@@ -29,7 +28,6 @@ const UserComponent = defineComponent({
29
28
  }
30
29
  });
31
30
 
32
- // ES Module component for testing resolveComponent
33
31
  const ESModuleComponent = {
34
32
  __esModule: true,
35
33
  default: defineComponent({
@@ -46,12 +44,10 @@ describe('router-view.ts - RouterView Component', () => {
46
44
  let testContainer: HTMLElement;
47
45
 
48
46
  beforeEach(async () => {
49
- // Create test container
50
47
  testContainer = document.createElement('div');
51
48
  testContainer.id = 'test-app';
52
49
  document.body.appendChild(testContainer);
53
50
 
54
- // Create test routes
55
51
  const routes: RouteConfig[] = [
56
52
  {
57
53
  path: '/',
@@ -75,7 +71,6 @@ describe('router-view.ts - RouterView Component', () => {
75
71
  }
76
72
  ];
77
73
 
78
- // Create router instance
79
74
  router = new Router({
80
75
  root: '#test-app',
81
76
  routes,
@@ -83,19 +78,15 @@ describe('router-view.ts - RouterView Component', () => {
83
78
  base: new URL('http://localhost:8000/')
84
79
  });
85
80
 
86
- // Initialize router to root path and wait for it to be ready
87
81
  await router.replace('/');
88
- // Wait for route to be fully initialized
89
82
  await new Promise((resolve) => setTimeout(resolve, 10));
90
83
  });
91
84
 
92
85
  afterEach(() => {
93
- // Clean up test environment
94
86
  if (testContainer.parentNode) {
95
87
  testContainer.parentNode.removeChild(testContainer);
96
88
  }
97
89
 
98
- // Destroy router
99
90
  if (router) {
100
91
  router.destroy();
101
92
  }
@@ -114,7 +105,6 @@ describe('router-view.ts - RouterView Component', () => {
114
105
  app.mount(testContainer);
115
106
  await nextTick();
116
107
 
117
- // Check if HomeComponent is rendered
118
108
  expect(testContainer.textContent).toContain('Home Page');
119
109
 
120
110
  app.unmount();
@@ -132,10 +122,8 @@ describe('router-view.ts - RouterView Component', () => {
132
122
  app.mount(testContainer);
133
123
  await nextTick();
134
124
 
135
- // Initially should show Home
136
125
  expect(testContainer.textContent).toContain('Home Page');
137
126
 
138
- // Navigate to About
139
127
  await router.push('/about');
140
128
  await nextTick();
141
129
 
@@ -155,7 +143,6 @@ describe('router-view.ts - RouterView Component', () => {
155
143
  const app = createApp(TestApp);
156
144
  app.mount(testContainer);
157
145
 
158
- // Navigate to user route with parameter
159
146
  await router.push('/users/123');
160
147
  await nextTick();
161
148
 
@@ -177,7 +164,6 @@ describe('router-view.ts - RouterView Component', () => {
177
164
  const app = createApp(TestApp);
178
165
  app.mount(testContainer);
179
166
 
180
- // Navigate to ES module route
181
167
  await router.push('/es-module');
182
168
  await nextTick();
183
169
 
@@ -204,7 +190,6 @@ describe('router-view.ts - RouterView Component', () => {
204
190
  base: new URL('http://localhost:8000/')
205
191
  });
206
192
 
207
- // Initialize the router and wait for it to be ready
208
193
  await functionRouter.replace('/function');
209
194
  await new Promise((resolve) => setTimeout(resolve, 10));
210
195
 
@@ -230,10 +215,8 @@ describe('router-view.ts - RouterView Component', () => {
230
215
  it('should inject depth 0 by default', async () => {
231
216
  let injectedDepth: number | undefined;
232
217
 
233
- // Use the same symbol key that RouterView uses internally
234
218
  const RouterViewDepth = Symbol('RouterViewDepth');
235
219
 
236
- // Create a custom RouterView component that can capture the injected depth
237
220
  const TestRouterView = defineComponent({
238
221
  name: 'TestRouterView',
239
222
  setup() {
@@ -253,8 +236,7 @@ describe('router-view.ts - RouterView Component', () => {
253
236
  app.mount(testContainer);
254
237
  await nextTick();
255
238
 
256
- // TestRouterView should inject the default depth 0 when no parent RouterView exists
257
- expect(injectedDepth).toBe(-1); // Default value since no parent RouterView provides depth
239
+ expect(injectedDepth).toBe(-1);
258
240
 
259
241
  app.unmount();
260
242
  });
@@ -269,7 +251,7 @@ describe('router-view.ts - RouterView Component', () => {
269
251
  name: 'ParentTestComponent',
270
252
  setup() {
271
253
  parentDepth = inject(RouterViewDepth, -1);
272
- provide(RouterViewDepth, 0); // Simulate parent RouterView
254
+ provide(RouterViewDepth, 0);
273
255
  return () =>
274
256
  h('div', [h('span', 'Parent'), h(ChildTestComponent)]);
275
257
  }
@@ -294,9 +276,8 @@ describe('router-view.ts - RouterView Component', () => {
294
276
  app.mount(testContainer);
295
277
  await nextTick();
296
278
 
297
- // Parent should see default depth, child should see provided depth
298
- expect(parentDepth).toBe(-1); // Default value since no RouterView above
299
- expect(childDepth).toBe(0); // Value provided by parent
279
+ expect(parentDepth).toBe(-1);
280
+ expect(childDepth).toBe(0);
300
281
 
301
282
  app.unmount();
302
283
  });
@@ -337,7 +318,6 @@ describe('router-view.ts - RouterView Component', () => {
337
318
  base: new URL('http://localhost:8000/')
338
319
  });
339
320
 
340
- // Initialize the router and wait for it to be ready
341
321
  await nestedRouter.replace('/level1/level2');
342
322
  await new Promise((resolve) => setTimeout(resolve, 10));
343
323
 
@@ -367,7 +347,6 @@ describe('router-view.ts - RouterView Component', () => {
367
347
  const DeepRouterView = defineComponent({
368
348
  name: 'DeepRouterView',
369
349
  setup() {
370
- // Inject depth 0 from parent RouterView and provide depth 1
371
350
  const currentDepth = inject(RouterViewDepth, 0);
372
351
  provide(RouterViewDepth, currentDepth + 1);
373
352
  return () => h(RouterView);
@@ -380,8 +359,8 @@ describe('router-view.ts - RouterView Component', () => {
380
359
  return () =>
381
360
  h('div', [
382
361
  h('span', 'App'),
383
- h(RouterView), // This renders Home component at depth 0
384
- h(DeepRouterView) // This tries to render at depth 1, but no match
362
+ h(RouterView),
363
+ h(DeepRouterView)
385
364
  ]);
386
365
  }
387
366
  });
@@ -390,8 +369,6 @@ describe('router-view.ts - RouterView Component', () => {
390
369
  app.mount(testContainer);
391
370
  await nextTick();
392
371
 
393
- // Should contain "App" and "Home Page" from the first RouterView
394
- // but no additional content from the deep RouterView
395
372
  expect(testContainer.textContent).toContain('App');
396
373
  expect(testContainer.textContent).toContain('Home Page');
397
374
 
@@ -414,7 +391,6 @@ describe('router-view.ts - RouterView Component', () => {
414
391
  base: new URL('http://localhost:8000/')
415
392
  });
416
393
 
417
- // Initialize the router and wait for it to be ready
418
394
  await nullRouter.replace('/null-component');
419
395
  await new Promise((resolve) => setTimeout(resolve, 10));
420
396
 
@@ -429,9 +405,8 @@ describe('router-view.ts - RouterView Component', () => {
429
405
  app.mount(testContainer);
430
406
  await nextTick();
431
407
 
432
- // Verify that only the "App" text is rendered and RouterView renders nothing
433
408
  expect(testContainer.textContent?.trim()).toBe('App');
434
- expect(testContainer.querySelector('div')?.children.length).toBe(1); // Only the span element
409
+ expect(testContainer.querySelector('div')?.children.length).toBe(1);
435
410
  expect(testContainer.querySelector('span')?.textContent).toBe(
436
411
  'App'
437
412
  );
@@ -441,20 +416,18 @@ describe('router-view.ts - RouterView Component', () => {
441
416
  });
442
417
 
443
418
  it('should handle non-existent routes', async () => {
444
- // Create a new router instance with a valid initial route
445
419
  const nonExistentRouter = new Router({
446
420
  root: '#test-app',
447
421
  routes: [
448
422
  {
449
423
  path: '/',
450
- component: null // Initial route with null component
424
+ component: null
451
425
  }
452
426
  ],
453
427
  mode: RouterMode.memory,
454
428
  base: new URL('http://localhost:8000/')
455
429
  });
456
430
 
457
- // Initialize router with root path
458
431
  await nonExistentRouter.replace('/');
459
432
  await new Promise((resolve) => setTimeout(resolve, 10));
460
433
 
@@ -468,16 +441,13 @@ describe('router-view.ts - RouterView Component', () => {
468
441
  const app = createApp(TestApp);
469
442
  app.mount(testContainer);
470
443
 
471
- // Navigate to non-existent route
472
444
  await nonExistentRouter.push('/non-existent');
473
445
  await nextTick();
474
446
 
475
- // Wait for any pending route changes
476
447
  await new Promise((resolve) => setTimeout(resolve, 10));
477
448
 
478
- // Verify that only the "App" text is rendered and RouterView renders nothing
479
449
  expect(testContainer.textContent?.trim()).toBe('App');
480
- expect(testContainer.querySelector('div')?.children.length).toBe(1); // Only the span element
450
+ expect(testContainer.querySelector('div')?.children.length).toBe(1);
481
451
  expect(testContainer.querySelector('span')?.textContent).toBe(
482
452
  'App'
483
453
  );
@@ -507,7 +477,6 @@ describe('router-view.ts - RouterView Component', () => {
507
477
  base: new URL('http://localhost:8000/')
508
478
  });
509
479
 
510
- // Initialize the router and wait for it to be ready
511
480
  await malformedRouter.replace('/malformed');
512
481
  await new Promise((resolve) => setTimeout(resolve, 10));
513
482
 
@@ -596,4 +565,276 @@ describe('router-view.ts - RouterView Component', () => {
596
565
  app.unmount();
597
566
  });
598
567
  });
568
+
569
+ describe('compilePath as Key', () => {
570
+ it('should use compilePath as key for component rendering', async () => {
571
+ let mountCount = 0;
572
+ const TrackedComponent = defineComponent({
573
+ name: 'TrackedComponent',
574
+ setup() {
575
+ mountCount++;
576
+ return () =>
577
+ h(
578
+ 'div',
579
+ { class: 'tracked' },
580
+ `Mounted ${mountCount} times`
581
+ );
582
+ }
583
+ });
584
+
585
+ const routes: RouteConfig[] = [
586
+ {
587
+ path: '/route1',
588
+ component: TrackedComponent
589
+ },
590
+ {
591
+ path: '/route2',
592
+ component: TrackedComponent
593
+ }
594
+ ];
595
+
596
+ const testRouter = new Router({
597
+ root: '#test-app',
598
+ routes,
599
+ mode: RouterMode.memory,
600
+ base: new URL('http://localhost:8000/')
601
+ });
602
+
603
+ await testRouter.replace('/route1');
604
+ await new Promise((resolve) => setTimeout(resolve, 10));
605
+
606
+ const TestApp = defineComponent({
607
+ setup() {
608
+ useProvideRouter(testRouter);
609
+ return () => h('div', [h(RouterView)]);
610
+ }
611
+ });
612
+
613
+ const app = createApp(TestApp);
614
+ app.mount(testContainer);
615
+ await nextTick();
616
+
617
+ expect(mountCount).toBe(1);
618
+ expect(testContainer.textContent).toContain('Mounted 1 times');
619
+
620
+ await testRouter.push('/route2');
621
+ await nextTick();
622
+
623
+ expect(mountCount).toBe(2);
624
+ expect(testContainer.textContent).toContain('Mounted 2 times');
625
+
626
+ await testRouter.push('/route1');
627
+ await nextTick();
628
+
629
+ expect(mountCount).toBe(3);
630
+ expect(testContainer.textContent).toContain('Mounted 3 times');
631
+
632
+ app.unmount();
633
+ testRouter.destroy();
634
+ });
635
+
636
+ it('should force re-render when compilePath changes for same route', async () => {
637
+ let mountCount = 0;
638
+ const TrackedComponent = defineComponent({
639
+ name: 'TrackedComponent',
640
+ setup() {
641
+ mountCount++;
642
+ return () =>
643
+ h('div', { class: 'tracked' }, `Mount #${mountCount}`);
644
+ }
645
+ });
646
+
647
+ const routes: RouteConfig[] = [
648
+ {
649
+ path: '/test',
650
+ component: TrackedComponent
651
+ }
652
+ ];
653
+
654
+ const testRouter = new Router({
655
+ root: '#test-app',
656
+ routes,
657
+ mode: RouterMode.memory,
658
+ base: new URL('http://localhost:8000/')
659
+ });
660
+
661
+ await testRouter.replace('/test');
662
+ await new Promise((resolve) => setTimeout(resolve, 10));
663
+
664
+ const TestApp = defineComponent({
665
+ setup() {
666
+ useProvideRouter(testRouter);
667
+ return () => h('div', [h(RouterView)]);
668
+ }
669
+ });
670
+
671
+ const app = createApp(TestApp);
672
+ app.mount(testContainer);
673
+ await nextTick();
674
+
675
+ expect(mountCount).toBe(1);
676
+ expect(testContainer.textContent).toContain('Mount #1');
677
+
678
+ const newRoutes: RouteConfig[] = [
679
+ {
680
+ path: '/test',
681
+ component: TrackedComponent,
682
+ meta: { updated: true }
683
+ }
684
+ ];
685
+
686
+ const newRouter = new Router({
687
+ root: '#test-app',
688
+ routes: newRoutes,
689
+ mode: RouterMode.memory,
690
+ base: new URL('http://localhost:8000/')
691
+ });
692
+
693
+ await newRouter.replace('/test');
694
+ await new Promise((resolve) => setTimeout(resolve, 10));
695
+
696
+ app.unmount();
697
+
698
+ const NewTestApp = defineComponent({
699
+ setup() {
700
+ useProvideRouter(newRouter);
701
+ return () => h('div', [h(RouterView)]);
702
+ }
703
+ });
704
+
705
+ const newApp = createApp(NewTestApp);
706
+ newApp.mount(testContainer);
707
+ await nextTick();
708
+
709
+ expect(mountCount).toBe(2);
710
+ expect(testContainer.textContent).toContain('Mount #2');
711
+
712
+ newApp.unmount();
713
+ newRouter.destroy();
714
+ });
715
+
716
+ it('should handle same component with same compilePath without unnecessary re-renders', async () => {
717
+ let mountCount = 0;
718
+ const TrackedComponent = defineComponent({
719
+ name: 'TrackedComponent',
720
+ setup() {
721
+ mountCount++;
722
+ return () => h('div', { class: 'tracked' }, `Component`);
723
+ }
724
+ });
725
+
726
+ const routes: RouteConfig[] = [
727
+ {
728
+ path: '/test',
729
+ component: TrackedComponent
730
+ }
731
+ ];
732
+
733
+ const testRouter = new Router({
734
+ root: '#test-app',
735
+ routes,
736
+ mode: RouterMode.memory,
737
+ base: new URL('http://localhost:8000/')
738
+ });
739
+
740
+ await testRouter.replace('/test');
741
+ await new Promise((resolve) => setTimeout(resolve, 10));
742
+
743
+ const TestApp = defineComponent({
744
+ setup() {
745
+ useProvideRouter(testRouter);
746
+ return () => h('div', [h(RouterView)]);
747
+ }
748
+ });
749
+
750
+ const app = createApp(TestApp);
751
+ app.mount(testContainer);
752
+ await nextTick();
753
+
754
+ expect(mountCount).toBe(1);
755
+
756
+ await testRouter.push('/');
757
+ await nextTick();
758
+ await testRouter.push('/test');
759
+ await nextTick();
760
+
761
+ expect(mountCount).toBe(1);
762
+
763
+ app.unmount();
764
+ testRouter.destroy();
765
+ });
766
+
767
+ it('should work with nested routes and compilePath keys', async () => {
768
+ let parentMountCount = 0;
769
+ let childMountCount = 0;
770
+
771
+ const ParentComponent = defineComponent({
772
+ name: 'ParentComponent',
773
+ setup() {
774
+ parentMountCount++;
775
+ return () =>
776
+ h('div', [
777
+ h('h1', `Parent Mount #${parentMountCount}`),
778
+ h(RouterView)
779
+ ]);
780
+ }
781
+ });
782
+
783
+ const ChildComponent = defineComponent({
784
+ name: 'ChildComponent',
785
+ setup() {
786
+ childMountCount++;
787
+ return () =>
788
+ h(
789
+ 'div',
790
+ { class: 'child' },
791
+ `Child Mount #${childMountCount}`
792
+ );
793
+ }
794
+ });
795
+
796
+ const nestedRoutes: RouteConfig[] = [
797
+ {
798
+ path: '/parent',
799
+ component: ParentComponent,
800
+ children: [
801
+ {
802
+ path: 'child',
803
+ component: ChildComponent
804
+ }
805
+ ]
806
+ }
807
+ ];
808
+
809
+ const nestedRouter = new Router({
810
+ root: '#test-app',
811
+ routes: nestedRoutes,
812
+ mode: RouterMode.memory,
813
+ base: new URL('http://localhost:8000/')
814
+ });
815
+
816
+ await nestedRouter.replace('/parent/child');
817
+ await new Promise((resolve) => setTimeout(resolve, 10));
818
+
819
+ const TestApp = defineComponent({
820
+ setup() {
821
+ useProvideRouter(nestedRouter);
822
+ return () => h('div', [h(RouterView)]);
823
+ }
824
+ });
825
+
826
+ const app = createApp(TestApp);
827
+ app.mount(testContainer);
828
+ await nextTick();
829
+
830
+ expect(parentMountCount).toBe(1);
831
+ expect(childMountCount).toBe(1);
832
+
833
+ expect(testContainer.textContent).toContain('Parent Mount #1');
834
+ expect(testContainer.textContent).toContain('Child Mount #1');
835
+
836
+ app.unmount();
837
+ nestedRouter.destroy();
838
+ });
839
+ });
599
840
  });
@@ -49,8 +49,11 @@ export const RouterView = defineComponent({
49
49
  ? resolveComponent(matchedRoute.component)
50
50
  : null;
51
51
 
52
- // Render the component or null if no match at this depth
53
- return component ? h(component) : null;
52
+ // Render the component with compilePath as key to force re-render when route config changes
53
+ // Using compilePath ensures component is recreated when navigating to different route configs
54
+ return component
55
+ ? h(component, { key: matchedRoute.compilePath })
56
+ : null;
54
57
  };
55
58
  }
56
59
  });