@volpe/astro-svelte-spa 0.1.0 → 0.1.1

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/App.svelte ADDED
@@ -0,0 +1,40 @@
1
+ <script lang="ts">
2
+ import { Router, route, StatusCode } from "@mateothegreat/svelte5-router"
3
+ import routes, { basePath, notFoundComponent } from "virtual:svelte-routes"
4
+
5
+ // Build statuses config for 404 handling
6
+ const statuses = notFoundComponent ? {
7
+ [StatusCode.NotFound]: { component: notFoundComponent }
8
+ } : undefined
9
+
10
+ // Action that combines route + prefetch on hover
11
+ function link(node: HTMLAnchorElement) {
12
+ const href = node.getAttribute("href")
13
+
14
+ function preload() {
15
+ // Convert full path to relative path for matching
16
+ const relativePath = href === basePath ? "/" : href?.replace(basePath, "") || "/"
17
+ const r = routes.find(r => r.path === relativePath)
18
+ if (r?.component && typeof r.component === "function") {
19
+ r.component()
20
+ }
21
+ }
22
+
23
+ node.addEventListener("mouseenter", preload)
24
+ node.addEventListener("touchstart", preload, { passive: true })
25
+
26
+ const routeAction = route(node)
27
+
28
+ return {
29
+ destroy() {
30
+ node.removeEventListener("mouseenter", preload)
31
+ node.removeEventListener("touchstart", preload)
32
+ routeAction?.destroy?.()
33
+ }
34
+ }
35
+ }
36
+
37
+ export { link }
38
+ </script>
39
+
40
+ <Router {routes} {basePath} {statuses} />
@@ -0,0 +1,5 @@
1
+ import { SvelteComponent } from "svelte"
2
+
3
+ declare const App: typeof SvelteComponent
4
+ export default App
5
+ export declare function link(node: HTMLAnchorElement): { destroy(): void }
package/Link.svelte ADDED
@@ -0,0 +1,32 @@
1
+ <script lang="ts">
2
+ import { route } from "@mateothegreat/svelte5-router"
3
+ import routes, { basePath, type SvelteAppRoutes } from "virtual:svelte-routes"
4
+ import type { Snippet } from "svelte"
5
+ import type { HTMLAnchorAttributes } from "svelte/elements"
6
+
7
+ type Props = Omit<HTMLAnchorAttributes, "href"> & {
8
+ href: SvelteAppRoutes
9
+ children: Snippet
10
+ }
11
+
12
+ let { href, children, ...rest }: Props = $props()
13
+
14
+ function preload() {
15
+ // Convert full path to relative path for matching
16
+ const relativePath = href === basePath ? "/" : href.replace(basePath, "")
17
+ const r = routes.find(r => r.path === relativePath)
18
+ if (r?.component && typeof r.component === "function") {
19
+ r.component()
20
+ }
21
+ }
22
+ </script>
23
+
24
+ <a
25
+ {href}
26
+ use:route
27
+ onmouseenter={preload}
28
+ ontouchstart={preload}
29
+ {...rest}
30
+ >
31
+ {@render children()}
32
+ </a>
@@ -0,0 +1,12 @@
1
+ import { SvelteComponent } from "svelte"
2
+ import type { SvelteAppRoutes } from "virtual:svelte-routes"
3
+ import type { Snippet } from "svelte"
4
+ import type { HTMLAnchorAttributes } from "svelte/elements"
5
+
6
+ type Props = Omit<HTMLAnchorAttributes, "href"> & {
7
+ href: SvelteAppRoutes
8
+ children: Snippet
9
+ }
10
+
11
+ declare const Link: typeof SvelteComponent<Props>
12
+ export default Link
package/README.md CHANGED
@@ -5,9 +5,10 @@ Vite plugin for file-based routing with svelte5-router in Astro.
5
5
  ## Features
6
6
 
7
7
  - File-based routing with `page.svelte` and `layout.svelte`
8
- - Auto-generates `App.svelte`, `Link.svelte`, `[...path].astro`, `page.svelte`, and `404.svelte`
8
+ - Pre-built `App.svelte` and `Link.svelte` components
9
+ - Auto-generates `[...path].astro`, `page.svelte`, and `404.svelte`
9
10
  - Virtual module `virtual:svelte-routes` with typed routes
10
- - `SvelteAppRoutes` type for autocomplete
11
+ - `SvelteAppRoutes` type for autocomplete in `<Link>`
11
12
  - 404 handling with `StatusCode.NotFound`
12
13
  - HMR support with full reload on changes
13
14
 
@@ -23,16 +24,38 @@ npm install @volpe/astro-svelte-spa @mateothegreat/svelte5-router
23
24
  // astro.config.mjs
24
25
  import { defineConfig } from "astro/config"
25
26
  import svelte from "@astrojs/svelte"
26
- import { astroSvelteSpa } from "@volpe/astro-svelte-spa"
27
+ import { plugin } from "@volpe/astro-svelte-spa"
27
28
 
