rkk-next 1.0.0
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/LICENSE +21 -0
- package/README.md +248 -0
- package/dist/analytics/webVitals.d.ts +2 -0
- package/dist/analytics/webVitals.js +8 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +32 -0
- package/dist/performance/ImageOptimizer.d.ts +16 -0
- package/dist/performance/ImageOptimizer.js +23 -0
- package/dist/performance/Lazy.d.ts +19 -0
- package/dist/performance/Lazy.js +33 -0
- package/dist/performance/cacheHeaders.d.ts +35 -0
- package/dist/performance/cacheHeaders.js +65 -0
- package/dist/performance/securityHeaders.d.ts +4 -0
- package/dist/performance/securityHeaders.js +17 -0
- package/dist/routing/RouteObserver.d.ts +24 -0
- package/dist/routing/RouteObserver.js +53 -0
- package/dist/routing/SmartLink.d.ts +17 -0
- package/dist/routing/SmartLink.js +62 -0
- package/dist/routing/prefetch.d.ts +25 -0
- package/dist/routing/prefetch.js +58 -0
- package/dist/seo/JsonLd.d.ts +15 -0
- package/dist/seo/JsonLd.js +26 -0
- package/dist/seo/MetaManager.d.ts +25 -0
- package/dist/seo/MetaManager.js +39 -0
- package/dist/seo/appMetadata.d.ts +13 -0
- package/dist/seo/appMetadata.js +15 -0
- package/dist/seo/defaults.d.ts +32 -0
- package/dist/seo/defaults.js +50 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Rohit Kumar Kundu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# 🚀 rkk-next
|
|
2
|
+
|
|
3
|
+
> **SEO, Performance & Routing SDK for Next.js**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/rkk-next)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
rkk-next is an opinionated Next.js SDK that helps you build **SEO-optimized**, **blazing fast**, and **scalable** applications with better routing, caching, and performance defaults.
|
|
10
|
+
|
|
11
|
+
✨ **Built for Next.js Pages Router & App Router**
|
|
12
|
+
🎯 **Ideal for:** Startups, Landing Pages, Web3 Dashboards, SaaS, Hackathons
|
|
13
|
+
|
|
14
|
+
## ✨ Features
|
|
15
|
+
|
|
16
|
+
### 🔍 SEO Optimization
|
|
17
|
+
- ✅ Centralized meta management (OpenGraph, Twitter Cards)
|
|
18
|
+
- ✅ JSON-LD structured data (Schema.org)
|
|
19
|
+
- ✅ Canonical URL handling
|
|
20
|
+
- ✅ SEO-safe defaults & best practices
|
|
21
|
+
|
|
22
|
+
### ⚡ Routing Optimization
|
|
23
|
+
- ✅ Intelligent route prefetching (hover-based)
|
|
24
|
+
- ✅ Network-aware prefetching
|
|
25
|
+
- ✅ Route change observer with performance metrics
|
|
26
|
+
- ✅ Analytics-ready routing events
|
|
27
|
+
|
|
28
|
+
### 🚀 Performance Boost
|
|
29
|
+
- ✅ Lazy loading for heavy components
|
|
30
|
+
- ✅ Optimized image wrapper (SEO + performance)
|
|
31
|
+
- ✅ Cache & CDN header presets
|
|
32
|
+
- ✅ Edge-friendly caching strategies
|
|
33
|
+
- ✅ Security headers included
|
|
34
|
+
|
|
35
|
+
### 📊 Analytics
|
|
36
|
+
- ✅ Web Vitals tracking (LCP, FID, CLS, etc.)
|
|
37
|
+
- ✅ Route navigation analytics
|
|
38
|
+
- ✅ Performance monitoring
|
|
39
|
+
|
|
40
|
+
📦 Installation
|
|
41
|
+
npm install rkk-next
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
or
|
|
45
|
+
|
|
46
|
+
yarn add rkk-next
|
|
47
|
+
|
|
48
|
+
🧠 Basic Usage
|
|
49
|
+
1️⃣ SEO Meta Manager
|
|
50
|
+
import { MetaManager } from "rkk-next";
|
|
51
|
+
|
|
52
|
+
export default function Home() {
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
<MetaManager
|
|
56
|
+
title="Home | My App"
|
|
57
|
+
description="SEO optimized Next.js app using rkk-next"
|
|
58
|
+
keywords="Next.js, SEO, Performance"
|
|
59
|
+
image="/og.png"
|
|
60
|
+
siteName="My App"
|
|
61
|
+
/>
|
|
62
|
+
|
|
63
|
+
<h1>Hello World</h1>
|
|
64
|
+
</>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
2️⃣ JSON-LD (Schema.org)
|
|
69
|
+
import { JsonLd } from "rkk-next";
|
|
70
|
+
|
|
71
|
+
<JsonLd
|
|
72
|
+
type="WebSite"
|
|
73
|
+
data={{
|
|
74
|
+
name: "My App",
|
|
75
|
+
url: "https://myapp.com",
|
|
76
|
+
}}
|
|
77
|
+
/>
|
|
78
|
+
|
|
79
|
+
🔗 Smart Routing
|
|
80
|
+
SmartLink (Enhanced next/link)
|
|
81
|
+
import { SmartLink } from "rkk-next";
|
|
82
|
+
|
|
83
|
+
<SmartLink href="/dashboard">
|
|
84
|
+
Go to Dashboard
|
|
85
|
+
</SmartLink>
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
✔ Prefetch on hover
|
|
89
|
+
✔ Network-aware
|
|
90
|
+
✔ SEO-safe <a> tag
|
|
91
|
+
|
|
92
|
+
Route Observer
|
|
93
|
+
import { observeRoutes } from "rkk-next";
|
|
94
|
+
|
|
95
|
+
observeRoutes((event) => {
|
|
96
|
+
console.log(event.url, event.duration);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
🖼️ Image Optimization
|
|
100
|
+
import { OptimizedImage } from "rkk-next";
|
|
101
|
+
|
|
102
|
+
<OptimizedImage
|
|
103
|
+
src="/hero.png"
|
|
104
|
+
alt="Landing page hero image"
|
|
105
|
+
width={1200}
|
|
106
|
+
height={630}
|
|
107
|
+
priority
|
|
108
|
+
/>
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
✔ SEO-safe alt enforcement
|
|
112
|
+
✔ Responsive sizes
|
|
113
|
+
✔ LCP optimized
|
|
114
|
+
|
|
115
|
+
💤 Lazy Loading
|
|
116
|
+
import { lazyImport } from "rkk-next";
|
|
117
|
+
|
|
118
|
+
const Chart = lazyImport(() => import("./Chart"));
|
|
119
|
+
|
|
120
|
+
export default function Dashboard() {
|
|
121
|
+
return <Chart />;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
🧠 Intelligent Prefetching
|
|
125
|
+
import { prefetchRoute, isFastConnection } from "rkk-next";
|
|
126
|
+
|
|
127
|
+
prefetchRoute("/dashboard", {
|
|
128
|
+
condition: isFastConnection,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
🗄️ Cache Headers
|
|
132
|
+
|
|
133
|
+
Use directly inside next.config.js:
|
|
134
|
+
|
|
135
|
+
const {
|
|
136
|
+
LONG_TERM_CACHE,
|
|
137
|
+
EDGE_CACHE,
|
|
138
|
+
NO_CACHE,
|
|
139
|
+
applyCache,
|
|
140
|
+
} = require("rkk-next");
|
|
141
|
+
|
|
142
|
+
module.exports = {
|
|
143
|
+
async headers() {
|
|
144
|
+
return [
|
|
145
|
+
applyCache("/_next/static/:path*", LONG_TERM_CACHE),
|
|
146
|
+
applyCache("/api/public/:path*", EDGE_CACHE),
|
|
147
|
+
applyCache("/dashboard/:path*", NO_CACHE),
|
|
148
|
+
];
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
## 🧩 Supported Next.js Versions
|
|
153
|
+
|
|
154
|
+
| Feature | Pages Router | App Router |
|
|
155
|
+
|-------------------|--------------|------------|
|
|
156
|
+
| MetaManager | ✅ | ✅ (via generateAppMetadata) |
|
|
157
|
+
| JsonLd | ✅ | ✅ |
|
|
158
|
+
| SmartLink | ✅ | ⚠️ (use for internal links only) |
|
|
159
|
+
| Routing Observer | ✅ | ⚠️ (Pages Router recommended) |
|
|
160
|
+
| OptimizedImage | ✅ | ✅ |
|
|
161
|
+
| Lazy Loading | ✅ | ✅ |
|
|
162
|
+
| Cache Headers | ✅ | ✅ |
|
|
163
|
+
| Web Vitals | ✅ | ✅ |
|
|
164
|
+
|
|
165
|
+
**Minimum Requirements:**
|
|
166
|
+
- Next.js >= 12.0.0
|
|
167
|
+
- React >= 17.0.0
|
|
168
|
+
- TypeScript >= 4.5.0 (optional but recommended)
|
|
169
|
+
🛠️ Best Practices
|
|
170
|
+
|
|
171
|
+
Use MetaManager on every page
|
|
172
|
+
|
|
173
|
+
Avoid lazy loading LCP elements
|
|
174
|
+
|
|
175
|
+
Use SmartLink for internal navigation
|
|
176
|
+
|
|
177
|
+
Enable cache headers for static assets
|
|
178
|
+
|
|
179
|
+
Always provide alt text for images
|
|
180
|
+
|
|
181
|
+
## 🧑💻 Author
|
|
182
|
+
|
|
183
|
+
**Rohit Kumar Kundu**
|
|
184
|
+
🎓 B.Tech CSE | Web3 & Next.js Developer
|
|
185
|
+
🔗 [GitHub](https://github.com/ROHIT8759) | [LinkedIn](https://linkedin.com/in/rohit-kumar-kundu)
|
|
186
|
+
|
|
187
|
+
## 📚 Documentation
|
|
188
|
+
|
|
189
|
+
- 📖 [Full Documentation](./docs/DOCS.md)
|
|
190
|
+
- 🚀 [Quick Start Guide](./docs/QUICKSTART.md)
|
|
191
|
+
- 📝 [API Reference](./docs/DOCS.md#api-reference)
|
|
192
|
+
- 💡 [Examples](./examples/)
|
|
193
|
+
|
|
194
|
+
## 🤝 Contributing
|
|
195
|
+
|
|
196
|
+
We welcome contributions! See [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for guidelines.
|
|
197
|
+
|
|
198
|
+
1. Fork the repository
|
|
199
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
200
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
201
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
202
|
+
5. Open a Pull Request
|
|
203
|
+
|
|
204
|
+
## 🚀 Next Steps
|
|
205
|
+
|
|
206
|
+
- [ ] Add App Router `generateMetadata` helper
|
|
207
|
+
- [ ] Expand Web Vitals analytics integration
|
|
208
|
+
- [ ] Create demo app showcase
|
|
209
|
+
- [ ] Add Lighthouse CI integration
|
|
210
|
+
- [ ] Video tutorials & guides
|
|
211
|
+
|
|
212
|
+
## 📄 License
|
|
213
|
+
|
|
214
|
+
MIT License © 2025 [Rohit Kumar Kundu](https://github.com/ROHIT8759)
|
|
215
|
+
|
|
216
|
+
Free to use, modify, and distribute. See [LICENSE](./LICENSE) for details.
|
|
217
|
+
|
|
218
|
+
## ⭐ Support the Project
|
|
219
|
+
|
|
220
|
+
If you find rkk-next helpful:
|
|
221
|
+
|
|
222
|
+
- ⭐ **Star the repo** on GitHub
|
|
223
|
+
- 🐛 **Report issues** to help improve the SDK
|
|
224
|
+
- 🤝 **Contribute** with PRs and feature ideas
|
|
225
|
+
- 📢 **Share** with other Next.js developers
|
|
226
|
+
- 💬 **Join discussions** and share your use cases
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
**Made with ❤️ for the Next.js community**
|
|
231
|
+
|
|
232
|
+
[Get Started](./docs/QUICKSTART.md) | [Documentation](./docs/DOCS.md) | [Examples](./examples/) | [Report Issue](https://github.com/ROHIT8759/rkk-next/issues)
|
|
233
|
+
|
|
234
|
+
NPM publish
|
|
235
|
+
|
|
236
|
+
If you want, I can now:
|
|
237
|
+
|
|
238
|
+
✔ Review this README
|
|
239
|
+
|
|
240
|
+
✔ Add badges (npm, downloads)
|
|
241
|
+
|
|
242
|
+
✔ Prepare NPM publish checklist
|
|
243
|
+
|
|
244
|
+
✔ Create example Next.js app
|
|
245
|
+
|
|
246
|
+
✔ Final SDK audit before release
|
|
247
|
+
|
|
248
|
+
Just tell me 👍
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reportWebVitals = reportWebVitals;
|
|
4
|
+
function reportWebVitals(metric) {
|
|
5
|
+
const { id, name, value } = metric;
|
|
6
|
+
console.log("[Vitals]", name, value);
|
|
7
|
+
// future: send to analytics
|
|
8
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./seo/MetaManager";
|
|
2
|
+
export * from "./seo/JsonLd";
|
|
3
|
+
export * from "./seo/defaults";
|
|
4
|
+
export * from "./seo/appMetadata";
|
|
5
|
+
export * from "./routing/SmartLink";
|
|
6
|
+
export * from "./routing/prefetch";
|
|
7
|
+
export * from "./routing/RouteObserver";
|
|
8
|
+
export * from "./performance/ImageOptimizer";
|
|
9
|
+
export * from "./performance/Lazy";
|
|
10
|
+
export * from "./performance/cacheHeaders";
|
|
11
|
+
export * from "./performance/securityHeaders";
|
|
12
|
+
export * from "./analytics/webVitals";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// SEO
|
|
18
|
+
__exportStar(require("./seo/MetaManager"), exports);
|
|
19
|
+
__exportStar(require("./seo/JsonLd"), exports);
|
|
20
|
+
__exportStar(require("./seo/defaults"), exports);
|
|
21
|
+
__exportStar(require("./seo/appMetadata"), exports);
|
|
22
|
+
// Routing
|
|
23
|
+
__exportStar(require("./routing/SmartLink"), exports);
|
|
24
|
+
__exportStar(require("./routing/prefetch"), exports);
|
|
25
|
+
__exportStar(require("./routing/RouteObserver"), exports);
|
|
26
|
+
// Performance
|
|
27
|
+
__exportStar(require("./performance/ImageOptimizer"), exports);
|
|
28
|
+
__exportStar(require("./performance/Lazy"), exports);
|
|
29
|
+
__exportStar(require("./performance/cacheHeaders"), exports);
|
|
30
|
+
__exportStar(require("./performance/securityHeaders"), exports);
|
|
31
|
+
// Analytics
|
|
32
|
+
__exportStar(require("./analytics/webVitals"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ImageProps } from "next/image";
|
|
2
|
+
import React from "react";
|
|
3
|
+
export type OptimizedImageProps = ImageProps & {
|
|
4
|
+
/** Override default quality (1–100) */
|
|
5
|
+
quality?: number;
|
|
6
|
+
/** Enable priority loading (LCP images) */
|
|
7
|
+
priority?: boolean;
|
|
8
|
+
/** Fallback alt text (SEO safety) */
|
|
9
|
+
alt: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* OptimizedImage
|
|
13
|
+
* SEO-first wrapper around next/image
|
|
14
|
+
*/
|
|
15
|
+
export declare const OptimizedImage: React.FC<OptimizedImageProps>;
|
|
16
|
+
export default OptimizedImage;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OptimizedImage = void 0;
|
|
7
|
+
const image_1 = __importDefault(require("next/image"));
|
|
8
|
+
const react_1 = __importDefault(require("react"));
|
|
9
|
+
/**
|
|
10
|
+
* OptimizedImage
|
|
11
|
+
* SEO-first wrapper around next/image
|
|
12
|
+
*/
|
|
13
|
+
const OptimizedImage = ({ quality = 80, priority = false, alt, ...props }) => {
|
|
14
|
+
if (!alt) {
|
|
15
|
+
if (process.env.NODE_ENV !== "production") {
|
|
16
|
+
console.warn("[next-optimize-sdk] OptimizedImage requires alt text for SEO");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return (react_1.default.createElement(image_1.default, { ...props, alt: alt, quality: quality, priority: priority, loading: priority ? "eager" : "lazy", sizes: props.sizes ||
|
|
20
|
+
"(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw", placeholder: props.placeholder || "empty" }));
|
|
21
|
+
};
|
|
22
|
+
exports.OptimizedImage = OptimizedImage;
|
|
23
|
+
exports.default = exports.OptimizedImage;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Loader } from "next/dynamic";
|
|
2
|
+
import React from "react";
|
|
3
|
+
export type LazyOptions<P = {}> = {
|
|
4
|
+
/** Custom loading component */
|
|
5
|
+
loading?: React.ComponentType;
|
|
6
|
+
/** Enable / disable SSR */
|
|
7
|
+
ssr?: boolean;
|
|
8
|
+
/** Delay before showing loading component (ms) */
|
|
9
|
+
delay?: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Lazy-load a React component with Next.js dynamic import
|
|
13
|
+
* Optimized for performance and bundle size reduction
|
|
14
|
+
*/
|
|
15
|
+
export declare function lazyImport<P = {}>(loader: Loader<P>, options?: LazyOptions<P>): React.ComponentType<P>;
|
|
16
|
+
/**
|
|
17
|
+
* Simple fallback loading component
|
|
18
|
+
*/
|
|
19
|
+
export declare const DefaultLoader: React.FC;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DefaultLoader = void 0;
|
|
7
|
+
exports.lazyImport = lazyImport;
|
|
8
|
+
const dynamic_1 = __importDefault(require("next/dynamic"));
|
|
9
|
+
const react_1 = __importDefault(require("react"));
|
|
10
|
+
/**
|
|
11
|
+
* Lazy-load a React component with Next.js dynamic import
|
|
12
|
+
* Optimized for performance and bundle size reduction
|
|
13
|
+
*/
|
|
14
|
+
function lazyImport(loader, options = {}) {
|
|
15
|
+
const { loading: LoadingComponent, ssr = false, delay = 200, } = options;
|
|
16
|
+
const dynamicOptions = {
|
|
17
|
+
ssr,
|
|
18
|
+
loading: LoadingComponent
|
|
19
|
+
? () => react_1.default.createElement(LoadingComponent, null)
|
|
20
|
+
: () => null,
|
|
21
|
+
};
|
|
22
|
+
return (0, dynamic_1.default)(loader, dynamicOptions);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Simple fallback loading component
|
|
26
|
+
*/
|
|
27
|
+
const DefaultLoader = () => (react_1.default.createElement("div", { style: {
|
|
28
|
+
padding: "1rem",
|
|
29
|
+
textAlign: "center",
|
|
30
|
+
opacity: 0.7,
|
|
31
|
+
fontSize: "0.9rem",
|
|
32
|
+
} }, "Loading\u2026"));
|
|
33
|
+
exports.DefaultLoader = DefaultLoader;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache header presets for Next.js
|
|
3
|
+
* Centralized caching strategy for SEO & performance
|
|
4
|
+
*/
|
|
5
|
+
export type CacheHeader = {
|
|
6
|
+
key: string;
|
|
7
|
+
value: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Long-term cache
|
|
11
|
+
* Best for static assets (JS, CSS, fonts, images)
|
|
12
|
+
*/
|
|
13
|
+
export declare const LONG_TERM_CACHE: CacheHeader[];
|
|
14
|
+
/**
|
|
15
|
+
* Short-term cache
|
|
16
|
+
* Best for ISR pages or frequently updated content
|
|
17
|
+
*/
|
|
18
|
+
export declare const SHORT_TERM_CACHE: CacheHeader[];
|
|
19
|
+
/**
|
|
20
|
+
* No cache
|
|
21
|
+
* Best for dashboards, auth, user-specific pages
|
|
22
|
+
*/
|
|
23
|
+
export declare const NO_CACHE: CacheHeader[];
|
|
24
|
+
/**
|
|
25
|
+
* Edge / CDN optimized cache
|
|
26
|
+
*/
|
|
27
|
+
export declare const EDGE_CACHE: CacheHeader[];
|
|
28
|
+
/**
|
|
29
|
+
* Helper function to apply cache headers
|
|
30
|
+
* directly inside next.config.js
|
|
31
|
+
*/
|
|
32
|
+
export declare function applyCache(source: string, headers: CacheHeader[]): {
|
|
33
|
+
source: string;
|
|
34
|
+
headers: CacheHeader[];
|
|
35
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Cache header presets for Next.js
|
|
4
|
+
* Centralized caching strategy for SEO & performance
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.EDGE_CACHE = exports.NO_CACHE = exports.SHORT_TERM_CACHE = exports.LONG_TERM_CACHE = void 0;
|
|
8
|
+
exports.applyCache = applyCache;
|
|
9
|
+
/**
|
|
10
|
+
* Long-term cache
|
|
11
|
+
* Best for static assets (JS, CSS, fonts, images)
|
|
12
|
+
*/
|
|
13
|
+
exports.LONG_TERM_CACHE = [
|
|
14
|
+
{
|
|
15
|
+
key: "Cache-Control",
|
|
16
|
+
value: "public, max-age=31536000, immutable",
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Short-term cache
|
|
21
|
+
* Best for ISR pages or frequently updated content
|
|
22
|
+
*/
|
|
23
|
+
exports.SHORT_TERM_CACHE = [
|
|
24
|
+
{
|
|
25
|
+
key: "Cache-Control",
|
|
26
|
+
value: "public, max-age=60, stale-while-revalidate=300",
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* No cache
|
|
31
|
+
* Best for dashboards, auth, user-specific pages
|
|
32
|
+
*/
|
|
33
|
+
exports.NO_CACHE = [
|
|
34
|
+
{
|
|
35
|
+
key: "Cache-Control",
|
|
36
|
+
value: "no-store, no-cache, must-revalidate, proxy-revalidate",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
key: "Pragma",
|
|
40
|
+
value: "no-cache",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: "Expires",
|
|
44
|
+
value: "0",
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
/**
|
|
48
|
+
* Edge / CDN optimized cache
|
|
49
|
+
*/
|
|
50
|
+
exports.EDGE_CACHE = [
|
|
51
|
+
{
|
|
52
|
+
key: "Cache-Control",
|
|
53
|
+
value: "public, s-maxage=86400, stale-while-revalidate=604800",
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* Helper function to apply cache headers
|
|
58
|
+
* directly inside next.config.js
|
|
59
|
+
*/
|
|
60
|
+
function applyCache(source, headers) {
|
|
61
|
+
return {
|
|
62
|
+
source,
|
|
63
|
+
headers,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SECURITY_HEADERS = void 0;
|
|
4
|
+
exports.SECURITY_HEADERS = [
|
|
5
|
+
{
|
|
6
|
+
key: "X-Frame-Options",
|
|
7
|
+
value: "DENY",
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
key: "X-Content-Type-Options",
|
|
11
|
+
value: "nosniff",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
key: "Referrer-Policy",
|
|
15
|
+
value: "strict-origin-when-cross-origin",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type RouteChangeEvent = {
|
|
2
|
+
/** Current route URL */
|
|
3
|
+
url: string;
|
|
4
|
+
/** Previous route URL */
|
|
5
|
+
previousUrl: string;
|
|
6
|
+
/** Navigation duration in ms */
|
|
7
|
+
duration: number;
|
|
8
|
+
/** Timestamp when navigation finished */
|
|
9
|
+
timestamp: number;
|
|
10
|
+
};
|
|
11
|
+
type RouteObserverCallback = (event: RouteChangeEvent) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Observe Next.js route changes with performance metrics
|
|
14
|
+
*/
|
|
15
|
+
export declare function observeRoutes(callback: RouteObserverCallback): (() => void) | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* SEO helper – update document title on route change
|
|
18
|
+
*/
|
|
19
|
+
export declare function observeTitle(titleFormatter: (path: string) => string): void;
|
|
20
|
+
/**
|
|
21
|
+
* Analytics helper – plug any analytics provider
|
|
22
|
+
*/
|
|
23
|
+
export declare function observeAnalytics(track: (data: RouteChangeEvent) => void): void;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.observeRoutes = observeRoutes;
|
|
7
|
+
exports.observeTitle = observeTitle;
|
|
8
|
+
exports.observeAnalytics = observeAnalytics;
|
|
9
|
+
const router_1 = __importDefault(require("next/router"));
|
|
10
|
+
let previousUrl = "";
|
|
11
|
+
let startTime = 0;
|
|
12
|
+
/**
|
|
13
|
+
* Observe Next.js route changes with performance metrics
|
|
14
|
+
*/
|
|
15
|
+
function observeRoutes(callback) {
|
|
16
|
+
if (typeof window === "undefined")
|
|
17
|
+
return;
|
|
18
|
+
const handleStart = (url) => {
|
|
19
|
+
startTime = performance.now();
|
|
20
|
+
};
|
|
21
|
+
const handleComplete = (url) => {
|
|
22
|
+
const duration = performance.now() - startTime;
|
|
23
|
+
callback({
|
|
24
|
+
url,
|
|
25
|
+
previousUrl,
|
|
26
|
+
duration,
|
|
27
|
+
timestamp: Date.now(),
|
|
28
|
+
});
|
|
29
|
+
previousUrl = url;
|
|
30
|
+
};
|
|
31
|
+
router_1.default.events.on("routeChangeStart", handleStart);
|
|
32
|
+
router_1.default.events.on("routeChangeComplete", handleComplete);
|
|
33
|
+
return () => {
|
|
34
|
+
router_1.default.events.off("routeChangeStart", handleStart);
|
|
35
|
+
router_1.default.events.off("routeChangeComplete", handleComplete);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* SEO helper – update document title on route change
|
|
40
|
+
*/
|
|
41
|
+
function observeTitle(titleFormatter) {
|
|
42
|
+
if (typeof window === "undefined")
|
|
43
|
+
return;
|
|
44
|
+
observeRoutes(({ url }) => {
|
|
45
|
+
document.title = titleFormatter(url);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Analytics helper – plug any analytics provider
|
|
50
|
+
*/
|
|
51
|
+
function observeAnalytics(track) {
|
|
52
|
+
observeRoutes(track);
|
|
53
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LinkProps } from "next/link";
|
|
2
|
+
import React, { AnchorHTMLAttributes } from "react";
|
|
3
|
+
type AnchorProps = AnchorHTMLAttributes<HTMLAnchorElement>;
|
|
4
|
+
export type SmartLinkProps = LinkProps & AnchorProps & {
|
|
5
|
+
/** Enable intelligent prefetching */
|
|
6
|
+
prefetchOnHover?: boolean;
|
|
7
|
+
/** Delay before prefetch (ms) */
|
|
8
|
+
prefetchDelay?: number;
|
|
9
|
+
/** Disable prefetch completely */
|
|
10
|
+
disablePrefetch?: boolean;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* SmartLink
|
|
14
|
+
* SEO-safe, accessibility-friendly, and performance-optimized
|
|
15
|
+
*/
|
|
16
|
+
export declare const SmartLink: React.FC<SmartLinkProps>;
|
|
17
|
+
export default SmartLink;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.SmartLink = void 0;
|
|
40
|
+
const link_1 = __importDefault(require("next/link"));
|
|
41
|
+
const react_1 = __importStar(require("react"));
|
|
42
|
+
const prefetch_1 = require("./prefetch");
|
|
43
|
+
/**
|
|
44
|
+
* SmartLink
|
|
45
|
+
* SEO-safe, accessibility-friendly, and performance-optimized
|
|
46
|
+
*/
|
|
47
|
+
const SmartLink = ({ href, children, prefetchOnHover = true, prefetchDelay = 150, disablePrefetch = false, onMouseEnter, ...props }) => {
|
|
48
|
+
const handleMouseEnter = (0, react_1.useCallback)((e) => {
|
|
49
|
+
onMouseEnter === null || onMouseEnter === void 0 ? void 0 : onMouseEnter(e);
|
|
50
|
+
if (disablePrefetch || !prefetchOnHover)
|
|
51
|
+
return;
|
|
52
|
+
if (typeof href === "string" && (0, prefetch_1.isFastConnection)()) {
|
|
53
|
+
(0, prefetch_1.prefetchRoute)(href, {
|
|
54
|
+
delay: prefetchDelay,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}, [href, disablePrefetch, prefetchOnHover, prefetchDelay, onMouseEnter]);
|
|
58
|
+
return (react_1.default.createElement(link_1.default, { href: href, passHref: true, legacyBehavior: true },
|
|
59
|
+
react_1.default.createElement("a", { ...props, onMouseEnter: handleMouseEnter }, children)));
|
|
60
|
+
};
|
|
61
|
+
exports.SmartLink = SmartLink;
|
|
62
|
+
exports.default = exports.SmartLink;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type PrefetchOptions = {
|
|
2
|
+
/** Enable or disable prefetch globally */
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
/** Delay before prefetch starts (ms) */
|
|
5
|
+
delay?: number;
|
|
6
|
+
/** Only prefetch when user is idle */
|
|
7
|
+
idleOnly?: boolean;
|
|
8
|
+
/** Custom condition (e.g. network check) */
|
|
9
|
+
condition?: () => boolean;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Intelligent route prefetching for Next.js
|
|
13
|
+
* Prefetches routes when user intent is detected
|
|
14
|
+
*/
|
|
15
|
+
export declare function prefetchRoute(href: string, options?: PrefetchOptions): void;
|
|
16
|
+
/**
|
|
17
|
+
* Prefetch multiple routes safely
|
|
18
|
+
*/
|
|
19
|
+
export declare function prefetchRoutes(routes: string[], options?: PrefetchOptions): void;
|
|
20
|
+
/**
|
|
21
|
+
* Network-aware prefetch condition
|
|
22
|
+
* Prevents prefetch on slow connections
|
|
23
|
+
*/
|
|
24
|
+
export declare function isFastConnection(): boolean;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.prefetchRoute = prefetchRoute;
|
|
7
|
+
exports.prefetchRoutes = prefetchRoutes;
|
|
8
|
+
exports.isFastConnection = isFastConnection;
|
|
9
|
+
const router_1 = __importDefault(require("next/router"));
|
|
10
|
+
/**
|
|
11
|
+
* Intelligent route prefetching for Next.js
|
|
12
|
+
* Prefetches routes when user intent is detected
|
|
13
|
+
*/
|
|
14
|
+
function prefetchRoute(href, options = {}) {
|
|
15
|
+
const { enabled = true, delay = 200, idleOnly = true, condition, } = options;
|
|
16
|
+
if (!enabled)
|
|
17
|
+
return;
|
|
18
|
+
if (typeof window === "undefined")
|
|
19
|
+
return;
|
|
20
|
+
if (condition && !condition())
|
|
21
|
+
return;
|
|
22
|
+
const startPrefetch = () => {
|
|
23
|
+
try {
|
|
24
|
+
router_1.default.prefetch(href);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
console.warn("[next-optimize-sdk] Prefetch failed:", err);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
if (idleOnly && "requestIdleCallback" in window) {
|
|
31
|
+
window.requestIdleCallback(() => {
|
|
32
|
+
setTimeout(startPrefetch, delay);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
setTimeout(startPrefetch, delay);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Prefetch multiple routes safely
|
|
41
|
+
*/
|
|
42
|
+
function prefetchRoutes(routes, options) {
|
|
43
|
+
routes.forEach((route) => prefetchRoute(route, options));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Network-aware prefetch condition
|
|
47
|
+
* Prevents prefetch on slow connections
|
|
48
|
+
*/
|
|
49
|
+
function isFastConnection() {
|
|
50
|
+
if (typeof navigator === "undefined")
|
|
51
|
+
return true;
|
|
52
|
+
const connection = navigator.connection ||
|
|
53
|
+
navigator.mozConnection ||
|
|
54
|
+
navigator.webkitConnection;
|
|
55
|
+
if (!connection)
|
|
56
|
+
return true;
|
|
57
|
+
return !["slow-2g", "2g"].includes(connection.effectiveType);
|
|
58
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type JsonLdProps<T extends object> = {
|
|
3
|
+
/** Schema.org type (e.g. WebSite, Article, Product, FAQPage) */
|
|
4
|
+
type: string;
|
|
5
|
+
/** Schema data object */
|
|
6
|
+
data: T;
|
|
7
|
+
/** Optional ID for deduplication */
|
|
8
|
+
id?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Generic JSON-LD injector for Next.js
|
|
12
|
+
* Safe for SSR, SEO-compliant, and reusable
|
|
13
|
+
*/
|
|
14
|
+
export declare function JsonLd<T extends object>({ type, data, id, }: JsonLdProps<T>): React.JSX.Element | null;
|
|
15
|
+
export default JsonLd;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.JsonLd = JsonLd;
|
|
7
|
+
const head_1 = __importDefault(require("next/head"));
|
|
8
|
+
const react_1 = __importDefault(require("react"));
|
|
9
|
+
/**
|
|
10
|
+
* Generic JSON-LD injector for Next.js
|
|
11
|
+
* Safe for SSR, SEO-compliant, and reusable
|
|
12
|
+
*/
|
|
13
|
+
function JsonLd({ type, data, id, }) {
|
|
14
|
+
if (!data)
|
|
15
|
+
return null;
|
|
16
|
+
const jsonLd = {
|
|
17
|
+
"@context": "https://schema.org",
|
|
18
|
+
"@type": type,
|
|
19
|
+
...data,
|
|
20
|
+
};
|
|
21
|
+
return (react_1.default.createElement(head_1.default, null,
|
|
22
|
+
react_1.default.createElement("script", { id: id, type: "application/ld+json", dangerouslySetInnerHTML: {
|
|
23
|
+
__html: JSON.stringify(jsonLd),
|
|
24
|
+
} })));
|
|
25
|
+
}
|
|
26
|
+
exports.default = JsonLd;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type MetaManagerProps = {
|
|
3
|
+
/** Page title */
|
|
4
|
+
title: string;
|
|
5
|
+
/** Meta description (important for SEO) */
|
|
6
|
+
description: string;
|
|
7
|
+
/** Optional keywords */
|
|
8
|
+
keywords?: string;
|
|
9
|
+
/** Canonical URL (auto-generated if not provided) */
|
|
10
|
+
canonicalUrl?: string;
|
|
11
|
+
/** Open Graph image URL */
|
|
12
|
+
image?: string;
|
|
13
|
+
/** Open Graph type */
|
|
14
|
+
type?: "website" | "article";
|
|
15
|
+
/** Robots meta */
|
|
16
|
+
noIndex?: boolean;
|
|
17
|
+
/** Site name for Open Graph */
|
|
18
|
+
siteName?: string;
|
|
19
|
+
/** Author name */
|
|
20
|
+
author?: string;
|
|
21
|
+
/** Twitter username (without @) */
|
|
22
|
+
twitterHandle?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare const MetaManager: React.FC<MetaManagerProps>;
|
|
25
|
+
export default MetaManager;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MetaManager = void 0;
|
|
7
|
+
const head_1 = __importDefault(require("next/head"));
|
|
8
|
+
const router_1 = require("next/router");
|
|
9
|
+
const react_1 = __importDefault(require("react"));
|
|
10
|
+
const MetaManager = ({ title, description, keywords, canonicalUrl, image, type = "website", noIndex = false, siteName = "My Website", author, twitterHandle, }) => {
|
|
11
|
+
const router = (0, router_1.useRouter)();
|
|
12
|
+
// Auto canonical URL fallback
|
|
13
|
+
const canonical = canonicalUrl ||
|
|
14
|
+
(typeof window !== "undefined"
|
|
15
|
+
? `${window.location.origin}${router.asPath}`
|
|
16
|
+
: "");
|
|
17
|
+
return (react_1.default.createElement(head_1.default, null,
|
|
18
|
+
react_1.default.createElement("title", null, title),
|
|
19
|
+
react_1.default.createElement("meta", { name: "description", content: description }),
|
|
20
|
+
keywords && react_1.default.createElement("meta", { name: "keywords", content: keywords }),
|
|
21
|
+
author && react_1.default.createElement("meta", { name: "author", content: author }),
|
|
22
|
+
react_1.default.createElement("meta", { name: "robots", content: noIndex ? "noindex, nofollow" : "index, follow" }),
|
|
23
|
+
canonical && react_1.default.createElement("link", { rel: "canonical", href: canonical }),
|
|
24
|
+
react_1.default.createElement("meta", { property: "og:type", content: type }),
|
|
25
|
+
react_1.default.createElement("meta", { property: "og:title", content: title }),
|
|
26
|
+
react_1.default.createElement("meta", { property: "og:description", content: description }),
|
|
27
|
+
react_1.default.createElement("meta", { property: "og:site_name", content: siteName }),
|
|
28
|
+
canonical && react_1.default.createElement("meta", { property: "og:url", content: canonical }),
|
|
29
|
+
image && react_1.default.createElement("meta", { property: "og:image", content: image }),
|
|
30
|
+
react_1.default.createElement("meta", { name: "twitter:card", content: "summary_large_image" }),
|
|
31
|
+
twitterHandle && (react_1.default.createElement("meta", { name: "twitter:site", content: `@${twitterHandle}` })),
|
|
32
|
+
react_1.default.createElement("meta", { name: "twitter:title", content: title }),
|
|
33
|
+
react_1.default.createElement("meta", { name: "twitter:description", content: description }),
|
|
34
|
+
image && react_1.default.createElement("meta", { name: "twitter:image", content: image }),
|
|
35
|
+
react_1.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
|
36
|
+
react_1.default.createElement("meta", { name: "theme-color", content: "#000000" })));
|
|
37
|
+
};
|
|
38
|
+
exports.MetaManager = MetaManager;
|
|
39
|
+
exports.default = exports.MetaManager;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function generateAppMetadata({ title, description, image, }: {
|
|
2
|
+
title?: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
image?: string;
|
|
5
|
+
}): {
|
|
6
|
+
title: string;
|
|
7
|
+
description: string;
|
|
8
|
+
openGraph: {
|
|
9
|
+
title: string | undefined;
|
|
10
|
+
description: string | undefined;
|
|
11
|
+
images: string[];
|
|
12
|
+
};
|
|
13
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateAppMetadata = generateAppMetadata;
|
|
4
|
+
const defaults_1 = require("./defaults");
|
|
5
|
+
function generateAppMetadata({ title, description, image, }) {
|
|
6
|
+
return {
|
|
7
|
+
title: title || defaults_1.SEO_DEFAULTS.defaultTitle,
|
|
8
|
+
description: description || defaults_1.SEO_DEFAULTS.defaultDescription,
|
|
9
|
+
openGraph: {
|
|
10
|
+
title,
|
|
11
|
+
description,
|
|
12
|
+
images: image ? [image] : [],
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global SEO defaults for next-optimize-sdk
|
|
3
|
+
* These values can be overridden per page using MetaManager
|
|
4
|
+
*/
|
|
5
|
+
export type SeoDefaults = {
|
|
6
|
+
siteName: string;
|
|
7
|
+
titleTemplate: string;
|
|
8
|
+
defaultTitle: string;
|
|
9
|
+
defaultDescription: string;
|
|
10
|
+
defaultKeywords: string;
|
|
11
|
+
defaultImage: string;
|
|
12
|
+
siteUrl: string;
|
|
13
|
+
twitterHandle?: string;
|
|
14
|
+
themeColor?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Default SEO configuration
|
|
18
|
+
* Override this in your app if needed
|
|
19
|
+
*/
|
|
20
|
+
export declare const SEO_DEFAULTS: SeoDefaults;
|
|
21
|
+
/**
|
|
22
|
+
* Helper to generate full title using template
|
|
23
|
+
*/
|
|
24
|
+
export declare function getSeoTitle(title?: string, template?: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Helper to generate canonical URL
|
|
27
|
+
*/
|
|
28
|
+
export declare function getCanonicalUrl(path: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Merge custom SEO config with defaults
|
|
31
|
+
*/
|
|
32
|
+
export declare function mergeSeoDefaults(overrides?: Partial<SeoDefaults>): SeoDefaults;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Global SEO defaults for next-optimize-sdk
|
|
4
|
+
* These values can be overridden per page using MetaManager
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.SEO_DEFAULTS = void 0;
|
|
8
|
+
exports.getSeoTitle = getSeoTitle;
|
|
9
|
+
exports.getCanonicalUrl = getCanonicalUrl;
|
|
10
|
+
exports.mergeSeoDefaults = mergeSeoDefaults;
|
|
11
|
+
/**
|
|
12
|
+
* Default SEO configuration
|
|
13
|
+
* Override this in your app if needed
|
|
14
|
+
*/
|
|
15
|
+
exports.SEO_DEFAULTS = {
|
|
16
|
+
siteName: "My Website",
|
|
17
|
+
titleTemplate: "%s | My Website",
|
|
18
|
+
defaultTitle: "My Website",
|
|
19
|
+
defaultDescription: "A modern, fast, and SEO-optimized Next.js application.",
|
|
20
|
+
defaultKeywords: "Next.js, SEO, Web Performance, React, Optimization",
|
|
21
|
+
defaultImage: "/og-image.png",
|
|
22
|
+
siteUrl: "https://example.com",
|
|
23
|
+
twitterHandle: "",
|
|
24
|
+
themeColor: "#000000",
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Helper to generate full title using template
|
|
28
|
+
*/
|
|
29
|
+
function getSeoTitle(title, template = exports.SEO_DEFAULTS.titleTemplate) {
|
|
30
|
+
if (!title)
|
|
31
|
+
return exports.SEO_DEFAULTS.defaultTitle;
|
|
32
|
+
return template.replace("%s", title);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Helper to generate canonical URL
|
|
36
|
+
*/
|
|
37
|
+
function getCanonicalUrl(path) {
|
|
38
|
+
if (!path.startsWith("/"))
|
|
39
|
+
path = `/${path}`;
|
|
40
|
+
return `${exports.SEO_DEFAULTS.siteUrl}${path}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Merge custom SEO config with defaults
|
|
44
|
+
*/
|
|
45
|
+
function mergeSeoDefaults(overrides = {}) {
|
|
46
|
+
return {
|
|
47
|
+
...exports.SEO_DEFAULTS,
|
|
48
|
+
...overrides,
|
|
49
|
+
};
|
|
50
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rkk-next",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SEO, routing and performance optimization SDK for Next.js",
|
|
5
|
+
"author": "Rohit Kumar Kundu",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/ROHIT8759/rkk-next.git"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/ROHIT8759/rkk-next/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/ROHIT8759/rkk-next#readme",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"dev": "tsc --watch",
|
|
23
|
+
"prepublishOnly": "npm run build",
|
|
24
|
+
"test": "echo \"Tests coming soon\" && exit 0"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"next": ">=12",
|
|
28
|
+
"react": ">=17",
|
|
29
|
+
"react-dom": ">=17"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^20.10.0",
|
|
33
|
+
"@types/react": "^18.2.45",
|
|
34
|
+
"@types/react-dom": "^18.2.18",
|
|
35
|
+
"typescript": "^5.3.3"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"nextjs",
|
|
39
|
+
"seo",
|
|
40
|
+
"performance",
|
|
41
|
+
"routing",
|
|
42
|
+
"optimization",
|
|
43
|
+
"web-vitals",
|
|
44
|
+
"sdk",
|
|
45
|
+
"rkk-next",
|
|
46
|
+
"react",
|
|
47
|
+
"meta-tags",
|
|
48
|
+
"json-ld",
|
|
49
|
+
"prefetch"
|
|
50
|
+
]
|
|
51
|
+
}
|