reactive-route 0.0.1-alpha.26 → 0.0.1-alpha.27

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.
Files changed (49) hide show
  1. package/LICENSE +1 -1
  2. package/dist/cjs/adapters/vue/index.js +39 -0
  3. package/dist/cjs/adapters/vue/package.json +1 -0
  4. package/dist/cjs/vue/index.js +116 -0
  5. package/dist/cjs/vue/package.json +1 -0
  6. package/dist/esm/adapters/vue/index.js +18 -0
  7. package/dist/esm/adapters/vue/package.json +1 -0
  8. package/dist/esm/vue/index.js +93 -0
  9. package/dist/esm/vue/package.json +1 -0
  10. package/e2e/app.test.ts +130 -0
  11. package/e2e/teardown.ts +12 -0
  12. package/package.json +22 -7
  13. package/playwright.config.ts +52 -0
  14. package/vitepress/.vitepress/cache/deps/_metadata.json +52 -0
  15. package/vitepress/.vitepress/cache/deps/chunk-FL23S3EK.js +12705 -0
  16. package/vitepress/.vitepress/cache/deps/chunk-FL23S3EK.js.map +7 -0
  17. package/vitepress/.vitepress/cache/deps/chunk-VGAXUAUJ.js +9952 -0
  18. package/vitepress/.vitepress/cache/deps/chunk-VGAXUAUJ.js.map +7 -0
  19. package/vitepress/.vitepress/cache/deps/package.json +3 -0
  20. package/vitepress/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +3844 -0
  21. package/vitepress/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  22. package/vitepress/.vitepress/cache/deps/vitepress___@vueuse_core.js +588 -0
  23. package/vitepress/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  24. package/vitepress/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1153 -0
  25. package/vitepress/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  26. package/vitepress/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1665 -0
  27. package/vitepress/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  28. package/vitepress/.vitepress/cache/deps/vitepress___minisearch.js +1812 -0
  29. package/vitepress/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  30. package/vitepress/.vitepress/cache/deps/vue.js +342 -0
  31. package/vitepress/.vitepress/cache/deps/vue.js.map +7 -0
  32. package/vitepress/.vitepress/config.mts +72 -0
  33. package/vitepress/.vitepress/theme/custom.css +9 -0
  34. package/vitepress/.vitepress/theme/index.ts +5 -0
  35. package/vitepress/examples/preact.md +22 -0
  36. package/vitepress/examples/react.md +22 -0
  37. package/vitepress/examples/solid.md +21 -0
  38. package/vitepress/file.svg +79 -0
  39. package/vitepress/guide/advanced.md +131 -0
  40. package/vitepress/guide/getting-started.md +139 -0
  41. package/vitepress/guide/index.md +44 -0
  42. package/vitepress/guide/preact.md +33 -0
  43. package/vitepress/guide/react.md +33 -0
  44. package/vitepress/guide/router-component.md +67 -0
  45. package/vitepress/guide/router-configuration.md +185 -0
  46. package/vitepress/guide/routes-configuration.md +191 -0
  47. package/vitepress/guide/solid.md +68 -0
  48. package/vitepress/guide/ssr.md +70 -0
  49. package/vitepress/index.md +29 -0
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Dmitry
3
+ Copyright (c) 2025-present Dmitry
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/adapters/vue.ts
21
+ var vue_exports = {};
22
+ __export(vue_exports, {
23
+ adapters: () => adapters
24
+ });
25
+ module.exports = __toCommonJS(vue_exports);
26
+ var import_vue = require("vue");
27
+ var adapters = {
28
+ batch: (cb) => cb(),
29
+ autorun: import_vue.watchEffect,
30
+ replaceObject: (obj, newObj) => {
31
+ for (const variableKey in obj) {
32
+ if (obj.hasOwnProperty(variableKey)) {
33
+ delete obj[variableKey];
34
+ }
35
+ }
36
+ Object.assign(obj, newObj);
37
+ },
38
+ makeObservable: import_vue.reactive
39
+ };
@@ -0,0 +1 @@
1
+ {"type": "commonjs"}
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/vue/index.ts
21
+ var vue_exports = {};
22
+ __export(vue_exports, {
23
+ Router: () => Router
24
+ });
25
+ module.exports = __toCommonJS(vue_exports);
26
+
27
+ // packages/vue/Router.ts
28
+ var import_reactive_route = require("reactive-route");
29
+ var import_vue = require("vue");
30
+ var Router = (0, import_vue.defineComponent)({
31
+ name: "ReactiveRouteRouter",
32
+ props: {
33
+ // We keep the type generic via TS, but at runtime it's just any
34
+ router: { type: Object, required: true },
35
+ beforeSetPageComponent: { type: Function, required: false },
36
+ beforeUpdatePageComponent: { type: Function, required: false },
37
+ beforeMount: { type: Function, required: false }
38
+ },
39
+ // TS helper, runtime ignored
40
+ setup(props) {
41
+ const disposerRef = (0, import_vue.reactive)({ current: null });
42
+ const config = props.router.adapters.makeObservable({
43
+ loadedComponentName: void 0,
44
+ loadedComponentPage: void 0,
45
+ currentProps: {}
46
+ });
47
+ function redirectOnHistoryPop() {
48
+ if (!import_reactive_route.history) return;
49
+ import_reactive_route.history.listen((params) => {
50
+ if (params.action !== "POP") return;
51
+ const previousRoutePathname = props.router.routesHistory[props.router.routesHistory.length - 2];
52
+ if (previousRoutePathname === params.location.pathname) {
53
+ props.router.routesHistory.pop();
54
+ }
55
+ void props.router.restoreFromURL({
56
+ pathname: import_reactive_route.history.location.pathname,
57
+ noHistoryPush: true
58
+ });
59
+ });
60
+ }
61
+ function setLoadedComponent() {
62
+ const currentRouteName = props.router.currentRoute.name;
63
+ const currentRoutePage = props.router.currentRoute.pageId;
64
+ const componentConfig = props.router.routes[currentRouteName];
65
+ let preventRedirect = false;
66
+ if (props.router.isRedirecting) preventRedirect = true;
67
+ else if (config.loadedComponentName === currentRouteName) {
68
+ preventRedirect = true;
69
+ } else if (config.loadedComponentPage != null && currentRouteName != null) {
70
+ if (config.loadedComponentPage === currentRoutePage) {
71
+ props.router.adapters.replaceObject(
72
+ config.currentProps,
73
+ "props" in componentConfig ? componentConfig.props : {}
74
+ );
75
+ preventRedirect = true;
76
+ }
77
+ }
78
+ if (preventRedirect) return;
79
+ props.router.adapters.batch(() => {
80
+ if (config.loadedComponentName) {
81
+ props.beforeUpdatePageComponent?.();
82
+ }
83
+ props.beforeSetPageComponent?.(componentConfig);
84
+ props.router.adapters.batch(() => {
85
+ props.router.adapters.replaceObject(
86
+ config.currentProps,
87
+ "props" in componentConfig ? componentConfig.props : {}
88
+ );
89
+ config.loadedComponentName = currentRouteName;
90
+ config.loadedComponentPage = componentConfig.pageId;
91
+ });
92
+ });
93
+ }
94
+ setLoadedComponent();
95
+ (0, import_vue.onMounted)(() => {
96
+ props.beforeMount?.();
97
+ redirectOnHistoryPop();
98
+ if (props.router.adapters.immediateSetComponent) {
99
+ props.router.adapters.batch(() => {
100
+ setLoadedComponent();
101
+ });
102
+ }
103
+ const disposer = props.router.adapters.autorun(() => setLoadedComponent());
104
+ if (typeof disposer === "function") disposerRef.current = disposer;
105
+ });
106
+ (0, import_vue.onBeforeUnmount)(() => {
107
+ disposerRef.current?.();
108
+ });
109
+ return () => {
110
+ if (!config.loadedComponentName) return null;
111
+ const LoadedComponent = props.router.routes[config.loadedComponentName]?.component || null;
112
+ if (!LoadedComponent) return null;
113
+ return (0, import_vue.h)(LoadedComponent, { ...config.currentProps || {}, router: props.router });
114
+ };
115
+ }
116
+ });
@@ -0,0 +1 @@
1
+ {"type": "commonjs"}
@@ -0,0 +1,18 @@
1
+ // packages/adapters/vue.ts
2
+ import { reactive, watchEffect } from "vue";
3
+ var adapters = {
4
+ batch: (cb) => cb(),
5
+ autorun: watchEffect,
6
+ replaceObject: (obj, newObj) => {
7
+ for (const variableKey in obj) {
8
+ if (obj.hasOwnProperty(variableKey)) {
9
+ delete obj[variableKey];
10
+ }
11
+ }
12
+ Object.assign(obj, newObj);
13
+ },
14
+ makeObservable: reactive
15
+ };
16
+ export {
17
+ adapters
18
+ };
@@ -0,0 +1 @@
1
+ {"type": "module"}
@@ -0,0 +1,93 @@
1
+ // packages/vue/Router.ts
2
+ import { history } from "reactive-route";
3
+ import { defineComponent, h, onBeforeUnmount, onMounted, reactive } from "vue";
4
+ var Router = defineComponent({
5
+ name: "ReactiveRouteRouter",
6
+ props: {
7
+ // We keep the type generic via TS, but at runtime it's just any
8
+ router: { type: Object, required: true },
9
+ beforeSetPageComponent: { type: Function, required: false },
10
+ beforeUpdatePageComponent: { type: Function, required: false },
11
+ beforeMount: { type: Function, required: false }
12
+ },
13
+ // TS helper, runtime ignored
14
+ setup(props) {
15
+ const disposerRef = reactive({ current: null });
16
+ const config = props.router.adapters.makeObservable({
17
+ loadedComponentName: void 0,
18
+ loadedComponentPage: void 0,
19
+ currentProps: {}
20
+ });
21
+ function redirectOnHistoryPop() {
22
+ if (!history) return;
23
+ history.listen((params) => {
24
+ if (params.action !== "POP") return;
25
+ const previousRoutePathname = props.router.routesHistory[props.router.routesHistory.length - 2];
26
+ if (previousRoutePathname === params.location.pathname) {
27
+ props.router.routesHistory.pop();
28
+ }
29
+ void props.router.restoreFromURL({
30
+ pathname: history.location.pathname,
31
+ noHistoryPush: true
32
+ });
33
+ });
34
+ }
35
+ function setLoadedComponent() {
36
+ const currentRouteName = props.router.currentRoute.name;
37
+ const currentRoutePage = props.router.currentRoute.pageId;
38
+ const componentConfig = props.router.routes[currentRouteName];
39
+ let preventRedirect = false;
40
+ if (props.router.isRedirecting) preventRedirect = true;
41
+ else if (config.loadedComponentName === currentRouteName) {
42
+ preventRedirect = true;
43
+ } else if (config.loadedComponentPage != null && currentRouteName != null) {
44
+ if (config.loadedComponentPage === currentRoutePage) {
45
+ props.router.adapters.replaceObject(
46
+ config.currentProps,
47
+ "props" in componentConfig ? componentConfig.props : {}
48
+ );
49
+ preventRedirect = true;
50
+ }
51
+ }
52
+ if (preventRedirect) return;
53
+ props.router.adapters.batch(() => {
54
+ if (config.loadedComponentName) {
55
+ props.beforeUpdatePageComponent?.();
56
+ }
57
+ props.beforeSetPageComponent?.(componentConfig);
58
+ props.router.adapters.batch(() => {
59
+ props.router.adapters.replaceObject(
60
+ config.currentProps,
61
+ "props" in componentConfig ? componentConfig.props : {}
62
+ );
63
+ config.loadedComponentName = currentRouteName;
64
+ config.loadedComponentPage = componentConfig.pageId;
65
+ });
66
+ });
67
+ }
68
+ setLoadedComponent();
69
+ onMounted(() => {
70
+ props.beforeMount?.();
71
+ redirectOnHistoryPop();
72
+ if (props.router.adapters.immediateSetComponent) {
73
+ props.router.adapters.batch(() => {
74
+ setLoadedComponent();
75
+ });
76
+ }
77
+ const disposer = props.router.adapters.autorun(() => setLoadedComponent());
78
+ if (typeof disposer === "function") disposerRef.current = disposer;
79
+ });
80
+ onBeforeUnmount(() => {
81
+ disposerRef.current?.();
82
+ });
83
+ return () => {
84
+ if (!config.loadedComponentName) return null;
85
+ const LoadedComponent = props.router.routes[config.loadedComponentName]?.component || null;
86
+ if (!LoadedComponent) return null;
87
+ return h(LoadedComponent, { ...config.currentProps || {}, router: props.router });
88
+ };
89
+ }
90
+ });
91
+ export {
92
+ Router
93
+ };
@@ -0,0 +1 @@
1
+ {"type": "module"}
@@ -0,0 +1,130 @@
1
+ import { expect, test } from '@playwright/test';
2
+
3
+ const h1 = 'h1';
4
+
5
+ test.describe('App routing E2E', () => {
6
+ test('home redirects to /static', async ({ page }) => {
7
+ await page.goto('/');
8
+ await page.waitForLoadState('networkidle');
9
+ await expect(page).toHaveURL('/static');
10
+
11
+ await expect(page.locator(h1)).toHaveText('Static Page');
12
+ });
13
+
14
+ test('redirect from /static to /page/example works', async ({ page }) => {
15
+ await page.goto('/static');
16
+ await page.waitForLoadState('networkidle');
17
+ await expect(page).toHaveURL('/static');
18
+
19
+ await expect(page.locator(h1)).toHaveText('Static Page');
20
+
21
+ await page.getByText('Go to Dynamic Page').click();
22
+ await page.waitForLoadState('networkidle');
23
+ await expect(page).toHaveURL('/page/example');
24
+
25
+ await expect(page.locator(h1)).toHaveText('Dynamic Page');
26
+ });
27
+
28
+ test('dynamic route with valid param renders and shows params', async ({ page }) => {
29
+ await page.goto('/page/example');
30
+ await page.waitForLoadState('networkidle');
31
+ await expect(page).toHaveURL('/page/example');
32
+
33
+ const preLocator = page.locator('.dynamic-page pre').nth(1);
34
+
35
+ await expect(page.locator(h1)).toHaveText('Dynamic Page');
36
+ await expect(preLocator).toContainText('"foo": "example"');
37
+
38
+ await page.getByText('Go to random dynamic value').click();
39
+
40
+ const randomFoo = ((await preLocator.textContent()) || '').match(/foo": "(\d+)"/)?.[1];
41
+
42
+ await expect(preLocator).toContainText(`"foo": "${randomFoo}"`);
43
+ await expect(page).toHaveURL(`/page/${randomFoo}`);
44
+ });
45
+
46
+ test('redirect from /static to /query works', async ({ page }) => {
47
+ await page.goto('/static');
48
+ await page.waitForLoadState('networkidle');
49
+ await expect(page).toHaveURL('/static');
50
+
51
+ await expect(page.locator(h1)).toHaveText('Static Page');
52
+
53
+ await page.getByText('Go to Query Page').click();
54
+ await page.waitForLoadState('networkidle');
55
+ await expect(page).toHaveURL('/query?foo=example');
56
+
57
+ await expect(page.locator(h1)).toHaveText('Query Page');
58
+ });
59
+
60
+ test('query route shows params', async ({ page }) => {
61
+ await page.goto('/query?foo=1');
62
+ await page.waitForLoadState('networkidle');
63
+ await expect(page).toHaveURL('/query');
64
+
65
+ const preLocator = page.locator('.query-page pre').nth(1);
66
+
67
+ await expect(page.locator(h1)).toHaveText('Query Page');
68
+ await expect(preLocator).toContainText('{}');
69
+
70
+ await page.getByText('Go to random query value').click();
71
+
72
+ const randomFoo = ((await preLocator.textContent()) || '').match(/foo": "(\d+)"/)?.[1];
73
+
74
+ await expect(preLocator).toContainText(`"foo": "${randomFoo}"`);
75
+ await expect(page).toHaveURL(`/query?foo=${randomFoo}`);
76
+
77
+ await page.goto('/query?foo=bar');
78
+ await page.waitForLoadState('networkidle');
79
+ await expect(page).toHaveURL('/query?foo=bar');
80
+ });
81
+
82
+ test('invalid routes redirect to 404', async ({ page }) => {
83
+ await page.goto('/page/ab');
84
+ await page.waitForLoadState('networkidle');
85
+
86
+ await expect(page.locator('.error-code')).toHaveText('404');
87
+ await expect(page.locator(h1)).toHaveText('Page Not Found');
88
+ await expect(page).toHaveURL('/error404');
89
+
90
+ await page.goto('/ab');
91
+ await page.waitForLoadState('networkidle');
92
+
93
+ await expect(page.locator('.error-code')).toHaveText('404');
94
+ await expect(page.locator(h1)).toHaveText('Page Not Found');
95
+ await expect(page).toHaveURL('/error404');
96
+ });
97
+
98
+ test('prevent: coming from Dynamic to Prevent redirects to Static (beforeEnter)', async ({
99
+ page,
100
+ }) => {
101
+ await page.goto('/page/example');
102
+ await page.waitForLoadState('networkidle');
103
+
104
+ await expect(page.locator(h1)).toHaveText('Dynamic Page');
105
+
106
+ await page
107
+ .getByRole('button', { name: 'Go to Prevent Page (will redirect to Static)' })
108
+ .click();
109
+ await page.waitForLoadState('networkidle');
110
+
111
+ await expect(page.locator(h1)).toHaveText('Static Page');
112
+ await expect(page).toHaveURL('/static');
113
+ });
114
+
115
+ test('prevent: from Prevent trying to go to Query is blocked (beforeLeave) and URL remains the same', async ({
116
+ page,
117
+ }) => {
118
+ await page.goto('/prevent');
119
+ await page.waitForLoadState('networkidle');
120
+
121
+ await expect(page.locator(h1)).toHaveText('Prevent Redirect Page');
122
+
123
+ await page.getByRole('button', { name: 'Try to go to Query Page (will be blocked)' }).click();
124
+
125
+ await page.waitForTimeout(100);
126
+
127
+ await expect(page.locator(h1)).toHaveText('Prevent Redirect Page');
128
+ await expect(page).toHaveURL('/prevent');
129
+ });
130
+ });
@@ -0,0 +1,12 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ export default function teardown() {
5
+ fs.readdirSync(path.resolve('examples')).map((project) =>
6
+ fs
7
+ .readdirSync(path.resolve('examples', project))
8
+ .filter((folderName) => folderName.startsWith('dist'))
9
+ .map((folderName) => path.resolve('examples', project, folderName))
10
+ .forEach((folderPath) => fs.rmSync(folderPath, { recursive: true, force: true }))
11
+ );
12
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "reactive-route",
3
3
  "author": "Dmitry Kazakov",
4
4
  "license": "MIT",
5
- "version": "0.0.1-alpha.26",
5
+ "version": "0.0.1-alpha.27",
6
6
  "description": "Reactive Router for different frameworks",
7
7
  "repository": {
8
8
  "type": "git",
@@ -11,8 +11,6 @@
11
11
  "scripts": {
12
12
  "upd": "rm -rf ./node_modules&&pnpm i --prefer-offline",
13
13
  "build": "rm -rf ./dist&&node --import tsx ./scripts/build.ts&&tsc -b ./tsconfig.types.react.json&&tsc -b ./tsconfig.types.solid.json",
14
- "test": "vitest run&&node --import tsx ./scripts/genCoverageBadge.ts",
15
- "test-watch": "vitest --coverage=false",
16
14
  "npm-publish": "pnpm run build&&pnpm run test&&npm publish --access public",
17
15
  "analyze:js": "biome check --no-errors-on-unmatched .",
18
16
  "format:js": "biome check --no-errors-on-unmatched --write",
@@ -21,9 +19,14 @@
21
19
  "prepare": "husky",
22
20
  "upgrade-examples": "pnpm upgrade -r reactive-route@latest",
23
21
  "upgrade-lib": "bash -c 'pnpm upgrade -r $@' bash",
24
- "docs:dev": "vitepress dev docs",
25
- "docs:build": "vitepress build docs",
26
- "docs:preview": "vitepress preview docs"
22
+ "test": "vitest run&&node --import tsx ./scripts/genCoverageBadge.ts",
23
+ "test-watch": "vitest --coverage=false",
24
+ "e2e": "playwright test",
25
+ "e2e:ui": "playwright test --ui",
26
+ "e2e:install": "playwright install --with-deps",
27
+ "docs:dev": "vitepress dev vitepress",
28
+ "docs:build": "vitepress build vitepress --outDir docs",
29
+ "docs:preview": "vitepress preview vitepress"
27
30
  },
28
31
  "lint-staged": {
29
32
  "(*.js|*.ts|*.tsx|*.mjs)": [
@@ -43,6 +46,8 @@
43
46
  "@biomejs/biome": "2.2.5",
44
47
  "@espcom/esbuild-plugin-compress": "1.2.0",
45
48
  "@espcom/esbuild-plugin-replace": "1.3.2",
49
+ "playwright": "1.56.1",
50
+ "@playwright/test": "1.56.1",
46
51
  "@preact/preset-vite": "2.10.2",
47
52
  "@solidjs/testing-library": "0.8.10",
48
53
  "@testing-library/preact": "3.2.4",
@@ -102,6 +107,16 @@
102
107
  "require": "./dist/cjs/solid/index.js",
103
108
  "import": "./dist/esm/solid/index.js"
104
109
  },
110
+ "./vue": {
111
+ "types": "./dist/vue/index.d.ts",
112
+ "require": "./dist/cjs/vue/index.js",
113
+ "import": "./dist/esm/vue/index.js"
114
+ },
115
+ "./adapters/vue": {
116
+ "types": "./dist/adapters/vue.d.ts",
117
+ "require": "./dist/cjs/adapters/vue/index.js",
118
+ "import": "./dist/esm/adapters/vue/index.js"
119
+ },
105
120
  "./adapters/mobx-react": {
106
121
  "types": "./dist/adapters/mobx-react.d.ts",
107
122
  "require": "./dist/cjs/adapters/mobx-react/index.js",
@@ -141,4 +156,4 @@
141
156
  "main": "dist/cjs/index.js",
142
157
  "module": "dist/esm/index.js",
143
158
  "types": "dist/core/index.d.ts"
144
- }
159
+ }
@@ -0,0 +1,52 @@
1
+ import { defineConfig, devices } from '@playwright/test';
2
+
3
+ const csrVariants: Array<{ name: string; scriptName: string }> = [
4
+ { name: '[React+Mobx]', scriptName: './examples/react mobx' },
5
+ { name: '[React+Observable]', scriptName: './examples/react observable' },
6
+ { name: '[Preact+Mobx]', scriptName: './examples/preact mobx' },
7
+ { name: '[Preact+Observable]', scriptName: './examples/preact observable' },
8
+ { name: '[Solid+Mobx]', scriptName: './examples/solid mobx' },
9
+ { name: '[Solid+Observable]', scriptName: './examples/solid observable' },
10
+ { name: '[Solid+Solid]', scriptName: './examples/solid solid' },
11
+ ];
12
+
13
+ const ssrVariants: Array<{ name: string; scriptName: string }> = [
14
+ { name: '[React+Mobx+SSR]', scriptName: './examples/react ssr-mobx' },
15
+ { name: '[React+Observable+SSR]', scriptName: './examples/react ssr-observable' },
16
+ { name: '[Preact+Mobx+SSR]', scriptName: './examples/preact ssr-mobx' },
17
+ { name: '[Preact+Observable+SSR]', scriptName: './examples/preact ssr-observable' },
18
+ { name: '[Solid+Mobx+SSR]', scriptName: './examples/solid ssr-mobx' },
19
+ { name: '[Solid+Observable+SSR]', scriptName: './examples/solid ssr-observable' },
20
+ { name: '[Solid+Solid+SSR]', scriptName: './examples/solid ssr-solid' },
21
+ ];
22
+
23
+ const variants: Array<{ name: string; port: number; scriptName: string }> = [
24
+ ...csrVariants,
25
+ ...ssrVariants,
26
+ ].map((variant, i) => ({ ...variant, port: 8002 + i * 2 }));
27
+
28
+ export default defineConfig({
29
+ testDir: './e2e',
30
+ fullyParallel: true,
31
+ forbidOnly: false,
32
+ retries: 0,
33
+ // workers: 10,
34
+ reporter: [['list']],
35
+ webServer: variants.map((variant) => ({
36
+ name: variant.name,
37
+ command: `pnpm --filter ${variant.scriptName} ${variant.port} test`,
38
+ port: variant.port,
39
+ reuseExistingServer: false,
40
+ timeout: 10000,
41
+ cwd: __dirname,
42
+ stdout: 'pipe',
43
+ })),
44
+ projects: variants.map((variant) => ({
45
+ name: variant.name,
46
+ use: {
47
+ baseURL: `http://localhost:${variant.port}`,
48
+ ...devices['Desktop Chrome'],
49
+ },
50
+ })),
51
+ globalTeardown: require.resolve('./e2e/teardown'),
52
+ });
@@ -0,0 +1,52 @@
1
+ {
2
+ "hash": "5a633cf9",
3
+ "configHash": "c2aca7c2",
4
+ "lockfileHash": "81207e34",
5
+ "browserHash": "ffb49e63",
6
+ "optimized": {
7
+ "vue": {
8
+ "src": "../../../../node_modules/.pnpm/vue@3.5.22_typescript@5.9.2/node_modules/vue/dist/vue.runtime.esm-bundler.js",
9
+ "file": "vue.js",
10
+ "fileHash": "acc43dc7",
11
+ "needsInterop": false
12
+ },
13
+ "vitepress > @vue/devtools-api": {
14
+ "src": "../../../../node_modules/.pnpm/@vue+devtools-api@8.0.1/node_modules/@vue/devtools-api/dist/index.js",
15
+ "file": "vitepress___@vue_devtools-api.js",
16
+ "fileHash": "f6e97e3d",
17
+ "needsInterop": false
18
+ },
19
+ "vitepress > @vueuse/core": {
20
+ "src": "../../../../node_modules/.pnpm/@vueuse+core@13.9.0_vue@3.5.22_typescript@5.9.2_/node_modules/@vueuse/core/index.mjs",
21
+ "file": "vitepress___@vueuse_core.js",
22
+ "fileHash": "10a3e7ca",
23
+ "needsInterop": false
24
+ },
25
+ "vitepress > @vueuse/integrations/useFocusTrap": {
26
+ "src": "../../../../node_modules/.pnpm/@vueuse+integrations@13.9.0_focus-trap@7.6.5_vue@3.5.22_typescript@5.9.2_/node_modules/@vueuse/integrations/useFocusTrap.mjs",
27
+ "file": "vitepress___@vueuse_integrations_useFocusTrap.js",
28
+ "fileHash": "a8fdd658",
29
+ "needsInterop": false
30
+ },
31
+ "vitepress > mark.js/src/vanilla.js": {
32
+ "src": "../../../../node_modules/.pnpm/mark.js@8.11.1/node_modules/mark.js/src/vanilla.js",
33
+ "file": "vitepress___mark__js_src_vanilla__js.js",
34
+ "fileHash": "be042848",
35
+ "needsInterop": false
36
+ },
37
+ "vitepress > minisearch": {
38
+ "src": "../../../../node_modules/.pnpm/minisearch@7.1.2/node_modules/minisearch/dist/es/index.js",
39
+ "file": "vitepress___minisearch.js",
40
+ "fileHash": "f4e7a04e",
41
+ "needsInterop": false
42
+ }
43
+ },
44
+ "chunks": {
45
+ "chunk-VGAXUAUJ": {
46
+ "file": "chunk-VGAXUAUJ.js"
47
+ },
48
+ "chunk-FL23S3EK": {
49
+ "file": "chunk-FL23S3EK.js"
50
+ }
51
+ }
52
+ }