@mosaicjs/core v1.0.0
@mosaicjs/core
Framework-agnostic SSR core for Nanoservice-ts - Inertia.js style development experience.
Overview
@mosaicjs/core provides the framework-agnostic protocol logic for MosaicJS, enabling server-side rendering with any frontend framework. It handles the core request/response cycle, component resolution, and data flow patterns that make the Inertia.js development experience possible.
Installation
npm install @mosaicjs/coreCore Concepts
SSRRenderer Interface
The heart of MosaicJS is the SSRRenderer interface that each framework must implement:
interface SSRRenderer {
render(component: string, props: any, url: string): Promise<{ html: string }>;
hasComponent(componentName: string): Promise<boolean>;
getAssets(): { css: string[]; js: string[] };
initialize(): Promise<void>;
close(): Promise<void>;
}MosaicCore Class
The MosaicCore class handles all framework-agnostic logic:
import { MosaicCore, type SSRRenderer } from '@mosaicjs/core';
const core = new MosaicCore(renderer, {
assetsVersion: "1.0.0",
isDev: process.env.NODE_ENV !== "production"
});
// Handle requests
const response = await core.handle(ctx, inputs);BaseMosaic Class
Extend BaseMosaic to create framework-specific nodes:
import { BaseMosaic, type SSRRenderer } from '@mosaicjs/core';
export default class ReactMosaicNode extends BaseMosaic {
constructor() {
const renderer = new ReactSSRRenderer();
super(renderer, { assetsVersion: "1.0.0" });
}
}Configuration
MosaicConfig
interface MosaicConfig {
assetsVersion?: string;
isDev?: boolean;
componentResolver?: (path: string) => string;
sharedPropsResolver?: (ctx: Context) => Record<string, any>;
titleResolver?: (component: string, props: any) => string;
}Component Resolution
The default component resolver follows Inertia.js conventions:
import { deriveComponentFromPath } from '@mosaicjs/core';
// URL to component mapping
deriveComponentFromPath('/') // → 'Home'
deriveComponentFromPath('/about') // → 'About'
deriveComponentFromPath('/dashboard/analytics') // → 'DashboardAnalytics'
deriveComponentFromPath('/error/404') // → 'Error'Shared Props
Configure global data available to all pages:
import { configureSharedProps } from '@mosaicjs/core';
configureSharedProps((ctx) => ({
auth: { user: ctx.request.user || null },
flash: { success: ctx.request.session?.flash?.success || null }
}));Protocol Details
Request Headers
X-Mosaic: true- Indicates XHR request for JSON responseX-Mosaic-Version: 1.0.0- Asset version for cache bustingX-Mosaic-Partial-Data: prop1,prop2- Request specific props onlyX-Mosaic-Partial-Component: ComponentName- Component for partial data
Response Format
HTML Response (Initial Load):
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<link rel="stylesheet" href="/assets/app.css">
</head>
<body>
<div id="app" data-page='{"component":"Home","props":{...},"url":"/","version":"1.0.0"}'>
<!-- SSR content -->
</div>
<script type="module" src="/assets/app.js"></script>
</body>
</html>JSON Response (Navigation):
{
"component": "About",
"props": { "auth": {...}, "pageData": {...} },
"url": "/about",
"version": "1.0.0",
"_headers": {
"X-Mosaic": "true",
"Vary": "X-Mosaic"
}
}Framework Implementation
To create a framework adapter:
- Implement SSRRenderer:
class MyFrameworkSSRRenderer implements SSRRenderer {
async render(component: string, props: any, url: string) {
// Framework-specific SSR logic
return { html: renderedHtml };
}
async hasComponent(componentName: string) {
// Check if component exists
return true;
}
getAssets() {
// Return CSS and JS assets
return { css: [], js: [] };
}
async initialize() {
// Setup framework
}
async close() {
// Cleanup
}
}- Create Node Class:
export default class MyFrameworkMosaicNode extends BaseMosaic {
constructor() {
super(new MyFrameworkSSRRenderer());
}
}- Export Package:
export { default as MosaicNode } from './MyFrameworkMosaicNode';
export * from '@mosaicjs/core';Utilities
Component Resolution
import { deriveComponentFromPath, toPascalCase } from '@mosaicjs/core';Props Management
import { getSharedProps, mergeProps, configureSharedProps } from '@mosaicjs/core';Error Handling
The core handles errors gracefully:
- Version Mismatch (409): Asset version conflicts
- Component Not Found (404): Missing components
- SSR Errors (500): Fallback to client-side rendering
- Validation Errors: Input schema validation
Development vs Production
The core automatically detects environment:
const config = {
isDev: process.env.NODE_ENV !== "production",
assetsVersion: process.env.ASSETS_VERSION || "1.0.0"
};TypeScript Support
Full TypeScript support with strict typing:
import type {
SSRRenderer,
MosaicConfig,
PageData,
MosaicNodeInputs
} from '@mosaicjs/core';License
MIT
11 months ago