28
29
  export default defineConfig({
29
30
  integrations: [svelte()],
30
31
  vite: {
31
- plugins: [astroSvelteSpa({ basePath: "/app" })]
32
+ plugins: [plugin({ basePath: "/app" })]
32
33
  }
33
34
  })
34
35
  ```
35
36
 
37
+ ## Components
38
+
39
+ Import the pre-built components:
40
+
41
+ ```svelte
42
+ <!-- src/pages/svelte-app/[...path].astro -->
43
+ ---
44
+ import App from "@volpe/astro-svelte-spa/App.svelte"
45
+ ---
46
+
47
+ <App client:only="svelte" />
48
+ ```
49
+
50
+ ```svelte
51
+ <!-- In your Svelte pages -->
52
+ <script>
53
+ import Link from "@volpe/astro-svelte-spa/Link.svelte"
54
+ </script>
55
+
56
+ <Link href="/svelte-app/about">About</Link>
57
+ ```
58
+
36
59
  ## File Structure
37
60
 
38
61
  ```
@@ -41,15 +64,12 @@ src/
41
64
  svelte-app/ # or your custom basePath
42
65
  page.svelte # -> /svelte-app
43
66
  404.svelte # -> catch-all 404
44
- [...path].astro # Astro catch-all
67
+ [...path].astro # Astro catch-all (auto-generated)
45
68
  about/
46
69
  page.svelte # -> /svelte-app/about
47
70
  settings/
48
71
  page.svelte # -> /svelte-app/settings
49
72
  layout.svelte # wraps settings pages
50
- components/
51
- App.svelte # auto-generated
52
- Link.svelte # auto-generated
53
73
  ```
54
74
 
55
75
  ## Options
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Plugin } from "vite";
2
2
 
3
- export interface AstroSvelteSpaOptions {
3
+ export interface PluginOptions {
4
4
  /**
5
5
  * Base path for all routes.
6
6
  * When set to "/app", the plugin scans `src/pages/app/` and routes start with "/app".
@@ -14,7 +14,7 @@ export interface AstroSvelteSpaOptions {
14
14
  *
15
15
  * Features:
16
16
  * - File-based routing with `page.svelte` and `layout.svelte`
17
- * - Auto-generates `App.svelte`, `Link.svelte`, `[...path].astro`, `page.svelte`, and `404.svelte`
17
+ * - Auto-generates `[...path].astro`, `page.svelte`, and `404.svelte`
18
18
  * - Virtual module `virtual:svelte-routes` with typed routes
19
19
  * - `SvelteAppRoutes` type for autocomplete
20
20
  * - 404 handling with StatusCode.NotFound
@@ -23,15 +23,15 @@ export interface AstroSvelteSpaOptions {
23
23
  * @example
24
24
  * ```js
25
25
  * // astro.config.mjs
26
- * import { astroSvelteSpa } from "@volpe/astro-svelte-spa"
26
+ * import { plugin } from "@volpe/astro-svelte-spa"
27
27
  *
28
28
  * export default defineConfig({
29
29
  * vite: {
30
- * plugins: [astroSvelteSpa({ basePath: "/app" })]
30
+ * plugins: [plugin({ basePath: "/app" })]
31
31
  * }
32
32
  * })
