Introduction
ClientServeJS is a client-side file serving library that allows you to serve files directly from the browser without requiring a server. It's perfect for distributing web applications, games, and other content that can run entirely in the browser.
Key features include:
- Service worker-based file serving
- Blob URL mode for browsers without service worker support
- Support for various archive formats (ZIP, CSJ)
- Unity WebGL game support
- Progressive Web App (PWA) support New
- Offline HTML file generation New
- IndexedDB file persistence
Installation
To use ClientServeJS, simply include the script in your HTML file:
<script src="clientserve.js"></script>
The library is designed to function both as the main library and as a service worker. It detects its execution context and behaves accordingly.
Basic Usage
Loading and Serving Files
// Initialize ClientServe
const clientServe = new ClientServe({
path: '/app',
debug: true
});
// Load files from a URL
clientServe.loadFromUrl('https://example.com/myapp.csj', 'csj')
.then(() => {
// Launch the application
clientServe.launch('index.html');
})
.catch(error => {
console.error('Error loading files:', error);
});
Creating a CSJ Archive
CSJ (ClientServeJS) is a custom archive format optimized for web applications. You can create a CSJ file programmatically:
// Create a CSJ archive
const files = {
'index.html': {
content: '<html><body>Hello World</body></html>',
isBinary: false,
type: 'text/html'
},
'image.png': {
content: imageUint8Array,
isBinary: true,
type: 'image/png'
}
};
const metadata = {
title: 'My App',
author: 'Your Name'
};
// Create and download the CSJ file
CSJFormat.createCSJ(files, metadata, 'mypassword')
.then(csjData => {
const blob = new Blob([csjData], { type: 'application/x-clientserve-archive' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'myapp.csj';
a.click();
});
Options
ClientServeJS supports various options to customize its behavior:
| Option | Type | Default | Description |
|---|---|---|---|
| path | string | '/app' | The virtual path where files will be served from |
| showLoadingBar | boolean | true | Whether to show a loading bar during file loading |
| launchMethod | string | 'same-tab' | How to launch the application ('same-tab', 'new-tab', 'popup') |
| debug | boolean | false | Enable debug logging |
| fallbackMode | boolean | true | Whether to fall back to blob URLs if service workers are not supported |
| blobMode | boolean | false | Force using blob URLs instead of service workers |
| unitySupport | boolean | true | Enable Unity WebGL game support |
| persistFiles | boolean | false | Store files in IndexedDB for persistence |
| csjPassword | string | 'clientserve' | Default password for CSJ encryption/decryption |
| enablePWA | boolean | true | Enable Progressive Web App support New |
| offlineSupport | boolean | true | Enable offline support New |
| cacheFiles | boolean | true | Cache files for offline access New |
PWA Support New
ClientServeJS now supports Progressive Web Apps (PWAs), allowing your applications to be installed on devices and work offline.
Requirements
- A valid
manifest.jsonfile in your application - Service worker mode enabled (not blob mode)
- HTTPS connection (required for service workers)
Manifest.json Example
{
"name": "My PWA App",
"short_name": "MyApp",
"description": "A Progressive Web App example",
"start_url": "/app/index.html",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4CAF50",
"icons": [
{
"src": "icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
Enabling PWA Support
const clientServe = new ClientServe({
path: '/app',
enablePWA: true,
offlineSupport: true,
cacheFiles: true
});
Offline Support New
ClientServeJS now provides two ways to enable offline support:
1. Service Worker Caching
When using service worker mode with cacheFiles: true, files are automatically cached for offline access.
2. Standalone Offline HTML Files
You can generate standalone HTML files that work without a server using the new Offline Creator tool or the API:
// Generate an offline HTML file
const options = {
title: 'My Offline App',
startFile: 'index.html',
remoteServiceWorkerUrl: 'https://example.com/clientserve.js',
password: 'mypassword',
customCss: '.my-custom-style { color: red; }',
customJs: 'console.log("Custom script loaded");'
};
clientServe.createOfflineHtml(options)
.then(blob => {
// Download the offline HTML file
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'my-offline-app.html';
a.click();
});
Using the Offline Creator Tool
The Offline Creator tool (offline-creator.html) provides a user-friendly interface for creating offline HTML files from CSJ archives.
file:// URLs. The offline HTML file will connect to the specified remote service worker URL to enable full functionality.
Unity Support
ClientServeJS provides special support for Unity WebGL games, handling the unique requirements of Unity's file structure and loading process.
Unity Blob Mode (Beta)
The new Unity Blob Mode allows Unity games to run in blob URL mode without requiring a service worker:
const clientServe = new ClientServe({
path: '/app',
blobMode: true,
unityBlobMode: true
});
unityBlobFallback: true to automatically switch to service worker mode when Unity files are detected.
API Reference
ClientServe Class
The main class for loading and serving files.
Methods
loadFromUrl(url, type)- Load files from a URL (type can be 'zip', 'csj', etc.)launch(startFile)- Launch the application with the specified start fileloadFromStorage(path)- Load files from IndexedDB storagedeleteFromStorage(path)- Delete files from IndexedDB storagelistStoredPaths()- List all stored paths in IndexedDBcreateOfflineHtml(options)- Create a standalone offline HTML file Newdispose()- Clean up resources
CSJFormat Class
Utilities for working with CSJ archives.
Methods
createCSJ(files, metadata, password)- Create a CSJ archivedecrypt(data, password)- Decrypt a CSJ archiveencrypt(data, password)- Encrypt data using the CSJ formattoBase64(data)- Convert CSJ data to Base64 NewfromBase64(base64)- Convert Base64 to CSJ data New
Examples
Basic Example
<!DOCTYPE html>
<html>
<head>
<title>ClientServeJS Example</title>
<script src="clientserve.js"></script>
</head>
<body>
<h1>ClientServeJS Example</h1>
<button id="load-button">Load Application</button>
<script>
document.getElementById('load-button').addEventListener('click', function() {
const clientServe = new ClientServe({
path: '/app',
debug: true,
showLoadingBar: true
});
clientServe.loadFromUrl('app.csj', 'csj')
.then(() => {
clientServe.launch('index.html');
})
.catch(error => {
console.error('Error:', error);
});
});
</script>
</body>
</html>
PWA Example New
<!DOCTYPE html>
<html>
<head>
<title>ClientServeJS PWA Example</title>
<script src="clientserve.js"></script>
</head>
<body>
<h1>ClientServeJS PWA Example</h1>
<button id="load-button">Load PWA</button>
<script>
document.getElementById('load-button').addEventListener('click', function() {
const clientServe = new ClientServe({
path: '/app',
debug: true,
enablePWA: true,
offlineSupport: true,
cacheFiles: true
});
clientServe.loadFromUrl('pwa-app.csj', 'csj')
.then(() => {
clientServe.launch('index.html');
})
.catch(error => {
console.error('Error:', error);
});
});
</script>
</body>
</html>
Offline HTML Generation Example New
<!DOCTYPE html>
<html>
<head>
<title>ClientServeJS Offline Generator Example</title>
<script src="clientserve.js"></script>
</head>
<body>
<h1>Generate Offline HTML</h1>
<input type="file" id="csj-file" accept=".csj">
<button id="generate-button" disabled>Generate Offline HTML</button>
<script>
const fileInput = document.getElementById('csj-file');
const generateButton = document.getElementById('generate-button');
let csjFile = null;
fileInput.addEventListener('change', function(event) {
if (event.target.files.length > 0) {
csjFile = event.target.files[0];
generateButton.disabled = false;
}
});
generateButton.addEventListener('click', async function() {
if (!csjFile) return;
try {
// Read the CSJ file
const buffer = await csjFile.arrayBuffer();
// Create a ClientServe instance
const clientServe = new ClientServe({
debug: true,
blobMode: true
});
// Extract the CSJ file
const csjData = await CSJFormat.decrypt(new Uint8Array(buffer), 'clientserve');
clientServe.files = csjData.files;
// Generate the offline HTML file
const options = {
title: 'My Offline App',
startFile: 'index.html',
remoteServiceWorkerUrl: window.location.origin + '/clientserve.js'
};
const offlineBlob = await clientServe.createOfflineHtml(options);
// Download the offline HTML file
const url = URL.createObjectURL(offlineBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'offline-app.html';
a.click();
} catch (error) {
console.error('Error:', error);
alert('Error: ' + error.message);
}
});
</script>
</body>
</html>