Skip to main content

Monorepo Reference

Purpose: For contributors, provides workspace layout, pnpm commands, CI/CD pipeline, and troubleshooting.

Workspace Layout

headlamp-branding-plugin/
├── plugins/
│ └── branding/ # @opencenter/headlamp-plugin-branding
│ ├── src/
│ │ ├── index.tsx # Plugin entry point (registerAppLogo, registerAppTheme)
│ │ ├── components/
│ │ │ └── AppLogo.tsx # Logo component (light/dark, small/large)
│ │ ├── theme/
│ │ │ ├── index.ts # Re-exports both themes
│ │ │ ├── color.ts # Hex/RGB conversion and blending utilities
│ │ │ ├── opencenter.light.ts # Cloud Day theme definition
│ │ │ └── opencenter.dark.ts # Abyssal Night theme definition
│ │ └── setupTests.ts # Jest DOM matchers
│ ├── assets/
│ │ ├── logo.png # Light theme logo
│ │ └── logo_dark.png # Dark theme logo
│ ├── __tests__/ # Root-level property tests
│ ├── e2e/ # Playwright end-to-end tests
│ ├── dist/ # Build output (generated)
│ ├── package.json
│ ├── tsconfig.json
│ ├── webpack.config.js
│ ├── jest.config.js
│ ├── playwright.config.ts
│ ├── .eslintrc.js
│ └── .prettierrc
├── .github/
│ └── workflows/ # CI/CD workflows
├── package.json # Workspace root (scripts delegate to plugins)
├── pnpm-workspace.yaml # Declares plugins/* as workspace packages
├── pnpm-lock.yaml # Single lockfile for all packages
└── .npmrc # pnpm configuration

pnpm Workspace Configuration

pnpm-workspace.yaml declares the workspace packages:

packages:
- 'plugins/*'

All plugins under plugins/ are automatically discovered. The root package.json defines workspace-level scripts that delegate to all packages.

Commands Reference

Workspace-Wide Commands

CommandDescription
pnpm installInstall dependencies for all packages
pnpm run buildBuild all plugins
pnpm testRun tests across all plugins
pnpm run lintLint all plugins
pnpm run formatFormat all plugins with Prettier
pnpm run format:checkCheck formatting without writing

Plugin-Specific Commands

Use --filter to target a single plugin:

CommandDescription
pnpm --filter @opencenter/headlamp-plugin-branding run devWebpack watch mode
pnpm --filter @opencenter/headlamp-plugin-branding run buildProduction build
pnpm --filter @opencenter/headlamp-plugin-branding testRun Jest tests
pnpm --filter @opencenter/headlamp-plugin-branding run test:coverageTests with coverage report
pnpm --filter @opencenter/headlamp-plugin-branding run test:e2ePlaywright E2E tests
pnpm --filter @opencenter/headlamp-plugin-branding run lintESLint check
pnpm --filter @opencenter/headlamp-plugin-branding run lint:fixESLint auto-fix
pnpm --filter @opencenter/headlamp-plugin-branding run packageCreate distributable ZIP

Build Toolchain

ToolVersionPurpose
Node.js>= 20.0.0Runtime
pnpm>= 9.0.0Package manager
TypeScript^5.7Type checking
webpack^5.97Bundling (main.js as CommonJS2)
ts-loader^9.5TypeScript compilation in webpack
copy-webpack-plugin^14.0Copies package.json and assets/ to dist/
Jest^29.7Unit and property tests
fast-check^4.5Property-based testing
Playwright^1.58End-to-end browser tests
ESLint^9.18Linting
Prettier^3.4Code formatting

Webpack Externals

The webpack config (plugins/branding/webpack.config.js) marks these as externals — they are provided by the Headlamp host at runtime:

externals: {
react: 'react',
'react-dom': 'react-dom',
'@kinvolk/headlamp-plugin/lib': '@kinvolk/headlamp-plugin/lib',
}

Do not bundle these. They must match the versions shipped with Headlamp.

CI/CD Pipeline

On every pull request, GitHub Actions runs:

  1. pnpm install — dependency installation
  2. pnpm run lint — ESLint checks
  3. pnpm run format:check — Prettier formatting check
  4. pnpm test — Jest unit and property tests
  5. pnpm run build — webpack production build
  6. pnpm audit — dependency security audit

On tag push (v*), the pipeline additionally packages the plugin as a ZIP and creates a GitHub release with the artifact attached.

Adding a New Plugin

  1. Create the plugin directory: mkdir -p plugins/my-plugin/src
  2. Add a package.json with the @opencenter/headlamp-plugin- prefix, peerDependencies on @kinvolk/headlamp-plugin, react, and react-dom.
  3. Add a webpack.config.js following the same externals pattern as the branding plugin.
  4. Run pnpm install from the workspace root — the new package is auto-discovered.
  5. The plugin will be included in all workspace-wide commands.

Troubleshooting

pnpm install fails with resolution errors — Clear the store and reinstall:

pnpm store prune
rm -rf node_modules pnpm-lock.yaml plugins/*/node_modules
pnpm install

Workspace command does not find a plugin — Verify the plugin directory is under plugins/ and has a valid package.json with a name field.

TypeScript errors during build — Run pnpm --filter <plugin> run lint to surface type issues. Check that tsconfig.json extends the correct base and includes all source files.

Jest cannot find modules — Confirm jest.config.js has the correct moduleNameMapper entries and that ts-jest is configured as the transform.