33
33
  * ```
34
34
  */
35
- export function astroSvelteSpa(options?: AstroSvelteSpaOptions): Plugin;
35
+ export function plugin(options?: PluginOptions): Plugin;
36
36
 
37
- export default astroSvelteSpa;
37
+ export default plugin;
package/index.js CHANGED
@@ -215,101 +215,18 @@ declare module "virtual:svelte-routes" {
215
215
  }
216
216
 
217
217
  /**
218
- * @param {string} rootDir
219
218
  * @param {string} pagesDir
220
- * @param {string} basePath
221
219
  */
222
- function generateComponentFiles(rootDir, pagesDir, basePath) {
223
- const componentsDir = path.resolve(rootDir, "src/components");
224
-
225
- if (!fs.existsSync(componentsDir)) {
226
- fs.mkdirSync(componentsDir, { recursive: true });
227
- }
228
-
220
+ function generatePageFiles(pagesDir) {
229
221
  if (!fs.existsSync(pagesDir)) {
230
222
  fs.mkdirSync(pagesDir, { recursive: true });
231
223
  }
232
224
 
233
- // Generate App.svelte if it doesn't exist
234
- const appPath = path.resolve(componentsDir, "App.svelte");
235
- if (!fs.existsSync(appPath)) {
236
- const appContent = `<script>
237
- import { Router, route, StatusCode } from "@mateothegreat/svelte5-router"
238
- import routes, { basePath, notFoundComponent } from "virtual:svelte-routes"
239
-
240
- // Build statuses config for 404 handling
241
- const statuses = notFoundComponent ? {
242
- [StatusCode.NotFound]: { component: notFoundComponent }
243
- } : undefined
244
-
245
- // Action that combines route + prefetch on hover
246
- function link(node) {
247
- const href = node.getAttribute("href")
248
-
249
- function preload() {
250
- const r = routes.find(r => r.path === href)
251
- if (r?.component && typeof r.component === "function") {
252
- r.component()
253
- }
254
- }
255
-
256
- node.addEventListener("mouseenter", preload)
257
- node.addEventListener("touchstart", preload, { passive: true })
258
-
259
- const routeAction = route(node)
260
-
261
- return {
262
- destroy() {
263
- node.removeEventListener("mouseenter", preload)
264
- node.removeEventListener("touchstart", preload)
265
- routeAction?.destroy?.()
266
- }
267
- }
268
- }
269
-
270
- export { link }
271
- </script>
272
-
273
- <Router {routes} {basePath} {statuses} />
274
- `;
275
- fs.writeFileSync(appPath, appContent);
276
- }
277
-
278
- // Generate Link.svelte if it doesn't exist
279
- const linkPath = path.resolve(componentsDir, "Link.svelte");
280
- if (!fs.existsSync(linkPath)) {
281
- const linkContent = `<script>
282
- import { route } from "@mateothegreat/svelte5-router"
283
- import routes from "virtual:svelte-routes"
284
-
285
- let { href, children, ...rest } = $props()
286
-
287
- function preload() {
288
- const r = routes.find(r => r.path === href)
289
- if (r?.component && typeof r.component === "function") {
290
- r.component()
291
- }
292
- }
293
- </script>
294
-
295
- <a
296
- {href}
297
- use:route
298
- onmouseenter={preload}
299
- ontouchstart={preload}
300
- {...rest}
301
- >
302
- {@render children()}
303
- </a>
304
- `;
305
- fs.writeFileSync(linkPath, linkContent);
306
- }
307
-
308
225
  // Generate [...path].astro if it doesn't exist
309
226
  const catchAllPath = path.resolve(pagesDir, "[...path].astro");
310
227
  if (!fs.existsSync(catchAllPath)) {
311
228
  const catchAllContent = `---
312
- import App from "~/components/App.svelte"
229
+ import App from "@volpe/astro-svelte-spa/App.svelte"
313
230
  ---
314
231
 
315
232
  <App client:only="svelte" />
@@ -372,7 +289,7 @@ import App from "~/components/App.svelte"
372
289
  * @param {string} [options.basePath] - Base path for all routes (defaults to "/svelte-app")
373
290
  * @returns {import('vite').Plugin}
374
291
  */
375
- export function astroSvelteSpa(options = {}) {
292
+ export function plugin(options = {}) {
376
293
  // Normalize basePath, defaults to "/svelte-app"
377
294
  const basePath = options.basePath?.replace(/\/$/, "") || "/svelte-app";
378
295
  // Directory suffix: "/svelte-app" -> "svelte-app"
@@ -382,7 +299,7 @@ export function astroSvelteSpa(options = {}) {
382
299
  const pagesDir = path.resolve(rootDir, "src/pages", dirSuffix);
383
300
  const typesPath = path.resolve(rootDir, "src/svelte-routes.d.ts");
384
301
 
385
- generateComponentFiles(rootDir, pagesDir, basePath);
302
+ generatePageFiles(pagesDir);
386
303
 
387
304
  return {
388
305
  name: "vite-plugin-astro-svelte-spa",
@@ -441,4 +358,4 @@ export function astroSvelteSpa(options = {}) {
441
358
  };
442
359
  }
443
360
 
444
- export default astroSvelteSpa;
361
+ export default plugin;
package/package.json CHANGED
@@ -1,16 +1,36 @@
1
1
  {
2
2
  "name": "@volpe/astro-svelte-spa",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Vite plugin for file-based routing with svelte5-router in Astro",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
+ "svelte": "./index.js",
8
9
  "exports": {
9
10
  ".": {
10
11
  "types": "./index.d.ts",
12
+ "svelte": "./index.js",
11
13
  "default": "./index.js"
14
+ },
15
+ "./App.svelte": {
16
+ "types": "./App.svelte.d.ts",
17
+ "svelte": "./App.svelte",
18
+ "default": "./App.svelte"
19
+ },
20
+ "./Link.svelte": {
21
+ "types": "./Link.svelte.d.ts",
22
+ "svelte": "./Link.svelte",
23
+ "default": "./Link.svelte"
12
24
  }
13
25
  },
26
+ "files": [
27
+ "index.js",
28
+ "index.d.ts",
29
+ "App.svelte",
30
+ "App.svelte.d.ts",
31
+ "Link.svelte",
32
+ "Link.svelte.d.ts"
33
+ ],
14
34
  "keywords": [
15
35
  "vite",
16
36
  "vite-plugin",
@@ -23,7 +43,8 @@
23
43
  "author": "",
24
44
  "license": "MIT",
25
45
  "peerDependencies": {
26
- "vite": "^5.0.0 || ^6.0.0"
46
+ "vite": "^5.0.0 || ^6.0.0",
47
+ "@mateothegreat/svelte5-router": "^2.0.0"
27
48
  },
28
49
  "publishConfig": {
29
50
  "access": "public"