@absolutejs/absolute 0.19.0-beta.176 → 0.19.0-beta.178
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/.absolutejs/eslint-cache +1 -1
- package/.absolutejs/tsconfig.tsbuildinfo +1 -1
- package/ROADMAP.md +191 -191
- package/dist/Image-fpjk72vg.vue +140 -0
- package/dist/src/angular/components/image.component.d.ts +33 -0
- package/dist/src/angular/components/index.d.ts +1 -0
- package/dist/src/angular/components/index.js +395 -0
- package/dist/src/angular/components/index.js.map +11 -0
- package/dist/{angular → src/angular}/index.js +11 -1
- package/dist/{angular → src/angular}/index.js.map +2 -2
- package/dist/src/build/optimizeHtmlImages.d.ts +2 -0
- package/dist/{build.js → src/build.js} +496 -243
- package/dist/{build.js.map → src/build.js.map} +7 -5
- package/dist/{index.js → src/index.js} +746 -276
- package/dist/{index.js.map → src/index.js.map} +9 -6
- package/dist/src/plugins/imageOptimizer.d.ts +2 -0
- package/dist/src/react/components/Image.d.ts +2 -0
- package/dist/src/react/components/index.d.ts +1 -0
- package/dist/{react → src/react}/hooks/index.js +11 -1
- package/dist/{react → src/react}/hooks/index.js.map +2 -2
- package/dist/{react → src/react}/index.js +11 -1
- package/dist/{react → src/react}/index.js.map +2 -2
- package/dist/{svelte → src/svelte}/index.js +11 -1
- package/dist/{svelte → src/svelte}/index.js.map +2 -2
- package/dist/src/utils/imageProcessing.d.ts +33 -0
- package/dist/src/vue/components/index.d.ts +1 -0
- package/dist/src/vue/components/index.js +84 -0
- package/dist/src/vue/components/index.js.map +9 -0
- package/dist/{vue → src/vue}/index.js +11 -1
- package/dist/{vue → src/vue}/index.js.map +2 -2
- package/dist/svelte/components/Head.svelte +147 -0
- package/dist/svelte/components/Image.svelte +158 -0
- package/dist/svelte/components/JsonLd.svelte +20 -0
- package/dist/types/build.d.ts +2 -0
- package/dist/types/image.d.ts +77 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +19 -4
- package/types/build.ts +3 -0
- package/types/image.ts +91 -0
- package/types/index.ts +1 -0
package/ROADMAP.md
CHANGED
|
@@ -4,7 +4,7 @@ Features missing from AbsoluteJS that Next.js provides, ordered by priority. Eac
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## P1 — Image Optimization
|
|
7
|
+
## 1. P1 — Image Optimization
|
|
8
8
|
|
|
9
9
|
**What Next.js does:**
|
|
10
10
|
`<Image>` component that automatically converts images to WebP/AVIF, generates responsive `srcset` attributes, lazy loads with blur placeholders, and serves optimized images through an on-demand image optimization API route. Prevents layout shift with required width/height.
|
|
@@ -26,7 +26,7 @@ Nothing. Images are served as-is from the public/assets directory.
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
## P1 — Loading / Error / Not-Found States
|
|
29
|
+
## 2. P1 — Loading / Error / Not-Found States
|
|
30
30
|
|
|
31
31
|
**What Next.js does:**
|
|
32
32
|
Per-route-segment `loading.tsx` (shows during async data fetch), `error.tsx` (catches runtime errors with React error boundary), and `not-found.tsx` (404 page). These are automatic — drop the file in and it works.
|
|
@@ -51,7 +51,7 @@ Per-route-segment `loading.tsx` (shows during async data fetch), `error.tsx` (ca
|
|
|
51
51
|
|
|
52
52
|
---
|
|
53
53
|
|
|
54
|
-
## P1 — Client-Side Navigation / SPA Mode with `<Link>`
|
|
54
|
+
## 3. P1 — Client-Side Navigation / SPA Mode with `<Link>`
|
|
55
55
|
|
|
56
56
|
**What Next.js does:**
|
|
57
57
|
`<Link>` component that intercepts clicks and does client-side navigation — fetches only the new page's data/RSC payload, swaps the content, and preserves layout state (scroll position, open menus, form inputs). Prefetches linked pages on hover or when they enter the viewport. This is what makes Next.js apps feel like SPAs even though they're server-rendered.
|
|
@@ -123,7 +123,7 @@ React Router and similar client-side routers can't help here — they swap clien
|
|
|
123
123
|
|
|
124
124
|
---
|
|
125
125
|
|
|
126
|
-
## P1 — Islands Architecture (Multi-Framework Pages)
|
|
126
|
+
## 4. P1 — Islands Architecture (Multi-Framework Pages)
|
|
127
127
|
|
|
128
128
|
**What Astro does:**
|
|
129
129
|
Pages are rendered as static HTML with interactive "islands" — individual components that hydrate independently. Each island can be a different framework (React, Svelte, Vue, etc.) on the same page. Hydration is controlled with directives: `client:load` (immediate), `client:idle` (requestIdleCallback), `client:visible` (IntersectionObserver). Non-interactive content ships zero JS.
|
|
@@ -412,112 +412,7 @@ The key insight: `defineIslandRegistry` accepts actual imported components at ru
|
|
|
412
412
|
|
|
413
413
|
---
|
|
414
414
|
|
|
415
|
-
##
|
|
416
|
-
|
|
417
|
-
**What Next.js does:**
|
|
418
|
-
Built-in Sass support. Import `.scss` or `.sass` files directly. Also supports `.module.scss` for scoped Sass modules.
|
|
419
|
-
|
|
420
|
-
**What AbsoluteJS has today:**
|
|
421
|
-
Only `.css` files. Tailwind handles utility classes. No preprocessor support.
|
|
422
|
-
|
|
423
|
-
**What needs to be built:**
|
|
424
|
-
- A Bun build plugin that compiles `.scss`/`.sass`/`.less` files to CSS before bundling
|
|
425
|
-
- Bun has a plugin API for custom loaders — register `.scss` extension with a loader that calls the sass compiler
|
|
426
|
-
- Support `.module.scss` for scoped Sass modules (Bun's CSS Module handling + Sass compilation)
|
|
427
|
-
- Add `sass` as an optional peer dependency
|
|
428
|
-
|
|
429
|
-
**Files likely involved:**
|
|
430
|
-
- New: `src/build/sassPlugin.ts` — Bun plugin that compiles Sass
|
|
431
|
-
- `src/core/build.ts` — register the plugin in the Bun.build() calls
|
|
432
|
-
- `src/build/scanCssEntryPoints.ts` — extend glob to include `**/*.scss`, `**/*.sass`, `**/*.less`
|
|
433
|
-
|
|
434
|
-
---
|
|
435
|
-
|
|
436
|
-
## P2 — Middleware
|
|
437
|
-
|
|
438
|
-
**What Next.js does:**
|
|
439
|
-
A single `middleware.ts` at the project root that runs before every request. Can rewrite URLs, redirect, set headers, check auth, do A/B testing, geolocation-based routing. Runs on the edge (lightweight V8 isolate).
|
|
440
|
-
|
|
441
|
-
**What AbsoluteJS has today:**
|
|
442
|
-
Elysia's full middleware system — `onBeforeHandle`, `onAfterHandle`, `.use()` plugin chain, `derive`, `guard`. This is actually more powerful than Next.js middleware but less conventionalized.
|
|
443
|
-
|
|
444
|
-
**What needs to be built:**
|
|
445
|
-
- Honestly, this might just need documentation. Elysia's `onBeforeHandle` IS middleware. A `guard()` block with auth checks IS the auth middleware pattern.
|
|
446
|
-
- Consider a thin `middleware()` helper that wraps the common pattern: check auth, redirect if not authenticated, rewrite URLs, set CORS headers
|
|
447
|
-
- Examples showing: auth guard, redirect, URL rewrite, rate limiting, CORS
|
|
448
|
-
- The key gap isn't functionality — it's discoverability. New users don't know that Elysia's `onBeforeHandle` is the middleware they're looking for.
|
|
449
|
-
|
|
450
|
-
**Files likely involved:**
|
|
451
|
-
- Mostly documentation/examples
|
|
452
|
-
- Optional: `src/utils/middleware.ts` — convenience wrappers for common patterns
|
|
453
|
-
|
|
454
|
-
---
|
|
455
|
-
|
|
456
|
-
## P3 — Internationalization (i18n)
|
|
457
|
-
|
|
458
|
-
**What Next.js does:**
|
|
459
|
-
Built-in locale routing (`/en/about`, `/fr/about`), locale detection from Accept-Language header, and domain-based routing. Integrates with i18n libraries like next-intl.
|
|
460
|
-
|
|
461
|
-
**What AbsoluteJS has today:**
|
|
462
|
-
Nothing.
|
|
463
|
-
|
|
464
|
-
**What needs to be built:**
|
|
465
|
-
- Locale detection middleware (Accept-Language header parsing, cookie-based locale persistence)
|
|
466
|
-
- URL prefix routing pattern (`/:locale/page`)
|
|
467
|
-
- A helper to load translation files and inject them as props
|
|
468
|
-
- Per-framework translation access patterns (React context, Vue provide/inject, Svelte stores)
|
|
469
|
-
- This is mostly a pattern/plugin, not core framework work
|
|
470
|
-
|
|
471
|
-
**Files likely involved:**
|
|
472
|
-
- New: `src/plugins/i18n.ts` — Elysia plugin for locale detection and routing
|
|
473
|
-
- Documentation showing integration with popular i18n libraries
|
|
474
|
-
|
|
475
|
-
---
|
|
476
|
-
|
|
477
|
-
## P3 — Font Optimization
|
|
478
|
-
|
|
479
|
-
**What Next.js does:**
|
|
480
|
-
`next/font` automatically downloads Google Fonts at build time (no external requests), subsets them, adds `font-display: swap`, and inlines the CSS. Self-hosted fonts get the same optimizations. Zero layout shift from font loading.
|
|
481
|
-
|
|
482
|
-
**What AbsoluteJS has today:**
|
|
483
|
-
`generateHeadElement()` adds a Google Fonts `<link>` with `display=swap`. Fonts are loaded at runtime from Google's CDN.
|
|
484
|
-
|
|
485
|
-
**What needs to be built:**
|
|
486
|
-
- A build-time step that downloads declared Google Fonts, subsets them (woff2), and writes them to the assets directory
|
|
487
|
-
- Inline the `@font-face` CSS directly in the `<head>` instead of linking to Google
|
|
488
|
-
- This eliminates the external request to Google, improves privacy, and prevents FOUT
|
|
489
|
-
- Consider a `defineFont()` helper that takes a font config and returns the CSS + paths
|
|
490
|
-
|
|
491
|
-
**Files likely involved:**
|
|
492
|
-
- New: `src/build/downloadFonts.ts` — fetches and subsets Google Fonts at build time
|
|
493
|
-
- `src/utils/generateHeadElement.ts` — inline font CSS instead of external link
|
|
494
|
-
- `src/core/build.ts` — add font download step to build pipeline
|
|
495
|
-
|
|
496
|
-
---
|
|
497
|
-
|
|
498
|
-
## P3 — Edge Runtime / Serverless Deployment
|
|
499
|
-
|
|
500
|
-
**What Next.js does:**
|
|
501
|
-
Routes can opt into the Edge Runtime (lightweight V8) for lower latency at the edge. Serverless function deployment on Vercel, AWS Lambda, Cloudflare Workers. Middleware always runs on edge.
|
|
502
|
-
|
|
503
|
-
**What AbsoluteJS has today:**
|
|
504
|
-
Bun-only. Requires a long-running Bun server process. No serverless or edge adapter.
|
|
505
|
-
|
|
506
|
-
**What needs to be built:**
|
|
507
|
-
- Deployment adapters for common platforms (Fly.io, Railway, Render are easy since they support Bun directly)
|
|
508
|
-
- Docker template with a minimal Bun image
|
|
509
|
-
- For serverless: an adapter that wraps the Elysia server as a Lambda/Cloud Function handler
|
|
510
|
-
- Edge runtime is unlikely to be worth pursuing — Bun doesn't run on Cloudflare Workers, and the Bun server is already fast enough that edge latency gains are marginal
|
|
511
|
-
- Focus on making traditional deployment dead simple rather than chasing edge
|
|
512
|
-
|
|
513
|
-
**Files likely involved:**
|
|
514
|
-
- New: `src/adapters/docker/Dockerfile`
|
|
515
|
-
- New: `src/adapters/lambda.ts` — AWS Lambda adapter
|
|
516
|
-
- Documentation for common deployment targets
|
|
517
|
-
|
|
518
|
-
---
|
|
519
|
-
|
|
520
|
-
## P1 — Out-of-Order Streaming
|
|
415
|
+
## 5. P1 — Out-of-Order Streaming
|
|
521
416
|
|
|
522
417
|
**What SolidStart does:**
|
|
523
418
|
Components stream to the client as they resolve, not in DOM order. If your sidebar data query finishes before your main content query, the sidebar HTML ships first. The browser renders each chunk into the correct DOM position regardless of arrival order. This means the fastest data always appears first — no waterfall where a slow hero section blocks the entire page.
|
|
@@ -573,7 +468,7 @@ With in-order streaming, the activity feed waits for the stats section even thou
|
|
|
573
468
|
|
|
574
469
|
---
|
|
575
470
|
|
|
576
|
-
## P1 — Form Actions with Progressive Enhancement
|
|
471
|
+
## 6. P1 — Form Actions with Progressive Enhancement
|
|
577
472
|
|
|
578
473
|
**What SvelteKit and Remix do:**
|
|
579
474
|
Forms submit to the server as plain HTML `<form action="/submit" method="POST">` — this works with zero JavaScript. The server processes the form, validates input, and returns a result (redirect, error, or updated page). When JavaScript IS available, the framework intercepts the submission, sends it via `fetch()` instead, and updates the page without a full reload. The developer writes one handler that works both ways.
|
|
@@ -664,77 +559,7 @@ Elysia POST handlers work for form processing, but there's no convention for pro
|
|
|
664
559
|
|
|
665
560
|
---
|
|
666
561
|
|
|
667
|
-
##
|
|
668
|
-
|
|
669
|
-
**What Next.js 16 does:**
|
|
670
|
-
A page is split into a static shell (navbar, footer, layout — cached at CDN) and dynamic "holes" that stream in at request time (user-specific content, real-time data). The static parts load instantly from cache while the dynamic parts stream in via SSR. From the user's perspective, the page appears instantly with personalized content filling in smoothly.
|
|
671
|
-
|
|
672
|
-
Next.js implements this by combining static generation with Suspense boundaries — everything outside a `<Suspense>` boundary is pre-rendered at build time, and the Suspense fallbacks are replaced with streamed server-rendered content at request time.
|
|
673
|
-
|
|
674
|
-
**What AbsoluteJS has today:**
|
|
675
|
-
Every page is fully server-rendered at request time. No static caching of any page content. The entire page waits for all data before any HTML is sent (unless using streaming SSR, which streams in-order but still requires the server to render everything on each request).
|
|
676
|
-
|
|
677
|
-
**Why this matters:**
|
|
678
|
-
Most pages are 80% static content (nav, sidebar, footer, headings, layout) and 20% dynamic (user name, notifications, personalized feed). Rendering that 80% on every request is wasted work. Partial prerendering means:
|
|
679
|
-
- The static shell loads from CDN in ~50ms (no server round-trip)
|
|
680
|
-
- The dynamic holes stream from the server in ~200-500ms
|
|
681
|
-
- Combined: users see a near-instant page with dynamic content appearing smoothly
|
|
682
|
-
- Server load drops dramatically — most of the HTML is served from cache
|
|
683
|
-
|
|
684
|
-
**What needs to be built (depends on SSG being implemented first):**
|
|
685
|
-
|
|
686
|
-
*Build-time static shell generation:*
|
|
687
|
-
- During the build, render each page but stop at dynamic boundaries (Suspense, `{#await}`, `<Suspense>`, `@defer`)
|
|
688
|
-
- Write the static HTML (everything outside dynamic boundaries) to disk with placeholder slots for the dynamic parts
|
|
689
|
-
- The static shell includes all CSS, the page layout, and fallback content (loading skeletons) for each dynamic slot
|
|
690
|
-
|
|
691
|
-
*Request-time dynamic streaming:*
|
|
692
|
-
- When a request comes in, serve the static shell immediately from disk/cache
|
|
693
|
-
- Simultaneously, render the dynamic parts on the server and stream them into the placeholder slots
|
|
694
|
-
- Reuse the out-of-order streaming infrastructure — the `$RC` swap script handles inserting dynamic content into the static shell
|
|
695
|
-
|
|
696
|
-
*Per-framework dynamic boundaries:*
|
|
697
|
-
- **React**: `<Suspense>` boundaries — everything inside is dynamic, everything outside is static
|
|
698
|
-
- **Svelte**: `{#await}` blocks or a new `<Dynamic>` component
|
|
699
|
-
- **Vue**: `<Suspense>` component — same pattern as React
|
|
700
|
-
- **Angular**: `@defer` blocks — natural fit, Angular already distinguishes static vs deferred content
|
|
701
|
-
|
|
702
|
-
*Caching strategy:*
|
|
703
|
-
- Static shells cached in memory and/or on disk with content-hash keys
|
|
704
|
-
- Cache invalidation: rebuild the shell when the page's static parts change (detected via file watcher or manual invalidation)
|
|
705
|
-
- Dynamic parts are never cached (they're user-specific/time-specific)
|
|
706
|
-
- CDN integration: set `Cache-Control` headers so the static shell is edge-cached while the dynamic stream bypasses cache
|
|
707
|
-
|
|
708
|
-
*Configuration:*
|
|
709
|
-
- Per-page opt-in via a config option or export:
|
|
710
|
-
```ts
|
|
711
|
-
// In the route handler
|
|
712
|
-
app.get('/dashboard', () =>
|
|
713
|
-
handleReactPageRequest(Dashboard, manifest['DashboardIndex'], {
|
|
714
|
-
prerender: 'partial', // static shell + dynamic streaming
|
|
715
|
-
props: { userId: getCurrentUser() }
|
|
716
|
-
})
|
|
717
|
-
)
|
|
718
|
-
```
|
|
719
|
-
- Or via the build config for pages that should always be partially prerendered
|
|
720
|
-
|
|
721
|
-
**Design considerations:**
|
|
722
|
-
- The static shell must be a valid HTML document on its own — if dynamic streaming fails, the user sees the shell with fallback content (loading skeletons), not a broken page.
|
|
723
|
-
- Dynamic boundaries should be explicit — the developer marks what's dynamic, everything else is assumed static. No guessing.
|
|
724
|
-
- This compounds with islands — an island with `hydrate="visible"` inside a dynamic boundary gets: static shell → streamed SSR HTML → hydrated on scroll. Three layers of progressive loading.
|
|
725
|
-
- Hot reloading in dev: skip the static cache and render everything server-side (same as today). Partial prerendering is a production optimization only.
|
|
726
|
-
|
|
727
|
-
**Files likely involved:**
|
|
728
|
-
- Builds on top of SSG implementation and out-of-order streaming
|
|
729
|
-
- New: `src/core/partialPrerender.ts` — orchestrates static shell serving + dynamic streaming
|
|
730
|
-
- New: `src/build/generateStaticShells.ts` — renders pages at build time, extracts static content, writes shells to disk
|
|
731
|
-
- `src/utils/streamingSlots.ts` — reused from out-of-order streaming for dynamic slot insertion
|
|
732
|
-
- Each framework's `pageHandler.ts` — add `prerender: 'partial'` mode that serves cached shell + streams dynamic parts
|
|
733
|
-
- `src/plugins/hmr.ts` — static shell cache invalidation when source files change
|
|
734
|
-
|
|
735
|
-
---
|
|
736
|
-
|
|
737
|
-
## P1 — AI/LLM Streaming Helpers
|
|
562
|
+
## 7. P1 — AI/LLM Streaming Helpers
|
|
738
563
|
|
|
739
564
|
**What exists today in the ecosystem:**
|
|
740
565
|
Vercel's `ai` SDK (`npm install ai`) provides React hooks and server utilities for streaming LLM responses. It works with Next.js, SvelteKit, and Nuxt. But it uses Server-Sent Events (SSE) because Next.js has no native WebSocket support. SSE is one-directional (server → client only) — the client can't send messages mid-stream (cancel, follow-up, branch conversation) without opening a new HTTP request.
|
|
@@ -967,7 +792,7 @@ type AIServerMessage =
|
|
|
967
792
|
|
|
968
793
|
---
|
|
969
794
|
|
|
970
|
-
## P1 — Type-Safe Environment Variables (`defineEnv`)
|
|
795
|
+
## 8. P1 — Type-Safe Environment Variables (`defineEnv`)
|
|
971
796
|
|
|
972
797
|
**The problem:**
|
|
973
798
|
`process.env.DATABASE_URL` is always `string | undefined` in TypeScript. Typos are silent (`process.env.DATABSE_URL` → `undefined`, no error). Missing vars cause runtime crashes in production. Numeric vars like `PORT` come back as strings and need manual parsing. There's no single place to see what env vars an app requires.
|
|
@@ -1034,7 +859,7 @@ if (env.NODE_ENV === 'development') { ... } // narrowed union
|
|
|
1034
859
|
|
|
1035
860
|
---
|
|
1036
861
|
|
|
1037
|
-
## P1 — Security Headers + CSP Nonce Injection
|
|
862
|
+
## 9. P1 — Security Headers + CSP Nonce Injection
|
|
1038
863
|
|
|
1039
864
|
**The problem:**
|
|
1040
865
|
Most web apps ship with zero security headers. Without a Content-Security-Policy, any XSS vulnerability lets attackers inject arbitrary `<script>` tags that execute freely. AbsoluteJS injects inline scripts on every page (`window.__INITIAL_PROPS__=...`, `$RefreshReg$` buffer, HMR client) — all of these are blocked by a strict CSP unless they have a per-request nonce.
|
|
@@ -1133,7 +958,118 @@ app.use(secureHeaders({
|
|
|
1133
958
|
|
|
1134
959
|
---
|
|
1135
960
|
|
|
1136
|
-
## P2 —
|
|
961
|
+
## 10. P2 — Sass/SCSS/Less Preprocessing
|
|
962
|
+
|
|
963
|
+
**What Next.js does:**
|
|
964
|
+
Built-in Sass support. Import `.scss` or `.sass` files directly. Also supports `.module.scss` for scoped Sass modules.
|
|
965
|
+
|
|
966
|
+
**What AbsoluteJS has today:**
|
|
967
|
+
Only `.css` files. Tailwind handles utility classes. No preprocessor support.
|
|
968
|
+
|
|
969
|
+
**What needs to be built:**
|
|
970
|
+
- A Bun build plugin that compiles `.scss`/`.sass`/`.less` files to CSS before bundling
|
|
971
|
+
- Bun has a plugin API for custom loaders — register `.scss` extension with a loader that calls the sass compiler
|
|
972
|
+
- Support `.module.scss` for scoped Sass modules (Bun's CSS Module handling + Sass compilation)
|
|
973
|
+
- Add `sass` as an optional peer dependency
|
|
974
|
+
|
|
975
|
+
**Files likely involved:**
|
|
976
|
+
- New: `src/build/sassPlugin.ts` — Bun plugin that compiles Sass
|
|
977
|
+
- `src/core/build.ts` — register the plugin in the Bun.build() calls
|
|
978
|
+
- `src/build/scanCssEntryPoints.ts` — extend glob to include `**/*.scss`, `**/*.sass`, `**/*.less`
|
|
979
|
+
|
|
980
|
+
---
|
|
981
|
+
|
|
982
|
+
## 11. P2 — Middleware
|
|
983
|
+
|
|
984
|
+
**What Next.js does:**
|
|
985
|
+
A single `middleware.ts` at the project root that runs before every request. Can rewrite URLs, redirect, set headers, check auth, do A/B testing, geolocation-based routing. Runs on the edge (lightweight V8 isolate).
|
|
986
|
+
|
|
987
|
+
**What AbsoluteJS has today:**
|
|
988
|
+
Elysia's full middleware system — `onBeforeHandle`, `onAfterHandle`, `.use()` plugin chain, `derive`, `guard`. This is actually more powerful than Next.js middleware but less conventionalized.
|
|
989
|
+
|
|
990
|
+
**What needs to be built:**
|
|
991
|
+
- Honestly, this might just need documentation. Elysia's `onBeforeHandle` IS middleware. A `guard()` block with auth checks IS the auth middleware pattern.
|
|
992
|
+
- Consider a thin `middleware()` helper that wraps the common pattern: check auth, redirect if not authenticated, rewrite URLs, set CORS headers
|
|
993
|
+
- Examples showing: auth guard, redirect, URL rewrite, rate limiting, CORS
|
|
994
|
+
- The key gap isn't functionality — it's discoverability. New users don't know that Elysia's `onBeforeHandle` is the middleware they're looking for.
|
|
995
|
+
|
|
996
|
+
**Files likely involved:**
|
|
997
|
+
- Mostly documentation/examples
|
|
998
|
+
- Optional: `src/utils/middleware.ts` — convenience wrappers for common patterns
|
|
999
|
+
|
|
1000
|
+
---
|
|
1001
|
+
|
|
1002
|
+
## 12. P2 — Partial Prerendering (requires SSG)
|
|
1003
|
+
|
|
1004
|
+
**What Next.js 16 does:**
|
|
1005
|
+
A page is split into a static shell (navbar, footer, layout — cached at CDN) and dynamic "holes" that stream in at request time (user-specific content, real-time data). The static parts load instantly from cache while the dynamic parts stream in via SSR. From the user's perspective, the page appears instantly with personalized content filling in smoothly.
|
|
1006
|
+
|
|
1007
|
+
Next.js implements this by combining static generation with Suspense boundaries — everything outside a `<Suspense>` boundary is pre-rendered at build time, and the Suspense fallbacks are replaced with streamed server-rendered content at request time.
|
|
1008
|
+
|
|
1009
|
+
**What AbsoluteJS has today:**
|
|
1010
|
+
Every page is fully server-rendered at request time. No static caching of any page content. The entire page waits for all data before any HTML is sent (unless using streaming SSR, which streams in-order but still requires the server to render everything on each request).
|
|
1011
|
+
|
|
1012
|
+
**Why this matters:**
|
|
1013
|
+
Most pages are 80% static content (nav, sidebar, footer, headings, layout) and 20% dynamic (user name, notifications, personalized feed). Rendering that 80% on every request is wasted work. Partial prerendering means:
|
|
1014
|
+
- The static shell loads from CDN in ~50ms (no server round-trip)
|
|
1015
|
+
- The dynamic holes stream from the server in ~200-500ms
|
|
1016
|
+
- Combined: users see a near-instant page with dynamic content appearing smoothly
|
|
1017
|
+
- Server load drops dramatically — most of the HTML is served from cache
|
|
1018
|
+
|
|
1019
|
+
**What needs to be built (depends on SSG being implemented first):**
|
|
1020
|
+
|
|
1021
|
+
*Build-time static shell generation:*
|
|
1022
|
+
- During the build, render each page but stop at dynamic boundaries (Suspense, `{#await}`, `<Suspense>`, `@defer`)
|
|
1023
|
+
- Write the static HTML (everything outside dynamic boundaries) to disk with placeholder slots for the dynamic parts
|
|
1024
|
+
- The static shell includes all CSS, the page layout, and fallback content (loading skeletons) for each dynamic slot
|
|
1025
|
+
|
|
1026
|
+
*Request-time dynamic streaming:*
|
|
1027
|
+
- When a request comes in, serve the static shell immediately from disk/cache
|
|
1028
|
+
- Simultaneously, render the dynamic parts on the server and stream them into the placeholder slots
|
|
1029
|
+
- Reuse the out-of-order streaming infrastructure — the `$RC` swap script handles inserting dynamic content into the static shell
|
|
1030
|
+
|
|
1031
|
+
*Per-framework dynamic boundaries:*
|
|
1032
|
+
- **React**: `<Suspense>` boundaries — everything inside is dynamic, everything outside is static
|
|
1033
|
+
- **Svelte**: `{#await}` blocks or a new `<Dynamic>` component
|
|
1034
|
+
- **Vue**: `<Suspense>` component — same pattern as React
|
|
1035
|
+
- **Angular**: `@defer` blocks — natural fit, Angular already distinguishes static vs deferred content
|
|
1036
|
+
|
|
1037
|
+
*Caching strategy:*
|
|
1038
|
+
- Static shells cached in memory and/or on disk with content-hash keys
|
|
1039
|
+
- Cache invalidation: rebuild the shell when the page's static parts change (detected via file watcher or manual invalidation)
|
|
1040
|
+
- Dynamic parts are never cached (they're user-specific/time-specific)
|
|
1041
|
+
- CDN integration: set `Cache-Control` headers so the static shell is edge-cached while the dynamic stream bypasses cache
|
|
1042
|
+
|
|
1043
|
+
*Configuration:*
|
|
1044
|
+
- Per-page opt-in via a config option or export:
|
|
1045
|
+
```ts
|
|
1046
|
+
// In the route handler
|
|
1047
|
+
app.get('/dashboard', () =>
|
|
1048
|
+
handleReactPageRequest(Dashboard, manifest['DashboardIndex'], {
|
|
1049
|
+
prerender: 'partial', // static shell + dynamic streaming
|
|
1050
|
+
props: { userId: getCurrentUser() }
|
|
1051
|
+
})
|
|
1052
|
+
)
|
|
1053
|
+
```
|
|
1054
|
+
- Or via the build config for pages that should always be partially prerendered
|
|
1055
|
+
|
|
1056
|
+
**Design considerations:**
|
|
1057
|
+
- The static shell must be a valid HTML document on its own — if dynamic streaming fails, the user sees the shell with fallback content (loading skeletons), not a broken page.
|
|
1058
|
+
- Dynamic boundaries should be explicit — the developer marks what's dynamic, everything else is assumed static. No guessing.
|
|
1059
|
+
- This compounds with islands — an island with `hydrate="visible"` inside a dynamic boundary gets: static shell → streamed SSR HTML → hydrated on scroll. Three layers of progressive loading.
|
|
1060
|
+
- Hot reloading in dev: skip the static cache and render everything server-side (same as today). Partial prerendering is a production optimization only.
|
|
1061
|
+
|
|
1062
|
+
**Files likely involved:**
|
|
1063
|
+
- Builds on top of SSG implementation and out-of-order streaming
|
|
1064
|
+
- New: `src/core/partialPrerender.ts` — orchestrates static shell serving + dynamic streaming
|
|
1065
|
+
- New: `src/build/generateStaticShells.ts` — renders pages at build time, extracts static content, writes shells to disk
|
|
1066
|
+
- `src/utils/streamingSlots.ts` — reused from out-of-order streaming for dynamic slot insertion
|
|
1067
|
+
- Each framework's `pageHandler.ts` — add `prerender: 'partial'` mode that serves cached shell + streams dynamic parts
|
|
1068
|
+
- `src/plugins/hmr.ts` — static shell cache invalidation when source files change
|
|
1069
|
+
|
|
1070
|
+
---
|
|
1071
|
+
|
|
1072
|
+
## 13. P2 — Web Vitals Reporting
|
|
1137
1073
|
|
|
1138
1074
|
**The problem:**
|
|
1139
1075
|
43% of sites fail the INP (Interaction to Next Paint) threshold. Most developers don't measure real user performance until complaints come in. Adding analytics requires third-party scripts that themselves hurt performance. Vercel has `reportWebVitals()` for Next.js but no other meta-framework has this built in.
|
|
@@ -1208,7 +1144,7 @@ app.use(vitals({
|
|
|
1208
1144
|
|
|
1209
1145
|
---
|
|
1210
1146
|
|
|
1211
|
-
## P2 — Background Jobs + Cron
|
|
1147
|
+
## 14. P2 — Background Jobs + Cron
|
|
1212
1148
|
|
|
1213
1149
|
**The problem:**
|
|
1214
1150
|
Web frameworks only handle request/response. Anything async — email sending, image processing, scheduled cleanups, webhook retries, report generation — requires separate infrastructure (Redis + Bull, separate worker process, cron service). This is the #1 reason apps "outgrow" their framework. Laravel and Rails have built-in queues and schedulers. No JS meta-framework has this.
|
|
@@ -1324,7 +1260,7 @@ app.use(jobs({
|
|
|
1324
1260
|
|
|
1325
1261
|
---
|
|
1326
1262
|
|
|
1327
|
-
## P2 — Health Check Endpoints
|
|
1263
|
+
## 15. P2 — Health Check Endpoints
|
|
1328
1264
|
|
|
1329
1265
|
**The problem:**
|
|
1330
1266
|
Every Kubernetes, Docker, ECS, or Fly.io deployment needs health check endpoints. Without them, the orchestrator can't tell if your app is alive, ready to accept traffic, or stuck. Every team implements these ad-hoc with slightly different patterns.
|
|
@@ -1403,7 +1339,7 @@ app.use(healthChecks({
|
|
|
1403
1339
|
|
|
1404
1340
|
---
|
|
1405
1341
|
|
|
1406
|
-
## P2 — Structured Logging with Request Context
|
|
1342
|
+
## 16. P2 — Structured Logging with Request Context
|
|
1407
1343
|
|
|
1408
1344
|
**The problem:**
|
|
1409
1345
|
`console.log` in production is useless — no request context, no correlation, no structured format. When something breaks, developers grep through unstructured text logs trying to match a request to its errors. Every log line should know which request it belongs to without the developer passing a logger through every function.
|
|
@@ -1484,7 +1420,7 @@ app.use(logging({
|
|
|
1484
1420
|
|
|
1485
1421
|
---
|
|
1486
1422
|
|
|
1487
|
-
## P2 — Parallel Data Loading
|
|
1423
|
+
## 17. P2 — Parallel Data Loading
|
|
1488
1424
|
|
|
1489
1425
|
**The problem:**
|
|
1490
1426
|
Request waterfalls are the #1 hidden performance killer. A parent component fetches data, renders a child, which fetches its own data, creating sequential roundtrips. On a page with 3 data sources each taking 100ms, a waterfall takes 300ms while parallel loading takes 100ms.
|
|
@@ -1589,7 +1525,7 @@ app.get('/dashboard', async (ctx) => {
|
|
|
1589
1525
|
|
|
1590
1526
|
---
|
|
1591
1527
|
|
|
1592
|
-
## P2 — CLI Scaffolding / Page Generator
|
|
1528
|
+
## 18. P2 — CLI Scaffolding / Page Generator
|
|
1593
1529
|
|
|
1594
1530
|
**The problem:**
|
|
1595
1531
|
Adding a new page to an AbsoluteJS app requires: creating the page component file with the right structure, creating a CSS file, adding the route to `server.ts` with the correct page handler import and manifest keys, and updating the build config if needed. This is 3-5 files and getting the imports/manifest keys wrong is a common mistake.
|
|
@@ -1688,7 +1624,7 @@ bun abs generate component Button --framework react
|
|
|
1688
1624
|
|
|
1689
1625
|
---
|
|
1690
1626
|
|
|
1691
|
-
## P2 — CLI Framework Adder
|
|
1627
|
+
## 19. P2 — CLI Framework Adder
|
|
1692
1628
|
|
|
1693
1629
|
**The problem:**
|
|
1694
1630
|
A project starts with React only. Six months later the team wants to add a Svelte page for a performance-critical widget, or a Vue page because a new hire knows Vue. Today this requires manually creating the framework directory, installing dependencies, updating `absolute.config.ts`, adding the page handler import to `server.ts`, and knowing the correct handler API for that framework. It's error-prone and undocumented.
|
|
@@ -1807,3 +1743,67 @@ bun abs remove svelte
|
|
|
1807
1743
|
- New: `src/cli/generators/addFramework.ts` — shared logic for directory creation, config updates, server.ts modification
|
|
1808
1744
|
- Reuse generators from `create-absolutejs/src/generators/` — `scaffoldReact`, `scaffoldSvelte`, `scaffoldVue`, `scaffoldAngular`, `scaffoldHTML`, `scaffoldHTMX`
|
|
1809
1745
|
- Reuse `generateImportsBlock` and `generateRoutesBlock` from `create-absolutejs/src/generators/project/`
|
|
1746
|
+
|
|
1747
|
+
---
|
|
1748
|
+
|
|
1749
|
+
## 20. P3 — Internationalization (i18n)
|
|
1750
|
+
|
|
1751
|
+
**What Next.js does:**
|
|
1752
|
+
Built-in locale routing (`/en/about`, `/fr/about`), locale detection from Accept-Language header, and domain-based routing. Integrates with i18n libraries like next-intl.
|
|
1753
|
+
|
|
1754
|
+
**What AbsoluteJS has today:**
|
|
1755
|
+
Nothing.
|
|
1756
|
+
|
|
1757
|
+
**What needs to be built:**
|
|
1758
|
+
- Locale detection middleware (Accept-Language header parsing, cookie-based locale persistence)
|
|
1759
|
+
- URL prefix routing pattern (`/:locale/page`)
|
|
1760
|
+
- A helper to load translation files and inject them as props
|
|
1761
|
+
- Per-framework translation access patterns (React context, Vue provide/inject, Svelte stores)
|
|
1762
|
+
- This is mostly a pattern/plugin, not core framework work
|
|
1763
|
+
|
|
1764
|
+
**Files likely involved:**
|
|
1765
|
+
- New: `src/plugins/i18n.ts` — Elysia plugin for locale detection and routing
|
|
1766
|
+
- Documentation showing integration with popular i18n libraries
|
|
1767
|
+
|
|
1768
|
+
---
|
|
1769
|
+
|
|
1770
|
+
## 21. P3 — Font Optimization
|
|
1771
|
+
|
|
1772
|
+
**What Next.js does:**
|
|
1773
|
+
`next/font` automatically downloads Google Fonts at build time (no external requests), subsets them, adds `font-display: swap`, and inlines the CSS. Self-hosted fonts get the same optimizations. Zero layout shift from font loading.
|
|
1774
|
+
|
|
1775
|
+
**What AbsoluteJS has today:**
|
|
1776
|
+
`generateHeadElement()` adds a Google Fonts `<link>` with `display=swap`. Fonts are loaded at runtime from Google's CDN.
|
|
1777
|
+
|
|
1778
|
+
**What needs to be built:**
|
|
1779
|
+
- A build-time step that downloads declared Google Fonts, subsets them (woff2), and writes them to the assets directory
|
|
1780
|
+
- Inline the `@font-face` CSS directly in the `<head>` instead of linking to Google
|
|
1781
|
+
- This eliminates the external request to Google, improves privacy, and prevents FOUT
|
|
1782
|
+
- Consider a `defineFont()` helper that takes a font config and returns the CSS + paths
|
|
1783
|
+
|
|
1784
|
+
**Files likely involved:**
|
|
1785
|
+
- New: `src/build/downloadFonts.ts` — fetches and subsets Google Fonts at build time
|
|
1786
|
+
- `src/utils/generateHeadElement.ts` — inline font CSS instead of external link
|
|
1787
|
+
- `src/core/build.ts` — add font download step to build pipeline
|
|
1788
|
+
|
|
1789
|
+
---
|
|
1790
|
+
|
|
1791
|
+
## 22. P3 — Edge Runtime / Serverless Deployment
|
|
1792
|
+
|
|
1793
|
+
**What Next.js does:**
|
|
1794
|
+
Routes can opt into the Edge Runtime (lightweight V8) for lower latency at the edge. Serverless function deployment on Vercel, AWS Lambda, Cloudflare Workers. Middleware always runs on edge.
|
|
1795
|
+
|
|
1796
|
+
**What AbsoluteJS has today:**
|
|
1797
|
+
Bun-only. Requires a long-running Bun server process. No serverless or edge adapter.
|
|
1798
|
+
|
|
1799
|
+
**What needs to be built:**
|
|
1800
|
+
- Deployment adapters for common platforms (Fly.io, Railway, Render are easy since they support Bun directly)
|
|
1801
|
+
- Docker template with a minimal Bun image
|
|
1802
|
+
- For serverless: an adapter that wraps the Elysia server as a Lambda/Cloud Function handler
|
|
1803
|
+
- Edge runtime is unlikely to be worth pursuing — Bun doesn't run on Cloudflare Workers, and the Bun server is already fast enough that edge latency gains are marginal
|
|
1804
|
+
- Focus on making traditional deployment dead simple rather than chasing edge
|
|
1805
|
+
|
|
1806
|
+
**Files likely involved:**
|
|
1807
|
+
- New: `src/adapters/docker/Dockerfile`
|
|
1808
|
+
- New: `src/adapters/lambda.ts` — AWS Lambda adapter
|
|
1809
|
+
- Documentation for common deployment targets
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref } from 'vue';
|
|
3
|
+
import type { ImageProps } from '../../../types/image';
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_QUALITY,
|
|
6
|
+
buildOptimizedUrl,
|
|
7
|
+
generateBlurSvg,
|
|
8
|
+
generateSrcSet
|
|
9
|
+
} from '../../utils/imageProcessing';
|
|
10
|
+
|
|
11
|
+
const props = withDefaults(defineProps<ImageProps>(), {
|
|
12
|
+
quality: DEFAULT_QUALITY,
|
|
13
|
+
loading: 'lazy'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const blurRemoved = ref(false);
|
|
17
|
+
|
|
18
|
+
const resolvedSrc = computed(() => {
|
|
19
|
+
if (props.overrideSrc) return props.overrideSrc;
|
|
20
|
+
if (props.unoptimized) return props.src;
|
|
21
|
+
if (props.loader) return props.loader({ src: props.src, width: props.width ?? 0, quality: props.quality });
|
|
22
|
+
if (!props.width) return buildOptimizedUrl(props.src, 0, props.quality);
|
|
23
|
+
return buildOptimizedUrl(props.src, props.width, props.quality);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const srcSet = computed(() =>
|
|
27
|
+
props.unoptimized
|
|
28
|
+
? undefined
|
|
29
|
+
: generateSrcSet(props.src, props.width, props.sizes, undefined, props.loader ?? undefined)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const resolvedSizes = computed(() => props.sizes ?? (props.fill ? '100vw' : undefined));
|
|
33
|
+
|
|
34
|
+
const resolvedLoading = computed(() => (props.priority ? 'eager' : props.loading));
|
|
35
|
+
|
|
36
|
+
const resolvedFetchPriority = computed(() => (props.priority ? 'high' : props.fetchPriority));
|
|
37
|
+
|
|
38
|
+
const hasBlur = computed(() =>
|
|
39
|
+
props.placeholder === 'blur' ||
|
|
40
|
+
(typeof props.placeholder === 'string' &&
|
|
41
|
+
props.placeholder !== 'empty' &&
|
|
42
|
+
props.placeholder.startsWith('data:'))
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const blurBackground = computed(() => {
|
|
46
|
+
if (!hasBlur.value || blurRemoved.value) return undefined;
|
|
47
|
+
if (
|
|
48
|
+
typeof props.placeholder === 'string' &&
|
|
49
|
+
props.placeholder !== 'blur' &&
|
|
50
|
+
props.placeholder.startsWith('data:')
|
|
51
|
+
) {
|
|
52
|
+
return generateBlurSvg(props.placeholder);
|
|
53
|
+
}
|
|
54
|
+
if (props.blurDataURL) return generateBlurSvg(props.blurDataURL);
|
|
55
|
+
return undefined;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const imgStyle = computed(() => {
|
|
59
|
+
const base: Record<string, string | number> = {
|
|
60
|
+
...(props.style ?? {}),
|
|
61
|
+
color: 'transparent'
|
|
62
|
+
};
|
|
63
|
+
if (blurBackground.value) {
|
|
64
|
+
base.backgroundImage = blurBackground.value;
|
|
65
|
+
base.backgroundSize = 'cover';
|
|
66
|
+
base.backgroundPosition = 'center';
|
|
67
|
+
base.backgroundRepeat = 'no-repeat';
|
|
68
|
+
}
|
|
69
|
+
if (props.fill) {
|
|
70
|
+
base.position = 'absolute';
|
|
71
|
+
base.height = '100%';
|
|
72
|
+
base.width = '100%';
|
|
73
|
+
base.inset = '0';
|
|
74
|
+
base.objectFit = 'cover';
|
|
75
|
+
}
|
|
76
|
+
return base;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const handleLoad = (e: Event) => {
|
|
80
|
+
blurRemoved.value = true;
|
|
81
|
+
if (props.onLoad) (props.onLoad as (event: Event) => void)(e);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const handleError = (e: Event) => {
|
|
85
|
+
if (props.onError) (props.onError as (event: Event) => void)(e);
|
|
86
|
+
};
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<template>
|
|
90
|
+
<Teleport to="head" v-if="priority">
|
|
91
|
+
<link
|
|
92
|
+
rel="preload"
|
|
93
|
+
as="image"
|
|
94
|
+
:href="resolvedSrc"
|
|
95
|
+
:imagesrcset="srcSet"
|
|
96
|
+
:imagesizes="resolvedSizes"
|
|
97
|
+
:crossorigin="crossOrigin"
|
|
98
|
+
/>
|
|
99
|
+
</Teleport>
|
|
100
|
+
|
|
101
|
+
<span
|
|
102
|
+
v-if="fill"
|
|
103
|
+
style="position: relative; overflow: hidden; display: block; width: 100%; height: 100%"
|
|
104
|
+
>
|
|
105
|
+
<img
|
|
106
|
+
:alt="alt"
|
|
107
|
+
:src="resolvedSrc"
|
|
108
|
+
:srcset="srcSet"
|
|
109
|
+
:sizes="resolvedSizes"
|
|
110
|
+
:loading="resolvedLoading"
|
|
111
|
+
:class="className"
|
|
112
|
+
:style="imgStyle"
|
|
113
|
+
:crossorigin="crossOrigin"
|
|
114
|
+
:referrerpolicy="referrerPolicy"
|
|
115
|
+
:fetchpriority="resolvedFetchPriority"
|
|
116
|
+
decoding="async"
|
|
117
|
+
@load="handleLoad"
|
|
118
|
+
@error="handleError"
|
|
119
|
+
/>
|
|
120
|
+
</span>
|
|
121
|
+
|
|
122
|
+
<img
|
|
123
|
+
v-else
|
|
124
|
+
:alt="alt"
|
|
125
|
+
:src="resolvedSrc"
|
|
126
|
+
:srcset="srcSet"
|
|
127
|
+
:sizes="resolvedSizes"
|
|
128
|
+
:width="width"
|
|
129
|
+
:height="height"
|
|
130
|
+
:loading="resolvedLoading"
|
|
131
|
+
:class="className"
|
|
132
|
+
:style="imgStyle"
|
|
133
|
+
:crossorigin="crossOrigin"
|
|
134
|
+
:referrerpolicy="referrerPolicy"
|
|
135
|
+
:fetchpriority="resolvedFetchPriority"
|
|
136
|
+
decoding="async"
|
|
137
|
+
@load="handleLoad"
|
|
138
|
+
@error="handleError"
|
|
139
|
+
/>
|
|
140
|
+
</template>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ImageLoader } from '../../../types/image';
|
|
2
|
+
export declare class ImageComponent {
|
|
3
|
+
readonly alt: import("@angular/core").InputSignal<string>;
|
|
4
|
+
readonly blurDataURL: import("@angular/core").InputSignal<string | undefined>;
|
|
5
|
+
readonly className: import("@angular/core").InputSignal<string | undefined>;
|
|
6
|
+
readonly crossOrigin: import("@angular/core").InputSignal<"" | "anonymous" | "use-credentials" | undefined>;
|
|
7
|
+
readonly fetchPriority: import("@angular/core").InputSignal<"high" | "low" | "auto" | undefined>;
|
|
8
|
+
readonly fill: import("@angular/core").InputSignal<boolean>;
|
|
9
|
+
readonly height: import("@angular/core").InputSignal<number | undefined>;
|
|
10
|
+
readonly loader: import("@angular/core").InputSignal<ImageLoader | undefined>;
|
|
11
|
+
readonly loading: import("@angular/core").InputSignal<"lazy" | "eager">;
|
|
12
|
+
readonly onError: import("@angular/core").InputSignal<((event: Event) => void) | undefined>;
|
|
13
|
+
readonly onLoad: import("@angular/core").InputSignal<((event: Event) => void) | undefined>;
|
|
14
|
+
readonly overrideSrc: import("@angular/core").InputSignal<string | undefined>;
|
|
15
|
+
readonly placeholder: import("@angular/core").InputSignal<string>;
|
|
16
|
+
readonly priority: import("@angular/core").InputSignal<boolean>;
|
|
17
|
+
readonly quality: import("@angular/core").InputSignal<number>;
|
|
18
|
+
readonly referrerPolicy: import("@angular/core").InputSignal<string | undefined>;
|
|
19
|
+
readonly sizes: import("@angular/core").InputSignal<string | undefined>;
|
|
20
|
+
readonly src: import("@angular/core").InputSignal<string>;
|
|
21
|
+
readonly style: import("@angular/core").InputSignal<Record<string, string | number> | undefined>;
|
|
22
|
+
readonly unoptimized: import("@angular/core").InputSignal<boolean>;
|
|
23
|
+
readonly width: import("@angular/core").InputSignal<number | undefined>;
|
|
24
|
+
private readonly blurRemoved;
|
|
25
|
+
readonly resolvedSrc: import("@angular/core").Signal<string>;
|
|
26
|
+
readonly srcSet: import("@angular/core").Signal<string | undefined>;
|
|
27
|
+
readonly resolvedSizes: import("@angular/core").Signal<string | undefined>;
|
|
28
|
+
readonly resolvedLoading: import("@angular/core").Signal<"lazy" | "eager">;
|
|
29
|
+
readonly resolvedFetchPriority: import("@angular/core").Signal<"high" | "low" | "auto" | undefined>;
|
|
30
|
+
readonly imgStyle: import("@angular/core").Signal<Record<string, string | number>>;
|
|
31
|
+
handleLoad(event: Event): void;
|
|
32
|
+
handleError(event: Event): void;
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ImageComponent } from './image.component';
|