Note: Docs are a work in-progress
- Required: Use the provided CLI to scaffold your new package
- Package Rules
- Package Structure
- Include a
vite.config.ts
file - Include a
package.json
file - Include
tsconfig
files - Include a
README.md
file - Implement your package within a
src/
directory - Component Requirements
- Testing
- Integrate with CI
- Update
CODEOWNERS
After running pnpm install
to ensure your project is up-to-date and pnpm run build
to make sure all dependent packages are available, you must use the provided CLI to create a new package.
pnpm run create-package
This will launch an interactive prompt that will first verify your desired package name is available and then scaffold the required package structure and files.
Once complete, the prompt will output the directory tree that was created and provide additional info on getting started.
Start Coding 🚀
Your new package comes with an interactive sandbox where you can
play with your new component.
Configure the component import and usage inside the
/packages/{workspace}/demo-component/sandbox/ directory.
# Start the dev server
$ pnpm --filter "@kong-ui-public/demo-component" run dev
In addition to the rules defined below, the following rules apply to all packages within this monorepository:
- Packages must not import files that are contained outside of their package root other than for extending the base-level configuration files.
- If you need to utilize shared test fixtures, they should be placed in a subdirectory within
/cypress/fixtures/
at the project root and imported accordingly. - This also includes shared imports in your package's
/{package-name}/sandbox/
directory; if you need shared sandbox data, you should simply duplicate the files across sandboxes. DO NOT import/export for use in other packages.
- If you need to utilize shared test fixtures, they should be placed in a subdirectory within
- Adhere to the Component Requirements
This monorepo comes pre-configured with config files and other settings that ✨ automatically work ✨ for all packages when created via the CLI. In order to take advantage of this shared setup, each project must be structured correctly, including:
- A
README.md
at the package root that explains the purpose of the package, usage instructions, etc. You can create additional.md
files as needed for documentation, but please link to them from the package rootREADME.md
- A
package.json
file in the package root. The packagename
must follow the pattern@kong-ui-public/{package-name}
where{package-name}
is the same as the directory name itself. - A
tsconfig.json
that extends the roottsconfig.json
- A
tsconfig.build.json
that extends the local packagetsconfig.json
- A
vite.config.ts
that extends (viamergeConfig
) the rootvite.config.shared.ts
- All code must be contained within the
{package-name}/src
directory - A file at
src/index.ts
that exports all of the package exports. - If utilizing any text strings, your package must utilize a
src/locales/{lang}.json
file for the text strings and incorporate theuseI18n
helper from@kong-ui-public/core
- All packages are initialized with their own fully-functional Vue sandbox.
The CLI will generate a vite.config.ts
file for you where you can customize additional settings beyond the defaults in the root vite.config.shared.ts
.
If your package has imports that you do not want to be bundled with the package (e.g. axios
), you should pass the dependency name in an array to the build.rollupOptions.external
setting in your package's vite.config.ts
file.
The root vite.config.shared.ts
already externalizes the following dependencies:
vue
vue-router
@kong/kongponents
Any build.rollupOptions.external
setting at the package level will automatically be merged with the array from the root config.
The package.json
file is created automatically after running the CLI. Please consult the package.json
files that are already within existing packages for a complete example.
Some important fields to consider when adding your package.json
are:
Make sure to include all explicitly versioned runtime dependencies within this section. Packages that integrate or augment JS frameworks should not include the core framework dependencies in this section. Instead, these should be defined in peerDependencies
Add the dependency to your package.json
file by package name using the latest package version (as defined in its own package.json
file). For example, if you are developing @kong-ui-public/new-component
and @kong-ui-public/demo-component
already exists as a package within public-ui-components
, add the following to the package.json
file of @kong-ui-public/new-component
:
"dependencies": {
"@kong-ui-public/demo-component": "^1.6.2"
}
where 1.6.2
is the version that's currently listed in the package.json
file of @kong-ui-public/demo-component
within the public-ui-components
repo.
During local development, the local version of @kong-ui-public/demo-component
will be symlinked and used within @kong-ui-public/new-component
.
During our release automation, Lerna will ensure that the version of @kong-ui-public/demo-component
required in the package.json
of @kong-ui-public/new-component
is kept up-to-date. That is, when a new version of @kong-ui-public/demo-component
is released the package.json
file of @kong-ui-public/new-component
is also updated and thus a new version of @kong-ui-public/new-component
is released.
Important: If you are packaging a Vue component, you must include
vue
in thepeerDependencies
. If your component utilizes@kong/kongponents
, they too should be added as apeerDependency
and NOT adependency
.
Include loosely bounded (SemVer-wise) peer deps, i.e. vue
or vue-router
pnpm --filter="@kong-ui-public/demo-component" add --save-peer vue
Common or shared devDependencies
should be added within the monorepo root package.json
file. devDependencies
added within your specific package's package.json
should only include devDependencies
that only apply to your specific package.
To add common or shared devDependencies
:
pnpm add -wD @types/foo
To add package-specific devDependencies
:
pnpm --filter="@kong-ui-public/demo-component" add -D @types/foo
The following scripts should be defined within your package so that it's properly integrated within the monorepo development cycle (and CI/CD). Most of these are pre-configured when generating a new package via the CLI:
dev
to run the local sandbox of your component utilizing the files within the local/sandbox/*
directory.build
to compile/transpile your package into adist/
artifactbuild:package
to build the package for production (will also produce a/packages/{workspace}/{packageName}/bundle-analyzer/stats-treemap.html
file viarollup-bundle-analyzer
that shows the stats and metrics for your package dependencies; see existing packages)build:types
to generate the typesbuild:sandbox
to build your sandbox app as if it being built for production
preview
to run your production build sandbox app locally (requires first runningbuild:sandbox
)lint
to validate your code style/formatting via ESLintlint:fix
to automatically resolve basic code style/formatting issues with ESLinttypecheck
to validate typecheck the codetest:component
- to run Cypress component tests (if applicable)test:unit
- to run Vitest unit tests (if applicable)
Your scripts
section may also contain as many additional scripts as you'd like. However, please note that:
All
scripts
MUST be executed from the root context of the monorepo
So, if you wanted to run lint the code in your package defined as the lint
script command for a package named @kong-ui-public/foo
you would run:
pnpm --filter "@kong-ui-public/demo-component" run lint
The publishConfig
field is important as it marks the package as public for the given organization scope (i.e. @kong-ui-public/
) and leverages pnpm features to rewrite the main
and typings
fields at time of publish. It should look something like:
"publishConfig": {
"access": "public",
}
The files
field specifies which files will be included in the published NPM package (note that some files are automatically included, see NPM docs). In general this should refer to at least the dist/
directory, relative to the published package directory:
"files": ["dist"]
"types": "dist/types/index.d.ts"
Please consult the tsconfig.json
file that is already within existing packages for a complete example.
Each package MUST have a tsconfig.json
file that extends the monorepo root tsconfig.json
. This file can add/override Typescript compiler options as needed by the package. The minimum required tsconfig.json
is generated when running the CLI.
Each package MUST have a tsconfig.build.json
file that extends the local package tsconfig.json
in order to exclude files and types that should be omitted from the build artifact. The minimum required tsconfig.build.json
is generated when running the CLI.
Each package SHOULD include a README.md
file at the root of its package directory. This file should provide installation/usage documentation for consumers of the package. This file should be akin to the root README
file that would exist if the package was a standalone Git repository.
The one exception is the Development
section of the README. It is acceptable to omit that section or include a link/reference to the Development
section of the monorepo root.
All Vue and Typescript source code for your package should live within the src/
directory of your package.
If your component utilizes any components from the Kongponents library, you must not import the components or style file in your package or any of your components (importing into your package's sandbox/index.ts
file is fine.).
Instead, add the Kongponents package in the peerDependencies
of your package.json
file via pnpm --filter "@kong-ui-public/demo-component" add --save-peer @kong/kongponents
and edit your package's README.md
to specify that Kongponents must be globally available in the host application as a Vue plugin.
Design tokens sourced from the @kong/design-tokens
package should be utilized wherever possible.
The SCSS variables are automatically imported and available for use in all Vue components in this repository. JavaScript variables can be imported as needed.
Here's an example:
<template>
<div class="my-component">
<p>My component uses <span :style="{ color: KUI_COLOR_TEXT_PRIMARY }">design tokens</span></p>
</div>
</template>
<script setup lang="ts">
import { KUI_COLOR_TEXT_PRIMARY } from '@kong/design-tokens'
</script>
<style lang="scss">
.my-component {
color: $kui-color-text; // #000933
margin-bottom: $kui-space-60; // 16px
padding: $kui-space-40 $kui-space-0; // 8px 0
}
</style>
If your component needs to allow for style customization, it is highly recommended to utilize the @kong/design-tokens
package along with the CSS custom property values and SCSS variable fallbacks. See here for customization documentation and examples.
If your component needs to provide its own CSS custom properties, the properties must have the prefix --kong-ui-
in order to be valid.
Here's an example of providing customization via a CSS custom property and providing a fallback value sourced from Kong Design Tokens:
.my-component-class {
color: var(--kong-ui-my-component-color-text, $kui-color-text);
}
In order to prevent component styles from leaking out into the consuming application, all component styles MUST adhere to one of the following rules:
-
(Preferred) All styles must be
scoped
within your components with<style lang="scss" scoped>
.- If you need to target nested components (e.g. Kongponents) to override styles, you'll need to utilize deep selectors
<style lang="scss" scoped> .your-component-class { :deep(.k-button) { /* KButton override styles go here */ border-color: red; } } </style>
-
All component styles must be wrapped in a unique wrapper class so that styles do not leak out into the consuming application.
The class name should follow the syntax
.kong-ui-{package-name}
This is a good practice even if you go with option one outlined above.
<style lang="scss"> .kong-ui-public-demo-component { /* All other styles must go inside the wrapper */ } </style>
Styles should never use relative font units; specifically, do not use rem
or em
units.
We cannot control the html
base font size and therefore these relative units are not predictable within a host application. Use px
(pixels) or a similar unit instead.
If your component exposes any CSS variables, they must be prefixed with your package name --kong-ui-{package-name}
For example, the @kong-ui-public/app-layout
package exposes the following CSS variables:
--kong-ui-app-sidebar-mobile-icon-color
All packages should have substantial test coverage comprised of unit and/or component tests.
By convention, all unit tests MUST be included in the src/
directory and follow the *.spec.ts
filename pattern. A unit test can be defined as any test that does not require a visual UI running. Unit tests are run via Vitest.
By convention, component tests MUST be included in the src/
directory and follow the *.cy.ts
filename pattern. A component test can be defined as any test that DOES require a visual UI running. All components within this monorepo should have good component test coverage. Component tests are run via Cypress Component Test Runner.
By following this guide, CI integration should happen automatically. That is, your package will have the following out-of-the-box:
- Dependency Installation
- Linting & Code Validation
- Build
- Component & Unit Tests
- Publishing
Packaging is automatic via the CI. Releases are done via lerna and follow semantic-versioning.
Please update the CODEOWNERS
file at the root of the repository so that it includes your new package and specifies code owners for the package. This way, the code owners specified will automatically be added as reviewers to PRs that make contributions to your package.
Refer to the Github Docs on CODEOWNERS
for more information.