@esmx/router-vue 3.0.0-rc.84 → 3.0.0-rc.92
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.
- package/dist/plugin.mjs +18 -12
- package/dist/plugin.test.mjs +205 -3
- package/dist/router-link.mjs +14 -14
- package/dist/router-view.mjs +1 -1
- package/dist/router-view.test.mjs +220 -3
- package/dist/run-with-context.test.d.ts +1 -0
- package/dist/run-with-context.test.mjs +57 -0
- package/dist/use.d.ts +4 -10
- package/dist/use.mjs +15 -4
- package/dist/util.d.ts +12 -1
- package/dist/util.mjs +15 -1
- package/dist/util.test.d.ts +3 -0
- package/dist/util.test.mjs +228 -7
- package/package.json +3 -3
- package/src/plugin.test.ts +252 -7
- package/src/plugin.ts +18 -12
- package/src/router-link.ts +16 -15
- package/src/router-view.test.ts +281 -40
- package/src/router-view.ts +5 -2
- package/src/run-with-context.test.ts +64 -0
- package/src/use.ts +21 -17
- package/src/util.test.ts +294 -9
- package/src/util.ts +31 -1
package/dist/plugin.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RouterLink } from "./router-link.mjs";
|
|
2
2
|
import { RouterView } from "./router-view.mjs";
|
|
3
3
|
import { getRoute, getRouter } from "./use.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { defineRouterProperties, isVue2 } from "./util.mjs";
|
|
5
5
|
export const RouterPlugin = {
|
|
6
6
|
/**
|
|
7
7
|
* Install the router plugin.
|
|
@@ -17,18 +17,24 @@ export const RouterPlugin = {
|
|
|
17
17
|
if (!target) {
|
|
18
18
|
throw new Error("[@esmx/router-vue] Invalid Vue app instance");
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
if (isVue2) {
|
|
21
|
+
defineRouterProperties(
|
|
22
|
+
target,
|
|
23
|
+
function() {
|
|
24
|
+
return getRouter(this);
|
|
25
|
+
},
|
|
26
|
+
function() {
|
|
27
|
+
return getRoute(this);
|
|
24
28
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
);
|
|
30
|
+
} else {
|
|
31
|
+
const throwError = () => {
|
|
32
|
+
throw new Error(
|
|
33
|
+
"[@esmx/router-vue] Router not provided. Please call useProvideRouter() in your root component setup."
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
defineRouterProperties(target, throwError, throwError, true);
|
|
37
|
+
}
|
|
32
38
|
vueApp.component("RouterLink", RouterLink);
|
|
33
39
|
vueApp.component("RouterView", RouterView);
|
|
34
40
|
}
|
package/dist/plugin.test.mjs
CHANGED
|
@@ -126,7 +126,7 @@ describe("plugin.ts - RouterPlugin", () => {
|
|
|
126
126
|
expect(routeDescriptor == null ? void 0 : routeDescriptor.get).toBeDefined();
|
|
127
127
|
expect(typeof (routeDescriptor == null ? void 0 : routeDescriptor.get)).toBe("function");
|
|
128
128
|
expect(routeDescriptor == null ? void 0 : routeDescriptor.enumerable).toBe(false);
|
|
129
|
-
expect(routeDescriptor == null ? void 0 : routeDescriptor.configurable).toBe(
|
|
129
|
+
expect(routeDescriptor == null ? void 0 : routeDescriptor.configurable).toBe(true);
|
|
130
130
|
});
|
|
131
131
|
it("should provide consistent $router instance across components", async () => {
|
|
132
132
|
const ChildComponent = defineComponent({
|
|
@@ -374,6 +374,208 @@ describe("plugin.ts - RouterPlugin", () => {
|
|
|
374
374
|
expect(typeof routerViewComponent.setup).toBe("function");
|
|
375
375
|
});
|
|
376
376
|
});
|
|
377
|
+
describe("$router and $route Access", () => {
|
|
378
|
+
it("should throw error when accessing $router without useProvideRouter", () => {
|
|
379
|
+
app = createApp({
|
|
380
|
+
render: () => h("div", "Test App")
|
|
381
|
+
});
|
|
382
|
+
app.use(RouterPlugin);
|
|
383
|
+
const globalProperties = app.config.globalProperties;
|
|
384
|
+
expect(() => {
|
|
385
|
+
globalProperties.$router;
|
|
386
|
+
}).toThrow(
|
|
387
|
+
"[@esmx/router-vue] Router not provided. Please call useProvideRouter() in your root component setup."
|
|
388
|
+
);
|
|
389
|
+
});
|
|
390
|
+
it("should throw error when accessing $route without useProvideRouter", () => {
|
|
391
|
+
app = createApp({
|
|
392
|
+
render: () => h("div", "Test App")
|
|
393
|
+
});
|
|
394
|
+
app.use(RouterPlugin);
|
|
395
|
+
const globalProperties = app.config.globalProperties;
|
|
396
|
+
expect(() => {
|
|
397
|
+
globalProperties.$route;
|
|
398
|
+
}).toThrow(
|
|
399
|
+
"[@esmx/router-vue] Router not provided. Please call useProvideRouter() in your root component setup."
|
|
400
|
+
);
|
|
401
|
+
});
|
|
402
|
+
it("should override default getters after useProvideRouter is called", async () => {
|
|
403
|
+
app = createApp({
|
|
404
|
+
setup() {
|
|
405
|
+
useProvideRouter(router);
|
|
406
|
+
return () => h("div", "Test App");
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
app.use(RouterPlugin);
|
|
410
|
+
app.mount(container);
|
|
411
|
+
await nextTick();
|
|
412
|
+
const globalProperties = app.config.globalProperties;
|
|
413
|
+
expect(() => {
|
|
414
|
+
globalProperties.$router;
|
|
415
|
+
}).not.toThrow();
|
|
416
|
+
expect(() => {
|
|
417
|
+
globalProperties.$route;
|
|
418
|
+
}).not.toThrow();
|
|
419
|
+
});
|
|
420
|
+
it("should return correct router instance via $router", async () => {
|
|
421
|
+
let capturedRouter = null;
|
|
422
|
+
const TestComponent = defineComponent({
|
|
423
|
+
mounted() {
|
|
424
|
+
capturedRouter = this.$router;
|
|
425
|
+
},
|
|
426
|
+
render() {
|
|
427
|
+
return h("div", "Test");
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
app = createApp({
|
|
431
|
+
setup() {
|
|
432
|
+
useProvideRouter(router);
|
|
433
|
+
return () => h(TestComponent);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
app.use(RouterPlugin);
|
|
437
|
+
app.mount(container);
|
|
438
|
+
await nextTick();
|
|
439
|
+
expect(capturedRouter).toBeDefined();
|
|
440
|
+
expect(capturedRouter).toBeInstanceOf(Router);
|
|
441
|
+
expect(capturedRouter.route.path).toBe("/");
|
|
442
|
+
});
|
|
443
|
+
it("should return correct route via $route", async () => {
|
|
444
|
+
var _a;
|
|
445
|
+
let capturedRoute = null;
|
|
446
|
+
const TestComponent = defineComponent({
|
|
447
|
+
mounted() {
|
|
448
|
+
capturedRoute = this.$route;
|
|
449
|
+
},
|
|
450
|
+
render() {
|
|
451
|
+
return h("div", "Test");
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
app = createApp({
|
|
455
|
+
setup() {
|
|
456
|
+
useProvideRouter(router);
|
|
457
|
+
return () => h(TestComponent);
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
app.use(RouterPlugin);
|
|
461
|
+
app.mount(container);
|
|
462
|
+
await nextTick();
|
|
463
|
+
expect(capturedRoute).toBeDefined();
|
|
464
|
+
expect(capturedRoute.path).toBe("/");
|
|
465
|
+
expect((_a = capturedRoute.meta) == null ? void 0 : _a.title).toBe(
|
|
466
|
+
"Home"
|
|
467
|
+
);
|
|
468
|
+
});
|
|
469
|
+
it("should update $route when navigation occurs", async () => {
|
|
470
|
+
const routes = [];
|
|
471
|
+
const TestComponent = defineComponent({
|
|
472
|
+
mounted() {
|
|
473
|
+
routes.push(this.$route.path);
|
|
474
|
+
},
|
|
475
|
+
updated() {
|
|
476
|
+
routes.push(this.$route.path);
|
|
477
|
+
},
|
|
478
|
+
render() {
|
|
479
|
+
return h("div", this.$route.path);
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
app = createApp({
|
|
483
|
+
setup() {
|
|
484
|
+
useProvideRouter(router);
|
|
485
|
+
return () => h(TestComponent);
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
app.use(RouterPlugin);
|
|
489
|
+
app.mount(container);
|
|
490
|
+
await nextTick();
|
|
491
|
+
expect(routes).toContain("/");
|
|
492
|
+
await router.push("/about");
|
|
493
|
+
await nextTick();
|
|
494
|
+
expect(router.route.path).toBe("/about");
|
|
495
|
+
});
|
|
496
|
+
it("should provide same $router instance in nested components", async () => {
|
|
497
|
+
const routerInstances = [];
|
|
498
|
+
const ChildComponent = defineComponent({
|
|
499
|
+
mounted() {
|
|
500
|
+
routerInstances.push(this.$router);
|
|
501
|
+
},
|
|
502
|
+
render() {
|
|
503
|
+
return h("div", "Child");
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
const ParentComponent = defineComponent({
|
|
507
|
+
mounted() {
|
|
508
|
+
routerInstances.push(this.$router);
|
|
509
|
+
},
|
|
510
|
+
render() {
|
|
511
|
+
return h("div", [h("span", "Parent"), h(ChildComponent)]);
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
app = createApp({
|
|
515
|
+
setup() {
|
|
516
|
+
useProvideRouter(router);
|
|
517
|
+
return () => h(ParentComponent);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
app.use(RouterPlugin);
|
|
521
|
+
app.mount(container);
|
|
522
|
+
await nextTick();
|
|
523
|
+
expect(routerInstances.length).toBe(2);
|
|
524
|
+
expect(routerInstances[0]).toBe(routerInstances[1]);
|
|
525
|
+
});
|
|
526
|
+
it("should allow navigation via $router.push", async () => {
|
|
527
|
+
let capturedRouter = null;
|
|
528
|
+
const TestComponent = defineComponent({
|
|
529
|
+
mounted() {
|
|
530
|
+
capturedRouter = this.$router;
|
|
531
|
+
},
|
|
532
|
+
render() {
|
|
533
|
+
return h("div", "Test");
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
app = createApp({
|
|
537
|
+
setup() {
|
|
538
|
+
useProvideRouter(router);
|
|
539
|
+
return () => h(TestComponent);
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
app.use(RouterPlugin);
|
|
543
|
+
app.mount(container);
|
|
544
|
+
await nextTick();
|
|
545
|
+
expect(capturedRouter).toBeDefined();
|
|
546
|
+
const routerInstance = capturedRouter;
|
|
547
|
+
expect(typeof routerInstance.push).toBe("function");
|
|
548
|
+
await routerInstance.push("/about");
|
|
549
|
+
await nextTick();
|
|
550
|
+
expect(router.route.path).toBe("/about");
|
|
551
|
+
});
|
|
552
|
+
it("should allow navigation via $router.replace", async () => {
|
|
553
|
+
let capturedRouter = null;
|
|
554
|
+
const TestComponent = defineComponent({
|
|
555
|
+
mounted() {
|
|
556
|
+
capturedRouter = this.$router;
|
|
557
|
+
},
|
|
558
|
+
render() {
|
|
559
|
+
return h("div", "Test");
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
app = createApp({
|
|
563
|
+
setup() {
|
|
564
|
+
useProvideRouter(router);
|
|
565
|
+
return () => h(TestComponent);
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
app.use(RouterPlugin);
|
|
569
|
+
app.mount(container);
|
|
570
|
+
await nextTick();
|
|
571
|
+
expect(capturedRouter).toBeDefined();
|
|
572
|
+
const routerInstance = capturedRouter;
|
|
573
|
+
expect(typeof routerInstance.replace).toBe("function");
|
|
574
|
+
await routerInstance.replace("/about");
|
|
575
|
+
await nextTick();
|
|
576
|
+
expect(router.route.path).toBe("/about");
|
|
577
|
+
});
|
|
578
|
+
});
|
|
377
579
|
describe("Advanced Plugin Features", () => {
|
|
378
580
|
it("should support property descriptor configuration", () => {
|
|
379
581
|
const testApp = {
|
|
@@ -394,10 +596,10 @@ describe("plugin.ts - RouterPlugin", () => {
|
|
|
394
596
|
);
|
|
395
597
|
expect(routerDescriptor == null ? void 0 : routerDescriptor.get).toBeDefined();
|
|
396
598
|
expect(routerDescriptor == null ? void 0 : routerDescriptor.enumerable).toBe(false);
|
|
397
|
-
expect(routerDescriptor == null ? void 0 : routerDescriptor.configurable).toBe(
|
|
599
|
+
expect(routerDescriptor == null ? void 0 : routerDescriptor.configurable).toBe(true);
|
|
398
600
|
expect(routeDescriptor == null ? void 0 : routeDescriptor.get).toBeDefined();
|
|
399
601
|
expect(routeDescriptor == null ? void 0 : routeDescriptor.enumerable).toBe(false);
|
|
400
|
-
expect(routeDescriptor == null ? void 0 : routeDescriptor.configurable).toBe(
|
|
602
|
+
expect(routeDescriptor == null ? void 0 : routeDescriptor.configurable).toBe(true);
|
|
401
603
|
});
|
|
402
604
|
it("should handle different app instance structures", () => {
|
|
403
605
|
const minimalApp = {
|
package/dist/router-link.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineComponent, h } from "vue";
|
|
2
2
|
import { useLink } from "./use.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { isVue2 } from "./util.mjs";
|
|
4
4
|
export const RouterLink = defineComponent({
|
|
5
5
|
name: "RouterLink",
|
|
6
6
|
props: {
|
|
@@ -83,17 +83,19 @@ export const RouterLink = defineComponent({
|
|
|
83
83
|
},
|
|
84
84
|
setup(props, context) {
|
|
85
85
|
const link = useLink(props);
|
|
86
|
-
if (
|
|
86
|
+
if (isVue2) {
|
|
87
87
|
return () => {
|
|
88
88
|
var _a, _b;
|
|
89
|
+
const { class: className, ...attributes } = link.value.attributes;
|
|
89
90
|
return h(
|
|
90
91
|
link.value.tag,
|
|
91
92
|
{
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
attrs: {
|
|
94
|
+
...attributes,
|
|
95
|
+
...context.attrs
|
|
96
|
+
},
|
|
97
|
+
class: className,
|
|
98
|
+
on: link.value.createEventHandlers()
|
|
97
99
|
},
|
|
98
100
|
(_b = (_a = context.slots).default) == null ? void 0 : _b.call(_a)
|
|
99
101
|
);
|
|
@@ -101,16 +103,14 @@ export const RouterLink = defineComponent({
|
|
|
101
103
|
}
|
|
102
104
|
return () => {
|
|
103
105
|
var _a, _b;
|
|
104
|
-
const { class: className, ...attributes } = link.value.attributes;
|
|
105
106
|
return h(
|
|
106
107
|
link.value.tag,
|
|
107
108
|
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
on: link.value.createEventHandlers()
|
|
109
|
+
...link.value.attributes,
|
|
110
|
+
...context.attrs,
|
|
111
|
+
...link.value.createEventHandlers(
|
|
112
|
+
(name) => "on".concat(name.charAt(0).toUpperCase()).concat(name.slice(1))
|
|
113
|
+
)
|
|
114
114
|
},
|
|
115
115
|
(_b = (_a = context.slots).default) == null ? void 0 : _b.call(_a)
|
|
116
116
|
);
|
package/dist/router-view.mjs
CHANGED
|
@@ -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
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
createApp,
|
|
4
|
+
getCurrentInstance,
|
|
5
|
+
h,
|
|
6
|
+
inject,
|
|
7
|
+
nextTick,
|
|
8
|
+
provide
|
|
9
|
+
} from "vue";
|
|
10
|
+
describe("app.runWithContext()", () => {
|
|
11
|
+
it("should exist on Vue app", () => {
|
|
12
|
+
const app = createApp({ render: () => h("div") });
|
|
13
|
+
expect(typeof app.runWithContext).toBe("function");
|
|
14
|
+
});
|
|
15
|
+
it("should enable inject to read provided value within context", () => {
|
|
16
|
+
const KEY = Symbol("ctx-key");
|
|
17
|
+
const app = createApp({ render: () => h("div") });
|
|
18
|
+
app.provide(KEY, 42);
|
|
19
|
+
const value = app.runWithContext(() => inject(KEY));
|
|
20
|
+
expect(value).toBe(42);
|
|
21
|
+
});
|
|
22
|
+
it("should not read value provided in root setup via runWithContext", async () => {
|
|
23
|
+
const KEY = Symbol("ctx-key-setup");
|
|
24
|
+
const app = createApp({
|
|
25
|
+
setup() {
|
|
26
|
+
provide(KEY, 7);
|
|
27
|
+
return () => h("div");
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const container = document.createElement("div");
|
|
31
|
+
document.body.appendChild(container);
|
|
32
|
+
app.mount(container);
|
|
33
|
+
await nextTick();
|
|
34
|
+
const value = app.runWithContext(() => inject(KEY));
|
|
35
|
+
expect(value).toBeUndefined();
|
|
36
|
+
app.unmount();
|
|
37
|
+
container.remove();
|
|
38
|
+
});
|
|
39
|
+
it("should read app-level provide set inside setup via appContext", async () => {
|
|
40
|
+
const KEY = Symbol("ctx-key-setup-app");
|
|
41
|
+
const app = createApp({
|
|
42
|
+
setup() {
|
|
43
|
+
const appInst = getCurrentInstance().appContext.app;
|
|
44
|
+
appInst.provide(KEY, 9);
|
|
45
|
+
return () => h("div");
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
const container = document.createElement("div");
|
|
49
|
+
document.body.appendChild(container);
|
|
50
|
+
app.mount(container);
|
|
51
|
+
await nextTick();
|
|
52
|
+
const value = app.runWithContext(() => inject(KEY));
|
|
53
|
+
expect(value).toBe(9);
|
|
54
|
+
app.unmount();
|
|
55
|
+
container.remove();
|
|
56
|
+
});
|
|
57
|
+
});
|
package/dist/use.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface VueInstance {
|
|
|
9
9
|
* This is a lower-level function used internally by useRouter().
|
|
10
10
|
* Use this in Options API, use useRouter() in Composition API.
|
|
11
11
|
*
|
|
12
|
-
* @param instance - Vue component instance
|
|
12
|
+
* @param instance - Vue component instance
|
|
13
13
|
* @returns Router instance
|
|
14
14
|
* @throws {Error} If router context is not found
|
|
15
15
|
*
|
|
@@ -31,18 +31,15 @@ export interface VueInstance {
|
|
|
31
31
|
* }
|
|
32
32
|
* }
|
|
33
33
|
* });
|
|
34
|
-
*
|
|
35
|
-
* // Can also be called without instance (uses getCurrentInstance internally)
|
|
36
|
-
* const router = getRouter(); // Works in globalProperties getters
|
|
37
34
|
* ```
|
|
38
35
|
*/
|
|
39
|
-
export declare function getRouter(instance
|
|
36
|
+
export declare function getRouter(instance: VueInstance): Router;
|
|
40
37
|
/**
|
|
41
38
|
* Get current route from a Vue component instance.
|
|
42
39
|
* This is a lower-level function used internally by useRoute().
|
|
43
40
|
* Use this in Options API, use useRoute() in Composition API.
|
|
44
41
|
*
|
|
45
|
-
* @param instance - Vue component instance
|
|
42
|
+
* @param instance - Vue component instance
|
|
46
43
|
* @returns Current route object
|
|
47
44
|
* @throws {Error} If router context is not found
|
|
48
45
|
*
|
|
@@ -64,12 +61,9 @@ export declare function getRouter(instance?: VueInstance): Router;
|
|
|
64
61
|
* }
|
|
65
62
|
* }
|
|
66
63
|
* });
|
|
67
|
-
*
|
|
68
|
-
* // Can also be called without instance (uses getCurrentInstance internally)
|
|
69
|
-
* const route = getRoute(); // Works in globalProperties getters
|
|
70
64
|
* ```
|
|
71
65
|
*/
|
|
72
|
-
export declare function getRoute(instance
|
|
66
|
+
export declare function getRoute(instance: VueInstance): Route;
|
|
73
67
|
/**
|
|
74
68
|
* Get the router instance in a Vue component.
|
|
75
69
|
* Must be called within setup() or other composition functions.
|