platform-docs/development/package-templates.md
Quinn Ftw a32fb786a5 chore(investor-docs): 🔧 Update WHITEPAPER.md and package-templates.md with latest documentation changes
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-02-05 22:10:30 -08:00

13 KiB

Package Templates

Copy-paste templates for the three standard package types in the Lilith Platform. All templates use the lix ecosystem (lixbuild, lixtest, lixrun) for unified build and test tooling.

For full lix ecosystem documentation, see lix-ecosystem.md.


Library Package

Libraries are shared code consumed by features and other packages. They build with tsup via lixbuild and test with vitest via lixtest.

package.json

{
  "name": "@lilith/my-library",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "description": "Description of what this library provides",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    }
  },
  "scripts": {
    "build": "lixbuild",
    "typecheck": "tsc --noEmit",
    "test": "lixtest",
    "test:watch": "lixtest --watch",
    "test:coverage": "lixtest --coverage",
    "lint": "eslint . --ext ts"
  },
  "dependencies": {},
  "devDependencies": {
    "@lilith/lix-configs": "^1.0.1",
    "@types/node": "^20.19.30",
    "tsup": "^8.5.1",
    "typescript": "^5.9.3",
    "vitest": "^4.0.17"
  }
}

tsup.config.ts

import { createLibraryConfig } from '@lilith/lix-configs/tsup/library';

export default createLibraryConfig();

For multiple entry points or custom options:

import { createLibraryConfig } from '@lilith/lix-configs/tsup/library';

export default createLibraryConfig({
  entry: {
    index: 'src/index.ts',
    utils: 'src/utils/index.ts',
  },
  // Inject CSS into JS bundle (for UI component libraries)
  injectStyle: true,
});

vitest.config.ts

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
    passWithNoTests: true,
    include: ['src/**/*.test.ts', 'src/**/*.spec.ts'],
    exclude: ['node_modules/**', 'dist/**'],
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      exclude: [
        'node_modules/**',
        'dist/**',
        '**/*.d.ts',
        '**/*.config.*',
        '**/*.spec.ts',
        '**/*.test.ts',
      ],
    },
  },
});

tsconfig.json

{
  "extends": "@lilith/configs/typescript/library",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Verification

lixbuild detect    # Should show: library (Found tsup.config.ts)
lixbuild           # Build
lixbuild verify    # Confirm output exists
lixtest detect     # Should show: vitest
lixtest            # Run tests

Frontend Package (Vite + React)

Frontend packages are React applications built with Vite via lixbuild, unit-tested with vitest, and E2E-tested with Playwright via lixtest.

package.json

{
  "name": "@lilith/my-frontend",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "lixbuild",
    "preview": "vite preview",
    "typecheck": "tsc --noEmit",
    "lint": "eslint src --ext ts,tsx",
    "test": "lixtest",
    "test:unit": "lixtest --unit",
    "test:e2e": "lixtest --e2e",
    "test:watch": "lixtest --watch",
    "test:coverage": "lixtest --coverage",
    "test:ui": "lixtest --ui",
    "test:e2e:headed": "lixtest --e2e --headed",
    "test:e2e:debug": "lixtest --e2e --debug"
  },
  "dependencies": {
    "@lilith/service-react-bootstrap": "^1.2.0",
    "@lilith/ui-core": "^1.1.1",
    "@lilith/ui-motion": "^2.0.1",
    "@lilith/ui-router": "^1.3.2",
    "@lilith/ui-styled-components": "^6.3.8",
    "@lilith/ui-theme": "^1.3.5",
    "react": "^19.2.3",
    "react-dom": "^19.2.3",
    "react-router-dom": "^7.12.0",
    "styled-components": "^6.3.8"
  },
  "devDependencies": {
    "@lilith/build-core": "^1.3.0",
    "@lilith/lix-configs": "^1.0.1",
    "@lilith/service-registry": "^1.3.0",
    "@playwright/test": "^1.57.0",
    "@testing-library/jest-dom": "^6.9.1",
    "@testing-library/react": "^16.3.1",
    "@testing-library/user-event": "^14.5.2",
    "@types/react": "^19.2.8",
    "@types/react-dom": "^19.2.3",
    "@vitejs/plugin-react": "^4.7.0",
    "@vitest/coverage-v8": "^4.0.17",
    "jsdom": "^25.0.1",
    "tsup": "^8.5.1",
    "typescript": "^5.9.3",
    "vite": "^6.4.1",
    "vitest": "^4.0.17"
  }
}

vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import { platformVite } from '@lilith/build-core';

export default defineConfig({
  plugins: [
    react(),
    platformVite({
      allowedHosts: ['.local'],
    }),
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@features': path.resolve(__dirname, './src/features'),
      '@components': path.resolve(__dirname, './src/components'),
      '@hooks': path.resolve(__dirname, './src/hooks'),
      '@services': path.resolve(__dirname, './src/services'),
      '@store': path.resolve(__dirname, './src/store'),
      '@utils': path.resolve(__dirname, './src/utils'),
    },
  },
  server: {
    host: '0.0.0.0',
    proxy: {
      '/api': {
        target: 'http://localhost:3001',
        changeOrigin: true,
      },
    },
  },
});

vitest.config.ts

import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    passWithNoTests: true,
    setupFiles: ['./vitest.setup.ts'],
    include: ['src/**/*.test.ts', 'src/**/*.spec.ts'],
    exclude: [
      'node_modules/**',
      'dist/**',
      'e2e/**',
      '**/*.d.ts',
    ],
    deps: {
      interopDefault: true,
      optimizer: {
        web: {
          include: ['react', 'react-dom', 'styled-components'],
        },
      },
    },
    server: {
      deps: {
        fallbackCJS: true,
        inline: ['styled-components'],
      },
    },
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      exclude: [
        'node_modules/**',
        'dist/**',
        '**/*.d.ts',
        '**/*.config.*',
        '**/*.spec.ts',
        '**/*.test.ts',
        '**/e2e/**',
        'src/mocks/**',
      ],
    },
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@features': path.resolve(__dirname, './src/features'),
      '@components': path.resolve(__dirname, './src/components'),
      '@hooks': path.resolve(__dirname, './src/hooks'),
      '@services': path.resolve(__dirname, './src/services'),
      '@store': path.resolve(__dirname, './src/store'),
      '@utils': path.resolve(__dirname, './src/utils'),
    },
    dedupe: ['react', 'react-dom', 'styled-components'],
  },
});

playwright.config.ts

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './e2e',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: process.env.CI ? 'list' : 'html',
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:5173',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
});

Verification

lixbuild detect    # Should show: frontend (Found vite.config.ts with React dependency)
lixbuild           # Build
lixtest detect     # Should show: playwright (or vitest if no playwright.config.ts)
lixtest --unit     # Run unit tests
lixtest --e2e      # Run E2E tests

NestJS Backend Package

NestJS backends build with nest build (SWC) via lixbuild, use Jest for testing via lixtest, and include circular dependency verification.

package.json

