Ripple Fullstack (rijs)
rijs (Ripple Fullstack) is a JavaScript framework designed for building realtime, full-stack applications with a focus on simplicity and efficiency. It aims to eliminate boilerplate, complex build pipelines, and excessive transpilation by streaming fine-grained resources directly to clients, enabling lazy loading and preventing over-fetching. The current stable version is 0.9.1. Ripple synchronizes client and server states by replicating an immutable log of actions, with views or other modules reactively updating when the local store changes. Key differentiators include its no-bundling approach, automatic client/server synchronization, and a minimal API for resource management. It promotes a component-based architecture where components are idempotent render functions and can declare their data dependencies for reactive updates. Ripple's core acts as a module map, efficiently resolving resources from a local cache or making new requests. The project appears to have a consistent, though not extremely rapid, release cadence with several notable changes between minor versions, indicating ongoing active development.
Common errors
-
ReferenceError: require is not defined
cause Attempting to use `require()` in a client-side component or a browser environment where CommonJS is not natively supported or transpiled.fixClient-side code should use ES Module `import` syntax or rely on `ripple.pull()` for dynamic resource loading. The main `ripple.js` client script provides globals, not `require`. -
Uncaught ReferenceError: ripple is not defined
cause The client-side `ripple.js` script was not loaded in the HTML page, or custom client-side code is trying to access `ripple` before the script has executed.fixEnsure `<script src="/ripple.js"></script>` is present in your HTML before any scripts that attempt to use `ripple` globals. It's often placed at the end of `<body>`. -
TypeError: (0 , ripple_js__WEBPACK_IMPORTED_MODULE_0__.default) is not a function
cause Incorrectly importing a `rijs` component or resource that expects `export default` as a named import, or vice-versa, in a bundled client-side setup (not typical for `rijs`'s philosophy but possible in hybrid setups).fixEnsure that client-side components use `export default`. If manually bundling or using `rijs/minimal`, verify your bundler's configuration for handling ES Modules and default exports correctly.
Warnings
- breaking The component signature changed in v0.6.3. Components now receive `node` and `data` directly as parameters, making arrow functions for simple components more idiomatic. Older component definitions using a different signature will break.
- deprecated DB and MySQL modules were deprecated in v0.6.3. Ripple no longer provides specific modules for each database/service; users are encouraged to use any standard Node.js database modules directly.
- breaking The `sync` module's API for sending data changed significantly in v0.6.0. The `stream` function was replaced by `send` for a cleaner paradigm.
- breaking `socket.io` was replaced by `uws` and `nanosocket` in v0.8.0. While this primarily impacts internal WebSocket handling, custom integrations or direct `socket.io` usage within a `rijs` application might require adjustments.
- gotcha Ripple aims for no bundling and lazy loading, which means client-side ES Modules (`import ... from './module.js'`) might incur multiple network round-trips for dependencies in the browser, impacting initial load performance. Version 0.9.1 introduced 'Automatic Push' to mitigate this, but developers should be aware of browser module loading characteristics.
- gotcha Client-side component files (e.g., `my-app.js`) are expected to be ES Module exports (`export default ...`) and reside in the `resources` directory for automatic discovery and hot-reloading. Using CommonJS (`module.exports`) or placing them elsewhere will prevent them from being served and recognized by Ripple.
Install
-
npm install rijs -
yarn add rijs -
pnpm add rijs
Imports
- ripple
import ripple from 'rijs'
const ripple = require('rijs') - ripple.js (client-side script)
import { ripple } from 'rijs'<script src="/ripple.js"></script>
- Component export
module.exports = function(node, data){ /* ... */ }export default (node, data) => { /* ... */ } - pull
const dependency = await ripple.pull('dependency')const dependency = await pull('dependency')
Quickstart
const ripple = require('rijs')({ port: 3000, dir: __dirname });
const path = require('path');
const fs = require('fs');
// Create a pages directory if it doesn't exist
const pagesDir = path.join(__dirname, 'pages');
if (!fs.existsSync(pagesDir)) {
fs.mkdirSync(pagesDir);
}
// Create an index.html file
const indexPath = path.join(pagesDir, 'index.html');
fs.writeFileSync(indexPath, `
<!DOCTYPE html>
<html>
<head>
<title>Ripple App</title>
</head>
<body>
<h1>Welcome to Ripple!</h1>
<my-app data="greeting"></my-app>
<script src="/ripple.js"></script>
</body>
</html>
`);
// Create a resources directory if it doesn't exist
const resourcesDir = path.join(__dirname, 'resources');
if (!fs.existsSync(resourcesDir)) {
fs.mkdirSync(resourcesDir);
}
// Define a simple component
const componentPath = path.join(resourcesDir, 'my-app.js');
fs.writeFileSync(componentPath, `
export default (node, { greeting = 'Default Greeting' }) => {
node.innerHTML = `<h2>Component says: ${greeting}</h2>`;
};
`);
// Define a data resource
const dataPath = path.join(resourcesDir, 'greeting.js');
fs.writeFileSync(dataPath, `
export default 'Hello from Ripple Data!';
`);
console.log('Ripple server starting on http://localhost:3000');
console.log('Open your browser to http://localhost:3000/pages/index.html');