This guide is for contributors working on @kwiz/common.
The public README.md is intentionally consumer-focused. Build requirements, package architecture, export conventions, testing, and release practices belong here.
- Node.js 18.18+
- npm 9.8.1+
The published package supports Node.js 16+, but the current development toolchain requires Node.js 18.18+.
The repository currently declares:
{
"packageManager": "npm@9.5.1"
}Use the repository's declared npm version when practical.
@kwiz/common should behave like a tree-shakeable TypeScript library.
The package should provide:
- Convenient top-level imports for lightweight/common functionality
- Focused package entry points for heavier feature areas
- A static export-only root entry point
- No generated
exports-indexbarrel files - No post-build scripts that rewrite generated imports
- ESM output that modern bundlers can tree shake effectively
- CommonJS output for compatibility
- Application-agnostic shared functionality
src/ TypeScript source
lib/
esm/ Generated ES module output
cjs/ Generated CommonJS output
types/ Generated TypeScript declarations
test/ Generated test output
All development should be performed under src/.
Files under lib/ are generated build artifacts and should not be treated as source files.
The supported package subpaths are defined by package.json#exports.
Currently:
@kwiz/common
@kwiz/common/auth
@kwiz/common/crypto
@kwiz/common/sharepoint-rest
A source entry file does not automatically make a package subpath public. If a new supported subpath is added, update both:
- the appropriate source entry file; and
package.json#exports.
Do not document a subpath as public unless it is actually present in the export map.
The root entry point is:
src/index.ts
It must remain a static export-only module.
export { something } from "./helpers/something";or:
export * from "./helpers/something";import { something } from "./helpers/something";
export { something };Also avoid executing initialization logic from src/index.ts.
The root should describe the package API surface, not act as an application bootstrapper.
The project previously generated exports-index.* files.
That workflow has been removed.
Do not reintroduce:
create-ts-index
fix-folder-imports.js
reindex-project
remove-all-index-files
Prefer explicit exports maintained in the appropriate entry file.
For lightweight/common functionality intended for the root package:
// src/index.ts
export { getSomething } from "./helpers/getSomething";For functionality belonging to a focused feature area, export it through that feature entry point instead.
Examples:
src/auth.ts
src/crypto.ts
src/sharepoint-rest.ts
If you create a new public package subpath, also add it to package.json#exports.
Not every internal module needs to be publicly exported.
The package declares side-effect metadata in package.json.
Current side-effectful outputs include:
{
"sideEffects": [
"./lib/esm/config.js",
"./lib/cjs/config.js",
"./lib/esm/helpers/polyfill.js",
"./lib/cjs/helpers/polyfill.js",
"./lib/esm/utils/script.js",
"./lib/cjs/utils/script.js",
"./lib/esm/utils/sod.js",
"./lib/cjs/utils/sod.js"
]
}Assume new modules should be side-effect free unless import-time execution is genuinely required.
A side-effect-free module normally only defines or exports functions, classes, constants, and types.
If a module executes logic immediately when imported, determine whether its generated ESM/CJS outputs must be added to package.json#sideEffects.
Do not mark the whole package as side-effectful.
Configuration-dependent functionality and shared logging use config().
The current input contract is:
config({
BuildNumber,
ReleaseStatus,
ProjectName
});Example:
import { config } from "@kwiz/common";
export const { GetLogger, configInfo } = config({
BuildNumber,
ReleaseStatus,
ProjectName: "[my-project]"
});Do not pass IsLocalDev, IsFastRing, or IsProduction.
Those values are derived automatically from ReleaseStatus and exposed through configInfo.
Supported release values are:
dev
fastring
production
npm
For applications with multiple independently loaded Webpack entry points, use a shared bootstrap module or an explicit initialization function so configuration occurs before dependent code runs.
The package targets ES2019.
Do not change the TypeScript target solely to affect tree shaking.
The current optimization strategy relies on:
- ESM output
- Static exports
- Correct
sideEffectsmetadata - Avoiding generated barrels
- Focused package entry points
- Allowing the consuming bundler to analyze the module graph
Changes to the target should be treated as compatibility changes and tested against consuming applications.
npm installBuild ESM and CommonJS output:
npm run buildThe build runs:
npm run build:esm
npm run build:cjs
Individual builds:
npm run build:esm
npm run build:cjsExplain TypeScript build inputs:
npm run build-explainRun the standard test suite:
npm testThe current test script builds CommonJS output, builds the test configuration, and runs Mocha.
The repository also exposes:
npm run unit-testfor the Node test-runner/tsx-based tests under src.
Changes to shared helpers should include tests where practical.
Run:
npm run check-dependencieswhen reviewing dependency relationships or structural changes.
The repository supports both yalc and npm link.
Publish the package to the local yalc store:
npm run yalc-linkThe watch workflow runs the ESM build, CommonJS build, and yalc push helper in parallel:
npm run watchFrom the common repository:
npm run build
npm run npm-linkThen from the consuming project:
npm link @kwiz/commonAfter package changes, rebuild or push the package and rebuild the consuming application.
Compilation alone is not enough for changes involving exports, imports, dependencies, or side effects.
Inspect the consuming application's bundle after significant structural changes.
Look for:
- Unexpected large sections of
@kwiz/common - Modules included without being imported
- Heavy feature areas reachable through unrelated imports
- Side-effectful modules preventing tree shaking
- New dependencies significantly increasing bundle size
Bundle impact should be part of review for package-structure changes.
Before adding a dependency, consider whether:
- The functionality can reasonably be implemented without another package
- The dependency increases consuming bundle size
- The dependency supports tree shaking
- The dependency introduces browser or Node compatibility requirements
- It belongs in
dependencies,devDependencies, orpeerDependencies
Avoid product-specific dependencies unless the module is intentionally product-specific.
When changing shared functionality:
- Keep reusable helpers application-agnostic
- Prefer small focused modules
- Avoid module-level execution unless required
- Keep public exports intentional
- Prefer direct exports from implementation files
- Avoid unnecessary barrel files
- Preserve backward compatibility where practical
- Avoid large dependencies for small utility functions
- Add or update tests where practical
- Build before testing in consumers
- Validate significant changes in at least one real consuming application
- Review bundle impact when changing module structure
For normal package changes:
npm install
npm run build
npm testFor structural changes, also run:
npm run check-dependenciesand inspect an appropriate consuming application's bundle.
Before releasing:
- Source changes are complete
- Public exports are intentional
-
package.json#exportsmatches supported package subpaths - Generated
.d.tscontracts match the intended public API - No generated
exports-indexfiles were introduced - New modules do not introduce unintended import-time side effects
-
sideEffectsmetadata is correct -
npm run buildsucceeds -
npm testsucceeds - Relevant changes were validated in a consuming application
- Bundle impact was reviewed for structural/dependency changes
- Package version was updated appropriately
- The package is released using the approved repository process
The package entry points should act as API surfaces, not application bootstrap code.
entry point
↓
static exports
↓
implementation modules
↓
consumer bundler includes only reachable functionality
Preserving that structure is key to keeping @kwiz/common maintainable and tree-shakeable.
This project is licensed under the MIT License.
Copyright (c) 2024 KWIZ Corp.