Next.js Optional Catch-all Routes | [[...slug]] භාවිතය | Sinhala Guide
![Next.js Optional Catch-all Routes | [[...slug]] භාවිතය | Sinhala Guide](/content/images/size/w1200/2025/09/file-4.png)
ඉතින් කොහොමද යාලුවනේ, ඔයාලා Next.js project එකක් කරනකොට 'dynamic routing' කියන එක ගොඩක් වැදගත් වෙනවා. සාමාන්යයෙන් අපිට තියෙන්නේ fixed paths නේ. හැබැයි සමහර වෙලාවට URL එකේ කොටසක් තියෙන්නත් පුළුවන්, නැතිවෙන්නත් පුළුවන්. උදාහරණයක් විදිහට, ඔයාගේ blog එකක home page එක /blog
වෙන්න පුළුවන්, category page එක /blog/web-development
වෙන්න පුළුවන්, article page එක /blog/web-development/nextjs-tips
වගේ වෙන්නත් පුළුවන්.
මේ වගේ situations manage කරන්න Next.js අපිට සුපිරි feature එකක් දීලා තියෙනවා: ඒ තමයි Optional Catch-all Routes ([[...slug]]
). අද අපි මේක ගැන මුල ඉඳන්ම සිංහලෙන් පැහැදිලිව ඉගෙන ගමු. මේක මොකක්ද, කොහොමද වැඩ කරන්නේ, practical විදිහට implement කරන්නේ කොහොමද, ඒ වගේම මේක පාවිච්චි කරනකොට සැලකිලිමත් වෙන්න ඕන දේවල් මොනවද කියලත් බලමු. සූදානම්ද? එහෙනම් අපි පටන් ගමු!
Next.js Routing Basics (මතක් කිරීමක්)
Optional Catch-all Routes තේරුම් ගන්න කලින්, Next.js වල තියෙන සාමාන්ය dynamic routes ගැන පොඩි අවබෝධයක් තියෙන එක වැදගත්. Next.js App Router (අපි මේ tutorial එකේදී පාවිච්චි කරන්නේ App Router) එකේදී Routes හදන්නේ app
directory එක ඇතුළේ folders විදිහටයි.
1. Dynamic Segments ([slug]
)
ඔයාට URL එකේ තනි කොටසක් (single segment) dynamic කරන්න ඕන නම් [slug]
වගේ syntax එකක් පාවිච්චි කරනවා. slug
කියන එක ඕනම නමක් වෙන්න පුළුවන් ([id]
, [productId]
වගේ).
උදාහරණයක් විදිහට, ඔයාට /products/item-1
, /products/item-2
වගේ paths handle කරන්න ඕන නම්, ඔයා app/products/[slug]/page.js
කියලා file එකක් හදනවා.
// app/products/[slug]/page.js
export default function ProductPage({ params }) {
const productId = params.slug; // params.slug will be 'item-1', 'item-2', etc.
return (
<div>
<h1>Product ID: {productId}</h1>
<p>This page displays details for product <strong>{productId}</strong>.</p>
</div>
);
}
මේකෙන් වෙන්නේ /products/anything
කියන ඕනෑම path එකක් ProductPage
එකට redirect වෙන එකයි. anything
කියන කොටස params.slug
විදිහට අපිට access කරන්න පුළුවන්.
2. Catch-all Routes ([...slug]
)
සමහර වෙලාවට අපිට URL එකේ multiple segments, ඒ කියන්නේ ගොඩක් කොටස් dynamic කරන්න ඕන වෙනවා. උදාහරණයක් විදිහට, /docs/getting-started
, /docs/features/api
, /docs/features/api/v1
වගේ. මේ වගේ වෙලාවට Catch-all Routes පාවිච්චි කරනවා.
මේක හදන්නෙ app/docs/[...slug]/page.js
වගේ file එකක් පාවිච්චි කරලා.
// app/docs/[...slug]/page.js
export default function DocsCatchAll({ params }) {
const docPath = params.slug; // docPath will be an array, e.g., ['getting-started'] or ['features', 'api']
return (
<div>
<h1>Documentation Path: {docPath.join(' / ')}</h1>
<p>Displaying content for the path <strong>/{docPath.join('/')}</strong>.</p>
</div>
);
}
මෙහිදී /docs/anything
, /docs/anything/else
වගේ ඕනෑම path එකක් DocsCatchAll
එකට redirect වෙනවා. params.slug
එක array
එකක් විදිහට අපිට ලැබෙනවා. මේකෙ තියෙන වැදගත්ම දේ තමයි [...slug]
route එක වැඩ කරන්න නම් අනිවාර්යයෙන්ම URL එකේ dynamic segment එකක් තියෙන්න ඕනේ. ඒ කියන්නේ /docs
කියන path එක මේ route එකට match වෙන්නේ නෑ. ඒක handle කරන්න වෙනම app/docs/page.js
එකක් හදන්න වෙනවා.
Next.js Optional Catch-all Routes ([[...slug]]) යනු කුමක්ද?
හරි, දැන් අපි අද අපේ ප්රධාන මාතෘකාවට එමු - Optional Catch-all Routes. මේක [...slug]
route එකට ගොඩක් සමානයි, හැබැයි පොඩි වෙනසක් තියෙනවා: ඒ තමයි මේක 'optional' කියන එක. ඒ කියන්නේ, URL එකේ dynamic segments තියෙන්නත් පුළුවන්, නැතිවෙන්නත් පුළුවන්.
මේක හදන්නේ [[...slug]]
කියන syntax එක පාවිච්චි කරලා. මේ double square brackets ([[ ]]
) වලින් කියවෙන්නේ ඒ ඇතුළේ තියෙන dynamic segments ඔක්කොම optional කියන එකයි. ඒ කියන්නේ, මේ route එකට අදාල base path එකට විතරක් ආවත්, නැත්තම් ඒ base path එකට පස්සේ ඕනෑම segments ගාණක් තිබුණත් මේ route එක match වෙනවා.
[...slug]
සහ [[...slug]]
අතර වෙනස
සරලවම කියනවා නම්:
[...slug]
(Catch-all): මේක match වෙන්න නම් URL එකේ අනිවාර්යයෙන්ම dynamic segment එකක්වත් තියෙන්න ඕනේ. (උදා:/blog/a
,/blog/a/b
- match වෙනවා;/blog
- match වෙන්නේ නෑ).params.slug
හැමවෙලේමstring
වලින් පිරිච්චarray
එකක්.[[...slug]]
(Optional Catch-all): මේක match වෙන්න URL එකේ dynamic segments තියෙන්න ඕනෙම නෑ. Base path එකට විතරක් ආවත් match වෙනවා. (උදා:/blog
,/blog/a
,/blog/a/b
- ඔක්කොම match වෙනවා).params.slug
එකarray
එකක් වෙන්නත් පුළුවන්, නැත්තම්undefined
වෙන්නත් පුළුවන්. Base path එකට (/blog
වගේ) එනකොටparams.slug
එකundefined
වෙනවා.
මේ params.slug
එක undefined
වෙන්න පුළුවන් කියන එක තමයි Optional Catch-all Routes වල තියෙන ලොකුම වෙනස. මේකෙන් අපිට පුළුවන් එකම page.js
file එකකින් base path එකට අදාල content එකයි, ඒකෙ sub-paths වලට අදාල content එකයි දෙකම handle කරන්න.
ප්රායෝගික උදාහරණයක්: Blog Page එකක් හදමු
දැන් අපි Next.js App Router එකත් එක්ක Optional Catch-all Route එකක් implement කරලා බලමු. අපි හිතමු අපිට blog එකක් තියෙනවා කියලා. මේ blog එකේදී:
/blog
: Blog home page එක./blog/web-development
: 'Web Development' category එකේ posts./blog/web-development/nextjs-tips
: 'Next.js Tips' article එක.
මේ හැම path එකක්ම එකම component එකකින් handle කරන්න අපි Optional Catch-all Route එකක් පාවිච්චි කරනවා.
Project Setup
මුලින්ම අපි Next.js project එකක් හදාගමු:
npx create-next-app@latest my-blog-app
cd my-blog-app
Setup wizard එකේදී App Router එක use කරන්න Yes දෙන්න.
`app/blog/[[...slug]]/page.js` නිර්මාණය කිරීම
දැන් app
directory එක ඇතුළේ blog
කියලා folder එකක් හදලා, ඒ ඇතුළේ [[...slug]]
කියලා තවත් folder එකක් හදන්න. අන්තිමට ඒ ඇතුළේ page.js
කියලා file එක හදන්න. Path එක මෙහෙම වෙයි: app/blog/[[...slug]]/page.js
.
දැන් page.js
file එක ඇතුළට මේ code එක දාන්න:
// app/blog/[[...slug]]/page.js
import Link from 'next/link';
// මේක සරල dummy data එකක්, ඔයාට real project එකකදී API එකකින් fetch කරන්න පුළුවන්.
const blogContentMap = {
'': {
title: "Welcome to Our Blog!",
description: "This is the main blog index. Explore our categories and articles.",
links: [
{ href: "/blog/web-development", text: "Web Development Category" },
{ href: "/blog/cloud-computing", text: "Cloud Computing Category" },
{ href: "/blog/web-development/nextjs-tips", text: "Next.js Tips & Tricks" }
]
},
'web-development': {
title: "Web Development Category",
description: "Dive into the world of web development with our latest articles.",
links: [
{ href: "/blog/web-development/nextjs-tips", text: "Next.js Tips & Tricks" },
{ href: "/blog/web-development/react-hooks-guide", text: "React Hooks Guide" }
]
},
'web-development/nextjs-tips': {
title: "Next.js Tips & Tricks",
description: "Master Next.js with these essential tips for better performance and development experience."
},
'cloud-computing': {
title: "Cloud Computing Category",
description: "Explore the vast landscape of cloud services and their applications.",
links: [
{ href: "/blog/cloud-computing/aws-s3-guide", text: "AWS S3 Storage Guide" }
]
},
'cloud-computing/aws-s3-guide': {
title: "AWS S3 Storage Guide",
description: "Learn how to effectively use Amazon S3 for scalable object storage."
}
};
export default function BlogPage({ params }) {
const slug = params.slug; // slug will be undefined or an array of strings
// Convert slug array to a string key for map lookup
const pathKey = slug ? slug.join('/') : '';
const content = blogContentMap[pathKey];
if (!content) {
return (
<div>
<h1>404 - Blog Content Not Found</h1>
<p>The requested blog content could not be found.</p>
<p><Link href="/blog">Back to Blog Home</Link></p>
</div>
);
}
return (
<div style={{ padding: '20px', maxWidth: '800px', margin: 'auto' }}>
<h1>{content.title}</h1>
<p>{content.description}</p>
{content.links && (
<div>
<h3>Explore More:</h3>
<ul>
{content.links.map((link, index) => (
<li key={index}>
<Link href={link.href}>{link.text}</Link>
</li>
))}
</ul>
</div>
)}
<hr style={{ margin: '30px 0' }}/>
<p><Link href="/blog">Back to Blog Home</Link></p>
<div style={{ marginTop: '50px', borderTop: '1px solid #eee', paddingTop: '20px' }}>
<em>Current path: <code>/blog/{pathKey}</code></em><br />
<em>params.slug value: <code>{slug ? JSON.stringify(slug) : 'undefined'}</code></em>
</div>
</div>
);
}
මේ code එකේ අපි කරන්නේ params.slug
එකේ value එක බලලා, ඒ අනුව page එකේ content එක වෙනස් කරන එකයි.
/blog
path එකට එනකොට,params.slug
එකundefined
වෙනවා. ඒ වෙලාවට අපිpathKey
එක''
(empty string) විදිහට අරගෙන blog home page content එක display කරනවා./blog/web-development
path එකට එනකොට,params.slug
එක['web-development']
විදිහට එනවා.pathKey
එක'web-development'
වෙලා, web development category එකට අදාල content එක display කරනවා./blog/web-development/nextjs-tips
වගේ path එකකට එනකොට,params.slug
එක['web-development', 'nextjs-tips']
වගේ එනවා.pathKey
එක'web-development/nextjs-tips'
වෙලා, අදාල article එකේ content එක display කරනවා.
Test Paths
දැන් ඔයාගේ Next.js project එක start කරලා (npm run dev
හෝ yarn dev
) මේ paths වලට ගිහින් බලන්න:
http://localhost:3000/blog
http://localhost:3000/blog/web-development
http://localhost:3000/blog/web-development/nextjs-tips
http://localhost:3000/blog/cloud-computing
http://localhost:3000/blog/cloud-computing/aws-s3-guide
http://localhost:3000/blog/non-existent-path
(මේක 404 handler එක පෙන්නනවා)
ඔයාට පෙනෙයි මේ හැම path එකක්ම app/blog/[[...slug]]/page.js
එකෙන් handle කරනවා කියලා. params.slug
array එකේ value එක path එකට අනුව වෙනස් වෙන හැටිත් පහළටම scroll කරලා බලන්න.
SSR සහ SSG සඳහා generateStaticParams (App Router)
Next.js වල තියෙන තවත් ලොකු වාසියක් තමයි Server-Side Rendering (SSR) සහ Static Site Generation (SSG). අපේ Optional Catch-all Route එකටත් මේවා apply කරන්න පුළුවන්. generateStaticParams
කියන function එකෙන් අපිට පුළුවන් build time එකේදී pre-render කරන්න ඕන paths මොනවද කියලා Next.js ට කියන්න.
අපේ blog එකේදී අපි හිතමු අපිට category pages සහ article pages කිහිපයක් build time එකේදී generate කරන්න ඕන කියලා. ඒ සඳහා generateStaticParams
function එක app/blog/[[...slug]]/page.js
file එකට එකතු කරමු.
// app/blog/[[...slug]]/page.js (modified with generateStaticParams)
import Link from 'next/link';
// Dummy data for demonstration
const blogData = [
{ slug: [], title: "Welcome to Our Blog!", description: "This is the main blog index.", type: "home" },
{ slug: ["web-development"], title: "Web Development Category", description: "Latest in Web Dev.", type: "category" },
{ slug: ["web-development", "nextjs-tips"], title: "Next.js Tips & Tricks", description: "Master Next.js.", type: "post" },
{ slug: ["cloud-computing"], title: "Cloud Computing Insights", description: "Cloud service guides.", type: "category" },
{ slug: ["cloud-computing", "aws-basics"], title: "AWS Basics for Developers", description: "Intro to AWS services.", type: "post" },
];
// generateStaticParams function එක build time එකේදී run වෙනවා
export async function generateStaticParams() {
const paths = blogData.map((item) => ({
slug: item.slug,
}));
// Example: [{ slug: [] }, { slug: ['web-development'] }, { slug: ['web-development', 'nextjs-tips'] }]
return paths;
}
export default function BlogPage({ params }) {
const slug = params.slug; // undefined for /blog, or an array like ['web-development']
// If slug is undefined, treat it as an empty array for comparison
const currentPathSegments = slug || [];
const currentPageData = blogData.find(item =>
JSON.stringify(item.slug) === JSON.stringify(currentPathSegments)
);
if (!currentPageData) {
// This case should ideally not be hit for paths generated by generateStaticParams
// For dynamic paths not pre-rendered, Next.js will try to render on demand
return (
<div>
<h1>404 - Blog Content Not Found</h1>
<p>The requested blog content could not be found.</p>
<Link href="/blog">Back to Blog Home</Link>
</div>
);
}
return (
<div style={{ padding: '20px', maxWidth: '800px', margin: 'auto' }}>
<h1>{currentPageData.title}</h1>
<p>{currentPageData.description}</p>
{/* Simple navigation/links based on current page type */}
<h3>Available Content:</h3>
<ul>
{blogData.filter(item =>
item.slug.length === currentPathSegments.length + 1 &&
item.slug.slice(0, currentPathSegments.length).every((segment, i) => segment === currentPathSegments[i])
).map(item => (
<li key={item.slug.join('/')}>
<Link href={`/blog/${item.slug.join('/')}`}>
{item.title} ({item.type})
</Link>
</li>
))}
</ul>
<p><Link href="/blog">Back to Blog Home</Link></p>
<div style={{ marginTop: '50px', borderTop: '1px solid #eee', paddingTop: '20px' }}>
<em>Current path: <code>/blog/{currentPathSegments.join('/')}</code></em><br />
<em>params.slug value: <code>{slug ? JSON.stringify(slug) : 'undefined'}</code></em>
</div>
</div>
);
}
generateStaticParams
function එක build
process එකේදී run වෙලා, අපි දීලා තියෙන blogData
එකේ slug
වලට අදාලව paths generate කරනවා. මේකෙදී slug: []
කියන එකෙන් /blog
base path එකත් static generate වෙනවා. මේ paths ටික Next.js build එකේදී HTML files විදිහට generate කරනවා. මේකෙන් site එකේ performance එක සහ SEO ගොඩක් වැඩි වෙනවා.
සැලකිය යුතුයි: generateStaticParams
පාවිච්චි කරනකොට, slug: []
කියන item එක return කරන array
එකට දැම්මොත්, /blog
path එකට එනකොට params.slug
එක undefined
විදිහට ලැබෙනවා. මේක Optional Catch-all Routes වලට විශේෂිත දෙයක්.
වැදගත් කරුණු සහ Best Practices
Optional Catch-all Routes කියන්නේ ගොඩක් powerful tool එකක් වුණත්, ඒක පාවිච්චි කරනකොට සැලකිලිමත් වෙන්න ඕන කරුණු කිහිපයක් තියෙනවා:
1. Clarity and Structure
- Path Logic: ඔයාගේ route logic එක පැහැදිලිව තියාගන්න.
params.slug
එකundefined
ද, එහෙම නැත්තම්array
එකක් ද කියලා check කරලා, ඒ අනුව නිවැරදි content එක load කරන්න. - Folder Structure:
app/blog/[[...slug]]/page.js
වගේ පැහැදිලි folder structure එකක් maintain කරන්න.
2. SEO Implications
- Canonical URLs: එකම content එකට paths කිහිපයක් තියෙන්න පුළුවන් නම් (උදා:
/blog
සහ/blog/index
වගේ), search engines වලට කියන්න canonical URL එක මොකක්ද කියලා. මේකට<link rel="canonical" href="..." />
tag එක පාවිච්චි කරන්න පුළුවන්. - Meaningful URLs: URL segments වලට අදාල keywords පාවිච්චි කරන්න. මේක search engine ranking වලට උදව් වෙනවා.
3. Over-use Avoidance
Optional Catch-all Routes ගොඩක් flexible වුණත්, හැම route එකකටම මේක පාවිච්චි කරන්න හොඳ නෑ. ගොඩක් සංකීර්ණ logic එකක් ගොඩනැගෙන්න පුළුවන්. සරල static paths වලට, එහෙම නැත්තම් තනි dynamic segment එකක් තියෙන paths වලට [slug]
වගේ routes පාවිච්චි කරන එක වඩාත් හොඳයි.
4. Error Handling (404s)
ඔයාගේ [[...slug]]
route එකට match වෙන content එකක් නැති වුණොත්, නිවැරදිව 404 error page එකක් display කරන එක වැදගත්. අපේ උදාහරණයේදී අපි if (!content)
කියලා සරල 404 message එකක් පෙන්නුවා. Next.js App Router එකේදී not-found.js
file එකක් හදලා custom 404 page එකක් හදන්නත් පුළුවන්.
5. Performance Considerations
generateStaticParams
හරියට පාවිච්චි කරන එකෙන් performance එක ගොඩක් වැඩි කරගන්න පුළුවන්. නිතර වෙනස් නොවන content pre-render කරන එකෙන්, user ට ඉක්මනින් page load කරගන්න පුළුවන් වෙනවා.
නිගමනය
ඉතින් යාලුවනේ, අද අපි Next.js වල තියෙන Optional Catch-all Routes ([[...slug]]
) කියන powerful feature එක ගැන විස්තරාත්මකව ඉගෙන ගත්තා. මේක පාවිච්චි කරලා කොහොමද flexible, dynamic URLs handle කරන්නේ කියලා අපි දැක්කා. /blog
වගේ base paths වලටත්, /blog/category/article
වගේ multi-segment paths වලටත් එකම component එකකින් content load කරගන්න පුළුවන් විදිහ අපි code example එකකින් බැලුවා.
මේ feature එක ඔයාගේ Next.js project වල routing logic එක ගොඩක් සරල කරගන්න උදව් වෙයි කියලා මම හිතනවා. විශේෂයෙන්ම documentation sites, blogs, product catalogs වගේ dynamic content ගොඩක් තියෙන applications වලට මේක ගොඩක් ප්රයෝජනවත්.
දැන් ඔයාට පුළුවන් මේ concepts ඔයාගේ next project එකේදී implement කරලා බලන්න. ඔයාට මේ ගැන ප්රශ්න තියෙනවා නම්, එහෙම නැත්තම් ඔයාගේ අත්දැකීම් කොහොමද කියලා comment section එකේ share කරන්න අමතක කරන්න එපා. අපි ඊළඟ tutorial එකකින් හමුවෙමු!