← Back to cyclejs/cyclejs

How to Deploy & Use cyclejs/cyclejs

# Cycle.js Deploy & Usage Guide

A comprehensive guide for building and deploying applications with Cycle.js, a functional and reactive JavaScript framework.

## 1. Prerequisites

- **Node.js**: Version 14.x or higher (LTS recommended)
- **Package Manager**: npm 6+ or Yarn 1.22+
- **TypeScript**: Version 4.0+ (required for type definitions)
- **Build Tool**: Webpack, Rollup, Vite, or Parcel (for bundling)
- **Git**: For cloning examples and version control

## 2. Installation

### New Project Setup

Create a new project and install core dependencies:

```bash
mkdir my-cycle-app && cd my-cycle-app
npm init -y
npm install @cycle/run @cycle/dom xstream

Install TypeScript and build tools (optional but recommended):

npm install -D typescript webpack webpack-cli webpack-dev-server ts-loader html-webpack-plugin

Framework Development (Contributing)

To work on the Cycle.js source code:

git clone https://github.com/cyclejs/cyclejs.git
cd cyclejs
npm install

This installs dependencies for the monorepo and links local packages.

3. Configuration

TypeScript Configuration

Create tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2015",
    "module": "ES2015",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "react",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"]
}

Webpack Configuration (Example)

Create webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  resolve: {
    extensions: ['.ts', '.js']
  },
  module: {
    rules: [
      { test: /\.ts$/, use: 'ts-loader', exclude: /node_modules/ }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: 'index.html' })
  ],
  devServer: {
    port: 8080,
    hot: true
  }
};

Debug Configuration (Optional)

For reactive stream debugging, install the devtool:

npm install -D @cycle/devtool

Add to your application entry point:

import {run} from '@cycle/run';
// DevTool automatically detects and visualizes streams when included in build

4. Build & Run

Development Mode

Start the development server:

npx webpack serve --mode development

Or with Vite (faster alternative):

npm install -D vite
# Create vite.config.ts with @cycle/dom plugin support
npx vite

Production Build

Create optimized bundle:

npx webpack --mode production

Output will be in dist/ directory ready for deployment.

Basic Application Structure

Create src/index.ts:

import {run} from '@cycle/run';
import {makeDOMDriver, div, button, h1} from '@cycle/dom';
import xs from 'xstream';

interface Sources {
  DOM: any;
}

interface Sinks {
  DOM: any;
}

function main(sources: Sources): Sinks {
  const decrement$ = sources.DOM.select('.dec').events('click').mapTo(-1);
  const increment$ = sources.DOM.select('.inc').events('click').mapTo(+1);
  
  const count$ = xs.merge(decrement$, increment$)
    .fold((acc, curr) => acc + curr, 0);
    
  const vdom$ = count$.map(count =>
    div([
      button('.dec', 'Decrement'),
      button('.inc', 'Increment'),
      h1(`Count: ${count}`)
    ])
  );
  
  return { DOM: vdom$ };
}

run(main, {
  DOM: makeDOMDriver('#app')
});

Create index.html:

<!DOCTYPE html>
<html>
<head>
  <title>Cycle.js App</title>
</head>
<body>
  <div id="app"></div>
  <script src="bundle.js"></script>
</body>
</html>

5. Deployment

Static Hosting (Recommended)

Cycle.js applications compile to static JavaScript bundles suitable for any static host:

Netlify:

npm run build
netlify deploy --prod --dir=dist

Vercel: Create vercel.json:

{
  "version": 2,
  "builds": [
    { "src": "package.json", "use": "@vercel/static-build" }
  ]
}

GitHub Pages: Push dist/ folder to gh-pages branch or use GitHub Actions.

Server-Side Rendering (SSR)

For SEO or initial load performance, use @cycle/html:

npm install @cycle/html @cycle/run xstream

Server entry (server.ts):

import {run} from '@cycle/run';
import {makeHTMLDriver} from '@cycle/html';
import {app} from './app';

run(app, {
  DOM: makeHTMLDriver((html) => {
    // Send html to HTTP response
    console.log(html);
  })
});

Deploy to Node.js hosting (Heroku, Railway, AWS Elastic Beanstalk).

Docker Deployment

Create Dockerfile:

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 8080
CMD ["npx", "serve", "-s", "dist", "-l", "8080"]

Build and run:

docker build -t cyclejs-app .
docker run -p 8080:8080 cyclejs-app

6. Troubleshooting

Event Delegation Issues

Events not firing? Check the event type bubbles. Non-bubbling events (focus, blur, load, etc.) require special handling:

// Use capture phase for non-bubbling events
sources.DOM.select('input').events('focus', {useCapture: true})

Full list of non-bubbling events: blur, canplay, canplaythrough, durationchange, emptied, ended, focus, load, loadeddata, loadedmetadata, mouseenter, mouseleave, pause, play, playing, ratechange, reset, scroll, seeked, seeking, stalled, submit, suspend, timeupdate, unload, volumechange, waiting.

Memory Leaks

Always return sinks to ensure proper stream disposal:

// Bad - stream not returned
xs.periodic(1000).subscribe({ next: console.log });

// Good - managed by framework
return { DOM: xs.periodic(1000).map(i => div(`${i}`)) };

Isolation Boundaries

Components not receiving events? Ensure proper isolation