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