N
Nuxt8mo ago
Zampa

Get dynamic array of page names in Nuxt application

I have a scenario where I'd like to add a middleware that references an array of all the page names that exist at the root of the application (i.e. /user, /faq, /about, etc.). Rather than hardcode an array of all those names ['user', 'faq', 'about'], is there some way via Nitro or Nuxt to parse/call to get all the page names that exist within the current Nuxt application?
7 Replies
Zampa
ZampaOP8mo ago
Perhaps this is something Vue Router exposes, or Nitro exposes? This is what AI suggests, but I imagine won't work - but the methodology of iterating through the pages directory on the server-side during middleware execution to build a list of page names seems like the right direction:
import fs from 'node:fs';
import path from 'node:path';

export default defineEventHandler(async (event) => {
// Initialize empty array for page names
const pageNames = [];

// Get the path to the `pages` directory
const pagesDir = path.join(process.cwd(), 'pages');

// Function to recursively iterate through directories
const iterateDirectory = async (dirPath) => {
const files = await fs.promises.readdir(dirPath);
for (const file of files) {
const filePath = path.join(dirPath, file);
const stats = await fs.promises.stat(filePath);

// Check if it's a directory and recurse if needed
if (stats.isDirectory()) {
await iterateDirectory(filePath);
} else if (file.endsWith('.vue') || file.endsWith('.js') || file.endsWith('.ts')) {
// Extract page name from filename (excluding extension)
const pageName = path.basename(file, path.extname(file));
pageNames.push(pageName);
}
}
};

// Start iterating from the `pages` directory
await iterateDirectory(pagesDir);

// Access the page names array in your middleware logic (optional)
// event.context.pageNames = pageNames;

// Middleware doesn't need to return anything
});
import fs from 'node:fs';
import path from 'node:path';

export default defineEventHandler(async (event) => {
// Initialize empty array for page names
const pageNames = [];

// Get the path to the `pages` directory
const pagesDir = path.join(process.cwd(), 'pages');

// Function to recursively iterate through directories
const iterateDirectory = async (dirPath) => {
const files = await fs.promises.readdir(dirPath);
for (const file of files) {
const filePath = path.join(dirPath, file);
const stats = await fs.promises.stat(filePath);

// Check if it's a directory and recurse if needed
if (stats.isDirectory()) {
await iterateDirectory(filePath);
} else if (file.endsWith('.vue') || file.endsWith('.js') || file.endsWith('.ts')) {
// Extract page name from filename (excluding extension)
const pageName = path.basename(file, path.extname(file));
pageNames.push(pageName);
}
}
};

// Start iterating from the `pages` directory
await iterateDirectory(pagesDir);

// Access the page names array in your middleware logic (optional)
// event.context.pageNames = pageNames;

// Middleware doesn't need to return anything
});
I don't see that there's a direct way to read the filesystem in Nitro / h3, since it could be Bun, or Deno, or CF, or what have you
pyplacca
pyplacca8mo ago
Vite’s import.meta.glob might be helpful
Vite
Next Generation Frontend Tooling
Zampa
ZampaOP8mo ago
hmmm
manniL
manniL8mo ago
I'd go with unstorage / useStorage I'd say. But generating that would be better at build time, no? 🙂
Zampa
ZampaOP8mo ago
Yeah, I’d rather do it at build time. I just wasn’t sure what the easiest way would even be to parse all of the page path names that exist in a project
manniL
manniL8mo ago
I'd say just hook into the route extends hook and use the result there 😂
Zampa
ZampaOP8mo ago
Is there a way to hook into the event inside a defineEventHandler in server/middleware that might be able to access the app's routes? I'm ultimately trying to (on the server side - via Nitro) do a 301 redirect, but ONLY if it doesn't match any of the app's existing page names. This is working, but I'd like to replace the paths array with something that dynamically pulls those names:
export default defineEventHandler(async (event) => {
const urlObj = getRequestURL(event);

// don't touch error routes
if (urlObj.pathname === '/__nuxt_error')
return;

const paths = [
'_ipx',
'about',
'api',
'faq',
'fonts',
'images',
'disclaimer',
'blog',
'privacy',
'search',
'login',
'user',
// ... etc,
];

const potentialUsername = urlObj.pathname.split('/')[1];

if (potentialUsername && !paths.includes(potentialUsername) && urlObj.pathname !== '/' && !urlObj.pathname.startsWith('/_ipx'))
return sendRedirect(event, `/user/${potentialUsername}`, 301);
});
export default defineEventHandler(async (event) => {
const urlObj = getRequestURL(event);

// don't touch error routes
if (urlObj.pathname === '/__nuxt_error')
return;

const paths = [
'_ipx',
'about',
'api',
'faq',
'fonts',
'images',
'disclaimer',
'blog',
'privacy',
'search',
'login',
'user',
// ... etc,
];

const potentialUsername = urlObj.pathname.split('/')[1];

if (potentialUsername && !paths.includes(potentialUsername) && urlObj.pathname !== '/' && !urlObj.pathname.startsWith('/_ipx'))
return sendRedirect(event, `/user/${potentialUsername}`, 301);
});
So this in essence does: If we're on a normal page route, proceed.... If not, we might be a username (like domain.com/manniL), so redirect them to domain.com/user/manniL
Want results from more Discord servers?
Add your server