PluginModular
Collects information about a set of files or folders and generates a single combined file. Use it when you need a central module based on the project structure: a page registry, widget map, list of public entry points, or route or import configuration.
Unlike PluginReexport, this plugin does not create a file in every matched folder. Instead, it writes one targetFile per configuration.
In watch mode, the plugin responds only to files being added or deleted, ignoring changes to file content.
ts | An array of glob patterns for finding files and folders within |
ts | Determines how matches for entries are processed |
ts | The absolute path of the file to generate |
ts | A template function that returns the target file content |
modules fields
ts | The absolute path of the matched file or folder |
ts | The full name of the matched file or folder, including the extension |
ts | The name from |
ts | The name of the matched entry’s parent folder |
ts | The path from |
ts | The path from |
ts | For |
Example: Central entry points for feature modules
The plugin collects index.ts files from different feature modules into a single file with namespace exports. Each export name comes from the parent folder
new PluginModular([
{
entries: ['features/*/index.ts'],
entryKind: 'file',
targetFile: path.resolve(rootDir, 'features.generated.ts'),
template({ modules }) {
return modules
.map(({ moduleName, relativePath }) => `export * as ${moduleName} from './${relativePath}';`)
.join('\n');
},
},
]),
Run Sandbox
export const featureName = 'orders';
export const featureName = 'profile';
[ARFA-GEN] [write] features.generated.ts
[ARFA-GEN] finished in 0ms
// this file is generated
export * as orders from './features/orders/index';
export * as profile from './features/profile/index';
Example: Page types
The plugin creates types or runtime objects describing each page’s store and actions, where present
new PluginModular([
{
entries: ['pages/*'],
entryKind: 'dir',
targetFile: path.resolve(rootDir, 'modularPages.ts'),
template({ modules }) {
return modules
.map(({ entryName: pageName, files }) => ({
pageName,
storePath: files.find(({ fileName }) => fileName === 'store.ts')?.relativePath,
actionsPath: files.find(({ fileName }) => fileName === 'actions')?.relativePath,
}))
.map(
({ pageName, actionsPath, storePath }) => `export declare const ${pageName}: {
store: ${storePath ? `typeof import('./${storePath}').PageStore` : 'never'};
actions: ${actionsPath ? `typeof import('./${actionsPath}')` : 'never'};
};`
)
.join('\n\n');
},
},
]),
Run Sandbox
export const pageName = 'orders';
export class PageStore {}
export async function createOrder() {}
export const pageName = 'profile';
[ARFA-GEN] [write] modularPages.ts
[ARFA-GEN] finished in 0ms
// this file is generated
export declare const orders: {
store: typeof import('./pages/orders/store').PageStore;
actions: typeof import('./pages/orders/actions');
};
export declare const profile: {
store: never;
actions: never;
};
Example: Feature module routes
The plugin finds feature modules with a routes.ts file and combines their routes. Adding routes.ts includes the module automatically
new PluginModular([
{
entries: ['features/*'],
entryKind: 'dir',
targetFile: path.resolve(rootDir, 'routes.generated.ts'),
template({ modules }) {
const routeModules = modules.flatMap(({ entryName, files }) =>
files
.filter(({ fileName }) => fileName === 'routes.ts')
.map(({ relativePath }) => ({ name: `${entryName}Routes`, relativePath }))
);
const imports = routeModules
.map(({ name, relativePath }) => `import { routes as ${name} } from './${relativePath}';`)
.join('\n');
const routes = routeModules.map(({ name }) => ` ...${name},`).join('\n');
return `${imports}\n\nexport const routes = [\n${routes}\n];`;
},
},
]),
Run Sandbox
export const orders = [];
export const routes = [{ path: '/orders' }];
export const profile = {};
[ARFA-GEN] [write] routes.generated.ts
[ARFA-GEN] finished in 0ms
// this file is generated
import { routes as ordersRoutes } from './features/orders/routes';
export const routes = [
...ordersRoutes,
];
Example: Feature module manifest
Generates a typed description of each feature module’s capabilities based on the files in its directory
new PluginModular([
{
entries: ['features/*'],
entryKind: 'dir',
targetFile: path.resolve(rootDir, 'featureManifest.generated.ts'),
template({ modules }) {
const manifest: Record<string, { hasApi: boolean; hasRoutes: boolean; hasMessages: boolean }> = {};
for (const { entryName, files } of modules) {
const fileNames = new Set(files.map(({ fileName }) => fileName));
manifest[entryName] = {
hasApi: fileNames.has('api.ts'),
hasRoutes: fileNames.has('routes.ts'),
hasMessages: fileNames.has('messages.ts'),
};
}
return `export const featureManifest = ${JSON.stringify(manifest, null, 2)} as const;`;
},
},
]),
Run Sandbox
export async function getOrders() {}
export const routes = [{ path: '/orders' }];
export const messages = {};
export const routes = [{ path: '/profile' }];
[ARFA-GEN] [write] featureManifest.generated.ts
[ARFA-GEN] finished in 0ms
// this file is generated
export const featureManifest = {
"orders": {
"hasApi": true,
"hasRoutes": true,
"hasMessages": true
},
"profile": {
"hasApi": false,
"hasRoutes": true,
"hasMessages": false
}
} as const;