bsmnt 0.2.0 → 0.2.5
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/README.md +1 -1
- package/package.json +22 -5
- package/src/templates/next-default/.biome/plugins/no-anchor-element.grit +12 -0
- package/src/templates/next-default/.biome/plugins/no-relative-parent-imports.grit +10 -0
- package/src/templates/next-default/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
- package/src/templates/next-default/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- package/src/templates/next-default/.vscode/extensions.json +20 -0
- package/src/templates/next-default/.vscode/settings.json +105 -0
- package/src/templates/next-default/app/favicon.ico +0 -0
- package/src/templates/next-default/app/layout.tsx +104 -0
- package/src/templates/next-default/app/page.tsx +11 -0
- package/src/templates/next-default/app/robots.ts +15 -0
- package/src/templates/next-default/app/sitemap.ts +16 -0
- package/src/templates/next-default/biome.json +2 -2
- package/src/templates/next-default/components/layout/footer/index.tsx +31 -0
- package/src/templates/next-default/components/layout/header/index.tsx +9 -0
- package/src/templates/next-default/components/layout/theme/index.tsx +66 -0
- package/src/templates/next-default/components/layout/wrapper/index.tsx +63 -0
- package/src/templates/next-default/components/ui/README.md +77 -0
- package/src/templates/next-default/components/ui/image/README.md +37 -0
- package/src/templates/next-default/components/ui/image/index.tsx +219 -0
- package/src/templates/next-default/components/ui/link/index.tsx +152 -0
- package/src/templates/next-default/lib/utils/metadata.ts +26 -26
- package/src/templates/next-default/package.json +4 -4
- package/src/templates/next-default/public/fonts/geist/Geist-Mono.woff2 +0 -0
- package/src/templates/next-experiments/app/layout.tsx +18 -18
- package/src/templates/next-experiments/app/robots.ts +3 -3
- package/src/templates/next-experiments/app/sitemap.ts +4 -4
- package/src/templates/next-experiments/biome.json +2 -2
- package/src/templates/next-experiments/components/layout/theme/index.tsx +1 -1
- package/src/templates/next-experiments/components/layout/wrapper/index.tsx +7 -9
- package/src/templates/next-experiments/components/ui/image/index.tsx +39 -46
- package/src/templates/next-experiments/components/ui/link/index.tsx +6 -0
- package/src/templates/next-experiments/lib/utils/metadata.ts +26 -26
- package/src/templates/next-experiments/package.json +4 -4
- package/src/templates/next-webgl/app/layout.tsx +18 -18
- package/src/templates/next-webgl/app/robots.ts +3 -3
- package/src/templates/next-webgl/app/sitemap.ts +4 -4
- package/src/templates/next-webgl/biome.json +2 -2
- package/src/templates/next-webgl/components/layout/theme/index.tsx +1 -1
- package/src/templates/next-webgl/components/layout/wrapper/index.tsx +0 -2
- package/src/templates/next-webgl/components/ui/image/index.tsx +6 -11
- package/src/templates/next-webgl/components/ui/link/index.tsx +9 -2
- package/src/templates/next-webgl/components/webgl/components/scene/index.tsx +1 -0
- package/src/templates/next-webgl/lib/utils/metadata.ts +26 -26
- package/src/templates/next-webgl/package.json +4 -4
- package/src/templates/next-experiments/.cursor/rules/README.md +0 -184
- package/src/templates/next-experiments/.cursor/rules/architecture.mdc +0 -437
- package/src/templates/next-experiments/.cursor/rules/components.mdc +0 -436
- package/src/templates/next-experiments/.cursor/rules/integrations.mdc +0 -447
- package/src/templates/next-experiments/.cursor/rules/main.mdc +0 -278
- package/src/templates/next-experiments/.cursor/rules/styling.mdc +0 -433
- package/src/templates/next-experiments/.github/workflows/lighthouse-to-slack.yml +0 -136
- package/src/templates/next-webgl/.cursor/rules/README.md +0 -184
- package/src/templates/next-webgl/.cursor/rules/architecture.mdc +0 -437
- package/src/templates/next-webgl/.cursor/rules/components.mdc +0 -436
- package/src/templates/next-webgl/.cursor/rules/integrations.mdc +0 -447
- package/src/templates/next-webgl/.cursor/rules/main.mdc +0 -278
- package/src/templates/next-webgl/.cursor/rules/styling.mdc +0 -433
- package/src/templates/next-webgl/.github/workflows/lighthouse-to-slack.yml +0 -136
|
@@ -1,437 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
alwaysApply: true
|
|
3
|
-
---
|
|
4
|
-
---
|
|
5
|
-
description: Architecture patterns, state management, routing, and best practices
|
|
6
|
-
globs: *.tsx, *.jsx, *.css, *.js, *.ts
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Architecture Guidelines
|
|
10
|
-
|
|
11
|
-
## Type Safety
|
|
12
|
-
|
|
13
|
-
### TypeScript Configuration
|
|
14
|
-
- Use TypeScript for all new code
|
|
15
|
-
- Maintain strict type checking
|
|
16
|
-
- Avoid `any` types unless absolutely necessary
|
|
17
|
-
- Use proper type imports (`import type` when importing only types)
|
|
18
|
-
|
|
19
|
-
```tsx
|
|
20
|
-
import type { ComponentProps } from 'react'
|
|
21
|
-
|
|
22
|
-
interface ButtonProps extends ComponentProps<'button'> {
|
|
23
|
-
variant?: 'primary' | 'secondary'
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## State Management
|
|
28
|
-
|
|
29
|
-
### React Built-in State
|
|
30
|
-
Prefer React's built-in state for component state. Keep state as close to where it's used as possible.
|
|
31
|
-
|
|
32
|
-
```tsx
|
|
33
|
-
function Component() {
|
|
34
|
-
const [count, setCount] = useState(0)
|
|
35
|
-
return <button onClick={() => setCount(count + 1)}>{count}</button>
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Zustand for Global State
|
|
40
|
-
Use Zustand for global state when needed. Define stores in `@/lib/store.ts` or dedicated store files.
|
|
41
|
-
|
|
42
|
-
```tsx
|
|
43
|
-
import { create } from 'zustand'
|
|
44
|
-
|
|
45
|
-
interface CartStore {
|
|
46
|
-
items: CartItem[]
|
|
47
|
-
addItem: (item: CartItem) => void
|
|
48
|
-
removeItem: (id: string) => void
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export const useCartStore = create<CartStore>((set) => ({
|
|
52
|
-
items: [],
|
|
53
|
-
addItem: (item) => set((state) => ({ items: [...state.items, item] })),
|
|
54
|
-
removeItem: (id) => set((state) => ({
|
|
55
|
-
items: state.items.filter(item => item.id !== id)
|
|
56
|
-
})),
|
|
57
|
-
}))
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### State Management Best Practices
|
|
61
|
-
- Keep state minimal and derived values computed
|
|
62
|
-
- Use context for shared UI state (theme, modals)
|
|
63
|
-
- Use Zustand for complex global state (cart, user)
|
|
64
|
-
- Avoid prop drilling with composition patterns
|
|
65
|
-
|
|
66
|
-
## Routing & Navigation
|
|
67
|
-
|
|
68
|
-
### Next.js App Router
|
|
69
|
-
Use Next.js App Router conventions. Follow the file-based routing structure.
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
app/
|
|
73
|
-
(pages)/
|
|
74
|
-
home/
|
|
75
|
-
page.tsx
|
|
76
|
-
about/
|
|
77
|
-
page.tsx
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Navigation
|
|
81
|
-
Use the custom Link component for internal navigation. It automatically handles external links.
|
|
82
|
-
|
|
83
|
-
```tsx
|
|
84
|
-
import { Link } from '@/components/ui'
|
|
85
|
-
|
|
86
|
-
function Navigation() {
|
|
87
|
-
return (
|
|
88
|
-
<>
|
|
89
|
-
{/* Internal link - uses next/link */}
|
|
90
|
-
<Link href="/about">About</Link>
|
|
91
|
-
|
|
92
|
-
{/* External link - uses <a> with target="_blank" */}
|
|
93
|
-
<Link href="https://example.com">External</Link>
|
|
94
|
-
</>
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### Metadata & SEO
|
|
100
|
-
Use `@/utils/metadata` for SEO optimization. Generate metadata for all pages.
|
|
101
|
-
|
|
102
|
-
```tsx
|
|
103
|
-
import { generatePageMetadata } from '@/utils/metadata'
|
|
104
|
-
|
|
105
|
-
export async function generateMetadata({ params }) {
|
|
106
|
-
const page = await fetchPage(params.slug)
|
|
107
|
-
|
|
108
|
-
return generatePageMetadata({
|
|
109
|
-
title: page.title,
|
|
110
|
-
description: page.description,
|
|
111
|
-
image: { url: page.image },
|
|
112
|
-
url: `/pages/${params.slug}`,
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Loading and Error States
|
|
118
|
-
Implement proper loading and error states for all routes.
|
|
119
|
-
|
|
120
|
-
```tsx
|
|
121
|
-
// loading.tsx
|
|
122
|
-
export default function Loading() {
|
|
123
|
-
return <div>Loading...</div>
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// error.tsx
|
|
127
|
-
'use client'
|
|
128
|
-
|
|
129
|
-
export default function Error({ error, reset }) {
|
|
130
|
-
return (
|
|
131
|
-
<div>
|
|
132
|
-
<h2>Something went wrong!</h2>
|
|
133
|
-
<button onClick={() => reset()}>Try again</button>
|
|
134
|
-
</div>
|
|
135
|
-
)
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Performance
|
|
140
|
-
|
|
141
|
-
### Server Components
|
|
142
|
-
Use React Server Components by default. Only add 'use client' when needed.
|
|
143
|
-
|
|
144
|
-
```tsx
|
|
145
|
-
// Server Component (default)
|
|
146
|
-
async function ServerComponent() {
|
|
147
|
-
const data = await fetchData()
|
|
148
|
-
return <div>{data.title}</div>
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Client Component (when needed)
|
|
152
|
-
'use client'
|
|
153
|
-
|
|
154
|
-
function ClientComponent() {
|
|
155
|
-
const [state, setState] = useState(0)
|
|
156
|
-
return <button onClick={() => setState(state + 1)}>{state}</button>
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Code Splitting
|
|
161
|
-
Use `next/dynamic` for heavy components. Implement proper loading states.
|
|
162
|
-
|
|
163
|
-
```tsx
|
|
164
|
-
import dynamic from 'next/dynamic'
|
|
165
|
-
|
|
166
|
-
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
|
|
167
|
-
loading: () => <div>Loading...</div>,
|
|
168
|
-
ssr: false // if needed
|
|
169
|
-
})
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Caching Strategies
|
|
173
|
-
Follow Next.js 16 recommended caching strategies. Use appropriate revalidation times.
|
|
174
|
-
|
|
175
|
-
```tsx
|
|
176
|
-
// Static generation with revalidation
|
|
177
|
-
export const revalidate = 3600 // 1 hour
|
|
178
|
-
|
|
179
|
-
// Dynamic with specific cache tags
|
|
180
|
-
export async function fetchData() {
|
|
181
|
-
const res = await fetch('https://api.example.com/data', {
|
|
182
|
-
next: {
|
|
183
|
-
revalidate: 3600,
|
|
184
|
-
tags: ['data']
|
|
185
|
-
}
|
|
186
|
-
})
|
|
187
|
-
return res.json()
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// User-specific data - NEVER cache
|
|
191
|
-
export async function fetchUserCart(userId: string) {
|
|
192
|
-
const res = await fetch(`https://api.example.com/cart/${userId}`, {
|
|
193
|
-
cache: 'no-store' // Required for user-specific data
|
|
194
|
-
})
|
|
195
|
-
return res.json()
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Cache Components (Next.js 16)
|
|
200
|
-
|
|
201
|
-
Cache Components are enabled globally (`cacheComponents: true`). Key considerations:
|
|
202
|
-
|
|
203
|
-
**Suspense Boundaries:**
|
|
204
|
-
```tsx
|
|
205
|
-
import { Suspense } from 'react'
|
|
206
|
-
|
|
207
|
-
export default async function Page() {
|
|
208
|
-
return (
|
|
209
|
-
<Suspense fallback={<Loading />}>
|
|
210
|
-
<DataComponent />
|
|
211
|
-
</Suspense>
|
|
212
|
-
)
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
**Cache Invalidation:**
|
|
217
|
-
```tsx
|
|
218
|
-
import { revalidateTag, revalidatePath } from 'next/cache'
|
|
219
|
-
|
|
220
|
-
// In webhook handlers
|
|
221
|
-
export async function POST(request: Request) {
|
|
222
|
-
revalidateTag('products')
|
|
223
|
-
// or
|
|
224
|
-
revalidatePath('/products/[slug]', 'page')
|
|
225
|
-
return Response.json({ revalidated: true })
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
**⚠️ Critical Rules:**
|
|
230
|
-
- User-specific data: Always use `cache: 'no-store'`
|
|
231
|
-
- Real-time data: Always use `cache: 'no-store'`
|
|
232
|
-
- Test with hard refresh AND navigation
|
|
233
|
-
- Wrap data fetching in Suspense boundaries
|
|
234
|
-
|
|
235
|
-
### Asset Optimization
|
|
236
|
-
- Always use the custom `Image` component (`@/components/ui/image`)
|
|
237
|
-
- Optimize bundles with tree-shaking
|
|
238
|
-
- Check bundle size impact of new dependencies
|
|
239
|
-
- Use `bun lint` to check for linting issues
|
|
240
|
-
|
|
241
|
-
## Security
|
|
242
|
-
|
|
243
|
-
### Environment Variables
|
|
244
|
-
- Never commit API keys
|
|
245
|
-
- Use `.env.local` for development
|
|
246
|
-
- Document required variables in `.env.example`
|
|
247
|
-
- Validate environment variables are set before use
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
// Check required env vars at module load
|
|
251
|
-
const requiredEnvVars = [
|
|
252
|
-
'NEXT_PUBLIC_API_KEY',
|
|
253
|
-
'DATABASE_URL',
|
|
254
|
-
'SANITY_API_TOKEN'
|
|
255
|
-
] as const
|
|
256
|
-
|
|
257
|
-
for (const envVar of requiredEnvVars) {
|
|
258
|
-
if (!process.env[envVar]) {
|
|
259
|
-
throw new Error(`Missing required environment variable: ${envVar}`)
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Input Validation
|
|
265
|
-
Validate all user inputs. Use server-side validation for forms.
|
|
266
|
-
|
|
267
|
-
```tsx
|
|
268
|
-
async function submitForm(formData: FormData) {
|
|
269
|
-
'use server'
|
|
270
|
-
|
|
271
|
-
const email = formData.get('email')
|
|
272
|
-
|
|
273
|
-
// Validate
|
|
274
|
-
if (!email || typeof email !== 'string') {
|
|
275
|
-
return { error: 'Invalid email' }
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Process
|
|
279
|
-
// ...
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### Authentication & Authorization
|
|
284
|
-
- Implement proper authentication
|
|
285
|
-
- Use server-side API calls for sensitive operations
|
|
286
|
-
- Implement rate limiting where necessary
|
|
287
|
-
- Follow CSP guidelines
|
|
288
|
-
|
|
289
|
-
## Testing & Debugging
|
|
290
|
-
|
|
291
|
-
### Unit Testing
|
|
292
|
-
Write unit tests for critical functionality.
|
|
293
|
-
|
|
294
|
-
```tsx
|
|
295
|
-
import { render, screen } from '@testing-library/react'
|
|
296
|
-
import Button from './Button'
|
|
297
|
-
|
|
298
|
-
test('renders button with text', () => {
|
|
299
|
-
render(<Button>Click me</Button>)
|
|
300
|
-
expect(screen.getByText('Click me')).toBeInTheDocument()
|
|
301
|
-
})
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### Debugging Tools
|
|
305
|
-
- Use React DevTools for component inspection
|
|
306
|
-
|
|
307
|
-
### Error Boundaries
|
|
308
|
-
Implement error boundaries for critical sections. Provide meaningful fallback UI.
|
|
309
|
-
|
|
310
|
-
```tsx
|
|
311
|
-
'use client'
|
|
312
|
-
|
|
313
|
-
import { Component } from 'react'
|
|
314
|
-
|
|
315
|
-
class ErrorBoundary extends Component {
|
|
316
|
-
state = { hasError: false }
|
|
317
|
-
|
|
318
|
-
static getDerivedStateFromError(error) {
|
|
319
|
-
return { hasError: true }
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
componentDidCatch(error, errorInfo) {
|
|
323
|
-
console.error('ErrorBoundary caught:', error, errorInfo)
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
render() {
|
|
327
|
-
if (this.state.hasError) {
|
|
328
|
-
return <div>Something went wrong.</div>
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
return this.props.children
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
### Logging Best Practices
|
|
337
|
-
- Use console.log for simple debugging (auto-stripped in production)
|
|
338
|
-
- Use console.error and console.warn for important issues (kept in production)
|
|
339
|
-
- Gate expensive debug operations with `process.env.NODE_ENV === 'development'`
|
|
340
|
-
- Log errors with context for better debugging
|
|
341
|
-
|
|
342
|
-
## Code Quality
|
|
343
|
-
|
|
344
|
-
### Linting & Formatting
|
|
345
|
-
- Follow Biome linting rules
|
|
346
|
-
- Run `bun lint` before committing
|
|
347
|
-
- Maintain consistent code style
|
|
348
|
-
- Fix linting errors immediately
|
|
349
|
-
|
|
350
|
-
### Code Organization
|
|
351
|
-
- Follow the defined project structure
|
|
352
|
-
- Maintain separation of concerns
|
|
353
|
-
- Use meaningful variable and function names
|
|
354
|
-
- Write meaningful comments and documentation
|
|
355
|
-
- Prefer named exports for utilities
|
|
356
|
-
|
|
357
|
-
### Component Composition
|
|
358
|
-
Follow component composition patterns. Keep components focused and reusable.
|
|
359
|
-
|
|
360
|
-
```tsx
|
|
361
|
-
// Good: Composable components
|
|
362
|
-
function Card({ children, className }) {
|
|
363
|
-
return <div className={cn(s.card, className)}>{children}</div>
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function CardHeader({ children }) {
|
|
367
|
-
return <div className={s.header}>{children}</div>
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
function CardBody({ children }) {
|
|
371
|
-
return <div className={s.body}>{children}</div>
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// Usage
|
|
375
|
-
<Card>
|
|
376
|
-
<CardHeader>Title</CardHeader>
|
|
377
|
-
<CardBody>Content</CardBody>
|
|
378
|
-
</Card>
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
## Development Workflow
|
|
382
|
-
|
|
383
|
-
### Package Manager
|
|
384
|
-
Use Bun as the JavaScript runtime and package manager.
|
|
385
|
-
|
|
386
|
-
```bash
|
|
387
|
-
# Install dependencies
|
|
388
|
-
bun install
|
|
389
|
-
|
|
390
|
-
# Run development server (with Turbopack)
|
|
391
|
-
bun dev
|
|
392
|
-
|
|
393
|
-
# Build for production
|
|
394
|
-
bun run build
|
|
395
|
-
|
|
396
|
-
# Run linting
|
|
397
|
-
bun lint
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
### Git Workflow
|
|
401
|
-
- Write meaningful commit messages
|
|
402
|
-
- Use conventional commits when possible
|
|
403
|
-
- Review changes before committing
|
|
404
|
-
- DO NOT use `git push --force` without permission
|
|
405
|
-
- DO NOT skip hooks (--no-verify) unless explicitly requested
|
|
406
|
-
|
|
407
|
-
### Client/Server Boundaries
|
|
408
|
-
Keep client/server boundaries clear. Understand when code runs where.
|
|
409
|
-
|
|
410
|
-
```tsx
|
|
411
|
-
// Server Component
|
|
412
|
-
async function ServerComponent() {
|
|
413
|
-
'use server' // Optional annotation
|
|
414
|
-
const data = await fetchData() // Runs on server
|
|
415
|
-
return <ClientComponent data={data} />
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// Client Component
|
|
419
|
-
'use client'
|
|
420
|
-
|
|
421
|
-
function ClientComponent({ data }) {
|
|
422
|
-
const [state, setState] = useState(data) // Runs on client
|
|
423
|
-
return <div>{state}</div>
|
|
424
|
-
}
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
## Best Practices Summary
|
|
428
|
-
|
|
429
|
-
1. **Type Safety**: Use TypeScript everywhere, avoid `any`
|
|
430
|
-
2. **State Management**: React state first, Zustand for global needs
|
|
431
|
-
3. **Performance**: Server components by default, code splitting for heavy components
|
|
432
|
-
4. **Security**: Validate inputs, secure environment variables, server-side sensitive operations
|
|
433
|
-
5. **Testing**: Write tests for critical paths, use debugging tools effectively
|
|
434
|
-
6. **Code Quality**: Follow linting rules, maintain consistent style, write meaningful documentation
|
|
435
|
-
7. **Development**: Use Bun, follow git best practices, understand client/server boundaries
|
|
436
|
-
|
|
437
|
-
Last updated: 2026-01-26
|