Skip to content

Architecture

This document describes the real structure of the TSkeleton repository and how the pieces fit together.

Table of Contents

High-level overview

TSkeleton is a TypeScript library of loading skeleton Web Components. Each component is a custom element that renders a template string plus a shared stylesheet (SKELETON_CSS) into an open shadow root.

src/index.ts ──▶ vite (ES + CJS) ──▶ dist/tskeleton.js, dist/tskeleton.cjs
src/umd.ts   ──▶ vite (UMD)     ──▶ dist/tskeleton.umd.cjs
src/entries/ ──▶ vite (ES + CJS) ──▶ dist/<name>.js, dist/<name>.cjs  (24 subpaths)
scripts/gen-css.mjs ───────────────▶ dist/tskeleton.css
vite-plugin-dts  ──────────────────▶ dist/*.d.ts

Repository layout

TSkeleton/
├── src/
│   ├── core.ts               # SKELETON_CSS, SkeletonBase, configure(), defineSkeleton()
│   ├── register.ts           # REGISTRY (24 tag/class pairs) + registerAll()
│   ├── umd.ts                # UMD entry: registerAll() then re-export index
│   ├── index.ts              # public exports (root entry)
│   ├── demo.ts               # demo playground logic
│   ├── components/           # 24 component classes (one file each)
│   └── entries/              # 24 side-effect entry points (one file each)
├── scripts/
│   ├── smoke.mjs             # jsdom render test for all components
│   ├── gen-css.mjs           # generates dist/tskeleton.css from the built bundle
│   ├── add-parts.mjs         # maintenance helper that adds ::part() hooks to templates
│   └── generate-screenshots.py  # renders Screenshots/*.png with Pillow
├── docs/                     # Markdown documentation (built by MkDocs)
│   ├── index.md              # docs landing page
│   └── assets/               # site assets: logo.svg, favicon.ico, screenshots/
├── Screenshots/              # generated preview images (canonical)
├── dist/                     # build output (gitignored)
├── dist-demo/                # demo site build output (gitignored)
├── site/                     # MkDocs output (gitignored)
├── .github/workflows/
│   ├── docs.yml              # builds docs and deploys to GitHub Pages
│   └── container.yml         # builds and publishes the Docker image to ghcr.io
├── *.html                    # original standalone template files (source material)
├── index.html                # demo playground
├── vite.config.ts            # main build (ES + CJS) + d.ts
├── vite.umd.config.ts        # UMD build
├── vite.sub.config.ts        # subpath builds (24 entries) + d.ts
├── vite.demo.config.ts       # demo playground build (dist-demo/)
├── mkdocs.yml                # MkDocs configuration for the docs site
├── requirements-docs.txt     # Python deps for building the docs site
├── Dockerfile                # multi-stage container image (demo served by nginx)
├── nginx.conf                # non-root nginx config used by the image
├── tsconfig.json             # strict TypeScript config
└── package.json

Core runtime

src/core.ts contains everything the components share:

  • SKELETON_CSS — the stylesheet string injected into every shadow root. It defines .sk blocks, pulse/shimmer keyframes, cards, flex/grid helpers and sizing/spacing utilities.
  • SkeletonBase — abstract base class. Its connectedCallback() attaches an open shadow root and inserts <style>SKELETON_CSS</style> plus the subclass render() output. It also applies theme attributes. Outside the browser it falls back to a plain class so imports are SSR-safe.
  • defineSkeleton(name, ctor) — registers a custom element, ignoring duplicates and non-browser environments.
  • configure(theme) — sets global default CSS variables on :root.

Components and entries

src/components/ holds 24 classes, one per skeleton (for example FacebookSkeleton in facebook.ts). Every class extends SkeletonBase and implements render().

src/register.ts holds the REGISTRY of 24 [tag, class] pairs and registerAll(), which calls defineSkeleton() for each pair.

src/entries/ holds 24 entry points (for example facebook.ts). Each entry calls defineSkeleton('<tag>', Class) as a side effect and re-exports the class. These entries power the tree-shakable subpath imports (tskeleton/facebook and so on).

Build pipeline

The build script runs four steps in order:

  1. build:mainvite build (via vite.config.ts): bundles src/index.ts to dist/tskeleton.js (ES) and dist/tskeleton.cjs (CommonJS), and generates .d.ts files with vite-plugin-dts.
  2. build:umdvite build --config vite.umd.config.ts: bundles src/umd.ts to dist/tskeleton.umd.cjs (global name TSkeleton).
  3. build:subvite build --config vite.sub.config.ts: bundles all 24 entries to dist/<name>.js / dist/<name>.cjs.
  4. build:cssnode scripts/gen-css.mjs: imports the built ES bundle and writes dist/tskeleton.css from SKELETON_CSS.

Each config uses emptyOutDir: false (except the first) so the builds write into the same dist/ directory without wiping each other.

Demo site build

npm run build:demo runs vite build --config vite.demo.config.ts, which builds the playground (index.html + src/demo.ts) into dist-demo/. This is the artifact served by the Docker image.

Documentation site

The docs site is built with MkDocs from docs/ (python -m mkdocs build) and deployed to GitHub Pages by the .github/workflows/docs.yml workflow. See Deployment.

Screenshots

scripts/generate-screenshots.py renders the preview images in Screenshots/ using Pillow. See Screenshots.

Packaging

package.json declares:

  • main./dist/tskeleton.cjs, module./dist/tskeleton.js, types./dist/index.d.ts.
  • unpkg and jsdelivr./dist/tskeleton.umd.cjs for CDN usage.
  • exports map — the root plus 24 subpaths (./facebook, ./github, …), ./styles.css, ./tskeleton.css and ./package.json.
  • sideEffects — lists every subpath bundle so bundlers keep the registration side effects.
  • files — only dist, so the published tarball contains only build output plus README, LICENSE and package.json.

Back to README