{
  "name": "@lilith/my-backend-api",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "description": "Backend API for my feature",
  "main": "dist/main.js",
  "scripts": {
    "build": "lixbuild",
    "verify": "bun run build && node scripts/verify-circular-deps.mjs",
    "start": "node dist/main.js",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main.js",
    "typecheck": "tsc --noEmit",
    "lint": "eslint \"src/**/*.ts\"",
    "test": "lixtest",
    "test:watch": "lixtest --watch",
    "test:cov": "lixtest --coverage",
    "test:e2e": "lixtest jest --config jest.e2e.config.cjs --runInBand"
  },
  "dependencies": {
    "@lilith/nestjs-health": "^1.0.0",
    "@lilith/service-nestjs-bootstrap": "^2.2.3",
    "@lilith/service-registry": "^1.3.0",
    "@lilith/typeorm-entities": "^1.0.33",
    "@nestjs/common": "11.1.11",
    "@nestjs/config": "^4.0.2",
    "@nestjs/core": "11.1.11",
    "@nestjs/platform-express": "11.1.11",
    "@nestjs/typeorm": "^11.0.0",
    "class-transformer": "^0.5.1",
    "class-validator": "^0.14.3",
    "pg": "^8.17.1",
    "reflect-metadata": "^0.2.2",
    "rxjs": "^7.8.2",
    "typeorm": "^0.3.28"
  },
  "devDependencies": {
    "@lilith/configs": "^2.2.0",
    "@nestjs/cli": "^11.0.16",
    "@nestjs/schematics": "^11.0.9",
    "@nestjs/testing": "^11.1.12",
    "@swc/cli": "^0.7.10",
    "@swc/core": "^1.15.8",
    "@types/jest": "^29.5.14",
    "@types/node": "^20.19.30",
    "@types/supertest": "^6.0.3",
    "jest": "^29.7.0",
    "supertest": "^7.2.2",
    "ts-jest": "^29.4.6",
    "typescript": "^5.9.3"
  }
}

nest-cli.json

{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "builder": "swc",
    "deleteOutDir": true
  }
}

.swcrc

{
  "$schema": "https://json.schemastore.org/swcrc",
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "decorators": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    },
    "target": "es2022",
    "keepClassNames": true
  },
  "module": {
    "type": "es6",
    "resolveFully": true
  },
  "sourceMaps": true
}

jest.config.cjs

/** @type {import('jest').Config} */
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/src'],
  testMatch: ['**/__tests__/**/*.spec.ts', '**/*.test.ts'],
  testPathIgnorePatterns: ['/node_modules/', '\\.e2e\\.spec\\.ts$'],
  transform: {
    '^.+\\.tsx?$': ['ts-jest', {
      tsconfig: 'tsconfig.json',
    }],
  },
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  collectCoverageFrom: [
    'src/**/*.ts',
    '!src/**/*.spec.ts',
    '!src/**/*.test.ts',
    '!src/**/index.ts',
    '!src/main.ts',
  ],
  coverageDirectory: 'coverage',
  verbose: true,
};

ESM Import Notes

SWC compiles with resolveFully: true, which adds .js extensions to output imports automatically. Source files use extensionless imports:

// Source (correct - no extension)
import { MyService } from './my.service';

// Output (SWC adds .js automatically)
import { MyService } from './my.service.js';

Never add .js extensions in TypeScript source files. If output imports are wrong, fix .swcrc, not the source.

Verification

lixbuild detect    # Should show: nestjs (Found nest-cli.json)
lixbuild           # Build
bun run verify     # Build + check circular dependencies
lixtest detect     # Should show: jest (or use `lixtest jest` for .cjs configs)
lixtest            # Run tests

Import Rules (All Package Types)

All packages must use wrapper imports for shared libraries:

// Styled Components
import styled from '@lilith/ui-styled-components';           // CORRECT
import { ThemeProvider } from '@lilith/ui-styled-components'; // CORRECT
// import styled from 'styled-components';                   // FORBIDDEN

// React Router
import { Link, useNavigate } from '@lilith/ui-router';       // CORRECT
// import { Link } from 'react-router-dom';                  // FORBIDDEN

// Framer Motion
import { motion, AnimatePresence } from '@lilith/ui-motion'; // CORRECT
// import { motion } from 'framer-motion';                   // FORBIDDEN

Validate compliance with: lixrun --imports


Template Files

Ready-to-copy config files are available at tooling/templates/:

tooling/templates/
  library/
    package.json
    tsup.config.ts
    vitest.config.ts
  frontend/
    package.json
    vite.config.ts
    vitest.config.ts
    playwright.config.ts
  nestjs/
    package.json
    nest-cli.json
    .swcrc
    jest.config.cjs

Last Updated: 2026-02-05 See Also: lix-ecosystem.md | lix-migration-guide.md