Skip to content

Latest commit

 

History

History
86 lines (49 loc) · 7.73 KB

README.md

File metadata and controls

86 lines (49 loc) · 7.73 KB

Implementation of general purpose components for use in the content editor, sites or other projects.

Philosophy

This repo contains many modules that are inter-related. The idea is that each module represents a logical, self-contained component. Consumers can decide to only depend on a subset of the functionality by pulling in just the required set of modules, without having to worry to pull in too many, undesired dependencies.

The major version number of the repo (and all of its components) follows the major version number of Angular and the related tooling. Minor version numbers follow the semantic versioning guidelines and the patch level is the build number assigned by the CI tooling.

None of these modules contains end-user facing UI. The modules are meant to implement or facilitate implementing the business logic layer of an application, without making assumptions on the visual realization.

If a module has a dependency on a particular UI framework such as Angular or React then we typically split the functionality out into multiple modules

  • a framework independent API module for constants and interfaces. This module is shared by different UI frameworks
  • a framework specific API module. This one typically references the framework independent one and adds framework dependent aspects such as dependency injection tokens, etc
  • a framework independent implementation module containing as much code that can be shared across frameworks as possible
  • a framework specific implementation module. This ony typically only contains the framework bindings (e.g. dependency injection) and would dispatch to the framework independent layer

This split makes sense because we want the framework specific modules to make use of the programming concepts of the framework of choice as much as possible. A consumer of the module should find the best practices of the framework represented and not face a custom abstraction that feels alien to the framework. A good example is dependency injection. For Angular we fully embrace the built in DI approach, all services are provides as ngModules and injectable services. For React we rely on the React Context to provide our services. But despite the fundamentally differnt ways to expose and consume services, their implementation is largely the same, kept in the framework independent layer.

Repository structure

The repository is organized as a monorepo that contains of multiple npm packages. Each package implements one particular logical aspect. The repo uses yarn workspaces to manage its build and deployment tasks.

At build and development time all packages use a central copy of npm_modules, this significantly reduces the overall footprint and build times. The scripts/prebuild.ts script makes sure that all components reference the same version of external dependencies, so the whole set of components is consistent within itself.

Build

Call yarn build to build all packages. This uses yarn workspaces to build components in parallel if possible.

Prebuild

The prebuild step makes sure that ...

  • ... the version numbers of all components match the build version. Also there is a VERSION constant in each component that can be used for debugging purposes and the prebuild step makes sure that this constant carries the correct version information and build date
  • ... the versions of the dependencies match the versions managed top level, so all components are consistent

Build

The build generates npm packages for each component. These packages will reside in the dist folder of the components. The build can be run locally by calling yarn build or as part of the CI pipeline. In the CI case it runs the build inside a docker container for isolation and performance reasons.

Postbuild

The postbuild step makes sure that ...

  • ... the metadata.json file is removed from those packages that are not Angular packages. This will significantly speed up their use in Ivy based projects
  • ... the dependencies and peer dependencies are correct. The postbuild step will analyze the generated code to find references and will setup dependencies and peer dependencies accordingly. We can only do this as a postbuild step, since we need the build result for the analysis. From time to time it is advisable to run a full build locally and to checkin the resulting changes.
  • ... the public API gets extracted and documented.

Publish

Release to Global NPM

In order to make the packages available to customers they are published to the the global NPM registry. Use the following command to achieve this (note that npx is NOT a typo):

npx prod-wch-sdk-ng9

This command loads the full and consistent set of modules for the latest version from the internal registry and publishes them globally. In order to publish a particular version run

npx prod-wch-sdk-ng9@<VERSION>

Prereqs:

  • the configured registry points to a registry that contains the build artifacts
  • the configuration contains the npm authentication token, e.g. //registry.npmjs.org/:_authToken=<API_TOKEN>

Modules

Each package in the monorepo will compile to an npm module in Angular Package Format. This format does not limit the use of the packages to Angular in any way but instead exposes the source code in a variety of formats, so the components can be optimally used in a variety of environments.

In particular each module contains typings, an UMD version so the can be used without a compile step and a tree-shakeable version.

Documentation

Each module carries its own documentation as part of JSDoc comments, so documentation is available in the IDE using the components. Also the build process uses api-documenter to generate an API overview as part of the README of each component. This documentation is available directly on the npm page for the individual component.

Dependencies

All modules that are meant to be consumed by applications (in contrast to the CLI modules) are using the following dependency strategy:

  • if a components depends on a component from this monorepo then it uses a dependency and an explicit version number. So all components will reference each other consistently in exactly that version number. It is the prebuild step in the CI environment that guarantees this. Make sure that the source code always uses MAJOR.0.0 for all internal dependencies.
  • if a component has an external dependency, then this will be a peerDependency. This makes sure that consumers will not accidentially pull in multiple copies of a dependency. This repo tries to avoid external dependencies as much as possible, other than dependencies on frameworks such as Angular or React.