TSone

Getting Started

This guide helps you get started quickly with TSone.

Installation

Install the TSone framework and CLI with Bun >=1.3.0:

bun add @geektech/tsone @geektech/tsone-cli

Create Your First Application

1. Create a Simple Component

import { Component, VNode, createApp } from '@geektech/tsone';

interface AppState {
  count: number;
}

class App extends Component<object, AppState> {
  protected initState(): AppState {
    return { count: 0 };
  }

  protected initStyles(): void {
    this.styleManager.addStyle('.app', {
      selector: '.app',
      properties: {
        textAlign: 'center',
        padding: '20px',
      },
    });
  }

  protected render(): VNode {
    return {
      tag: 'div',
      props: { className: 'app' },
      children: [
        { tag: 'h1', children: ['Count: '] },
        {
          tag: 'button',
          props: { className: 'btn' },
          listeners: {
            click: () => this.state.count++,
          },
          children: ['Increment Count'],
        },
      ],
    };
  }
}

2. Create and Mount the Application

export const app = createApp({
  root: App,
  state: {
    appName: 'TSone Example',
  },
  document: { title: 'TSone Example' },
});

app.mount();

You do not need to pass rootElement for the default mount point. createApp uses #app by default, so call app.mount() after creating the application; mounting safely does nothing when the element is not present.

Save the entry as src/main.ts. The CLI requires the named export form export const app, and the exported value must provide renderHtmlDocument().

3. Generate the Document Shell from TypeScript

const app = createApp({
  root: App,
  document: {
    lang: 'en',
    title: 'TSone Example',
    description: 'A TSone counter application',
    body: { tag: 'div', props: { id: 'app' } },
    scripts: [{ type: 'module', src: './index.ts' }],
  },
});

const html = app.renderHtmlDocument();
app.mount();

Configure Development and Builds

The config file supports only a plain-object default export; functional or function-valued config is not supported. The defaults are entry src/main.ts, host 127.0.0.1, port 52211, an empty server.proxy, and build.outDir dist.

import { defineConfig } from '@geektech/tsone-cli';

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
  build: { outDir: 'dist' },
});

A proxy may use the string shorthand '/backend': 'http://localhost:4000'. The development server serves HTTP only. Proxy targets may use HTTP or HTTPS. Literal prefixes use the longest match first. Query strings, bodies, and end-to-end headers are forwarded, changeOrigin updates Host, rewrite changes the pathname, and an unreachable upstream returns 502 Bad Gateway.

Multi-Page Applications

Map additional routes to their own page entries with the pages option. Each page entry satisfies the same export const app contract as the root entry; keys must start with / and may nest, trailing slashes are normalized, and the root / route is always served by entry.

import { defineConfig } from '@geektech/tsone-cli';

export default defineConfig({
  entry: 'src/main.ts',
  pages: {
    '/about': 'src/about.ts',
    '/docs/guide': 'src/guide.ts',
  },
});

During development each page is served at its route, and tsone build emits one HTML document per page (index.html, about.html, docs/guide.html) with asset URLs relative to each document. Site JavaScript entries use content-hashed filenames such as main-<hash>.js, and each document references the emitted filename.

Run the Application

tsone create
tsone dev [--host <host>] [--port <port>] [--no-watch]
tsone build [--out-dir <path>]

create scaffolds a basic TSone project (package.json, tsone.config.ts, tsconfig.json, .gitignore, and a src/main.ts homepage showing the TSone name and a GitHub link) into the current directory and refuses to overwrite existing files. dev accepts host/port overrides plus a --no-watch flag, and build accepts only out-dir. Separated and equals forms such as --port 3000 and --port=3000 are supported. build.outDir must stay a child of the project root.

tsone dev watches the project by default: source, style, or config changes rebuild the current page and notify connected browsers to reload. Watch mode keeps only the latest successful bundle generation for each entry, deleting the previous generation before notifying browsers; old resource URLs return 404. Failed builds keep the last working artifacts without sending a reload notification. A change to tsone.config.ts restarts the server with the fresh configuration, removing the old instance session artifacts after it stops and its pending requests finish. Pass --no-watch to serve as a plain on-demand builder that retains its generations.

CLI v1 has no config plugins, WebSocket, HMR, SSR, functional config, public/ copying, or public minify/sourcemap settings.

Next Steps