Front-end package manager
Handles the creation, validation, and publication of packages built as part of the Springer Nature Elements Design System. More information on how this is used can be found within the developer documentation for Elements.
The Design System is made up of different toolkits
that contain packages
designed for use with different brands
within the Springer Nature ecosystem.
Packages are bundles of front-end assets (HTML, CSS, JS, images, tests etc...) that are published via NPM and used within the Springer Nature ecosystem. It is expected that multiple toolkits and packages live within one repository (monorepo).
Repository structure
The package manager expects the following repository structure:
repository-monorepo
└── context
└── name-of-context-package
└── toolkits
├── name-of-toolkit
└── packages
├── name-of-package
└── name-of-other-package
├── name-of-toolkit
└── packages
└── name-of-package
└── name-of-toolkit
└── packages
└── name-of-package
Where each individual toolkit (collection of packages) lives within a toolkits
folder, and the packages within that toolkit live within a packages
folder.
The package manager is used within the Springer Nature Front-End Toolkits repository.
Install
$ npm install --save-dev @springernature/frontend-package-manager
Installing frontend-package-manager
adds package management exectuables to ./node_modules/.bin/
.
Configuration
The package manager is configurable to enforce consistency across packages that are created. Below is the default configuration that is supplied:
Default configuration
{
"scope": "springernature",
"toolkitsDirectory": "toolkits",
"packagesDirectory": "packages",
"changelog": "HISTORY.md",
"required": [
"README.md",
"package.json"
]
}
scope
Type: String
All packages must be published under an organisation scope on NPM. By default packages within the Springer Nature ecosystem are published to the company scope.
toolkitsDirectory
Type: String
Defines the parent folder under which toolkits live (see example structure above), and can NOT be changed.
packagesDirectory
Type: String
Defines the parent folder under which packages live within a specific toolkit (see example structure above), and can NOT be changed.
changelog
Type: String
All packages MUST have a changelog file in their root directory.
required
Type: Array
An array of top level files that MUST appear in any package. There is no need to specify the changelog file here, it is added automatically.
Extending the default configuration
The default configuration options provided can be overriden and/or extended in one of two ways:
Repository
By providing a package-manager.json
file at the root of the toolkits
folder of your repository. Configuration options defined here will extend/override those in the default (with the exception of the toolkitsDirectory
and packagesDirectory
options), and are inherited by all toolkits.
Toolkit
By providing a package-manager.json
file in a specific toolkit folder e.g. toolkits > name-of-toolkit
. Configuration options defined here will extend/override those at both the default and repository level (with the exception of the toolkitsDirectory
and packagesDirectory
options), and are used by just a single toolkit.
Configuration options
The configuration files should take the same format as the default configuration, and can also add the following options:
prefix
Type: String
Package names can specify a prefix that namespaces them within NPM, based on which toolkit they live within.
For example all component packages published via the global toolkit use the prefix global
, they will appear on NPM as @springernature/global-name-of-component
folders
Type: Object
A folders object can be added to the config. This contains keys that map to any folder names that are allowed within a package, with their value being an array of allowed file extensions within that folder.
If the folders
key is present then these folders are the only ones allowed (but are optional). The folders can contain any number of sub-folders with no restriction on naming, but the file extensions within these sub-folders must match the array.
If the folders
key is not present then any folders/files are allowed, with no restrictions.
The following example would allow a folder with the name js
that contains files with the extensions .js
and .json
:
"folders": {
"js": [
"js",
"json"
]
}
CSSDirectoryStructure
Type: Object
This option allows you to specify a custom CSS folder structure. This is used in the package creation step to generate a sub-folder structure within a specified folder, to assist in quickly spinning up a new package. It is also used in the validation step to make sure that only valid CSS subdirectory naming is used.
The following shows an example folder structure, taken from the Springer Nature Front-End Toolkits repository:
"CSSDirectoryStructure": {
"scss": [
"10-settings",
"20-functions",
"30-mixins",
"50-components"
]
}
In the above example, the object key scss
, needs to match a key of the same name from the folders option mentioned above, to enable the sub-folders to be created in the correct parent.
enforceBrandFileNaming
Type: Array
This option accepts an array of folder paths that is used to enforce that all files contained in those folders are named after a valid brand (See the context section below for more information on branding).
"enforceBrandFileNaming": [
"scss/10-settings"
]
If we have the brands brandA
and brandB
configured, then in the above example the only filenames allowed (where ext
can be any file extension) within the scss/10-settings
folder would be:
brandA.ext
_brandA.ext
brandB.ext
_brandB.ext
Context
In addition to the toolkits
folder there is also a context
folder. This folder contains a single package that is split into brands
and contains brand specific configurations and baseline styles that are used by other packages. The folder structure looks like this:
repository-monorepo
└── context
└── name-of-context-package
├── brand-name
└── other-brand-name
The context package accepts the following default configuration which can be extended/overriden using a package-manager.json
configuration within the context
folder:
{
"scope": "springernature",
"prefix": "brand",
"contextDirectory": "context",
"brandContextName": "brand-context",
"brands": [],
"changelog": "HISTORY.md",
"required": [
"README.md",
"package.json"
]
}
In addition to the configuration options defined for regular packages, the context package allows an additional README.md
file within each brand folder e.g. name-of-context-package/brand-name/README.md
, as well as the following additional configuration items:
contextDirectory
Type: String
Defines the parent folder under which the context package lives (see example structure above), and can NOT be changed.
brandContextName
Type: String
Defines the name of the context package, by default this is brand-context
.
brands
Type: Array
Defines an array of brand names. These must map to the folder names that live within the context package. For example:
{
"brands": [
"brandA",
"brandB",
"brandC"
]
}
Package licensing
All packages that are published MUST be licensed. As packages are published as part of a monorepo the license file should live in the root of the repository, and be referenced in the package.json
. If a license
key is not found then no packages will be published.
Usage
Four CLI scripts are provided as part of this package. They should all be run from your repository root, in the same location as your package-manager.json
and package.json
files.
Script | Description |
---|---|
./node_modules/.bin/sn-package-create |
Create boilerplate code for a new package |
./node_modules/.bin/sn-package-validate |
Validate toolkit packages against config |
./node_modules/.bin/sn-package-publish |
Publish a new/updated package |
./node_modules/.bin/sn-package-demo |
Compile demo code to static html |
More guidance can be found within the tooling section of the developer documentation for Elements.
Continuous Integration
It is intended that the validation
and publication
scripts are run on your CI environment to ensure the safe and correct publication of packages.
When validating on your CI environment the sn-package-validate
script should be run with the -n
or --npm
argument. This will validate for publication to NPM.
The sn-package-publish
script expects a valid NPM token that allows you to publish to the specified organisation. this should be stored as an Environment Variable with the name NPM_TOKEN
.
The script also expects the Environment Variable CHANGED_FILES
which contains a list of all the files changed within the current commit, seperated with a line-break.
# Example from .travis.yml
env:
global:
- CHANGED_FILES=$(git diff --name-only $TRAVIS_COMMIT_RANGE)
Valid packages within the specified packages directory are identified, and a new version is published using the version number within the package.json
file, if that version is greater than the last version published on NPM. Version numbers of 0.0.0
are ignored.
It is also required that the package changelog
has been updated, and appears in the list of CHANGED_FILES
, otherwise publication will not happen.
Travis
This package has been written to work with TRAVIS CI and an example of the CI setup can be found in the Springer Nature frontend-toolkits:
Testing
Unit tests for this package are written with Jest. To run all the tests use npm run test
from the command line.
Linting
Javascript linting is enforced using the Springer Nature Eslint config. Run the linter using npm run lint
from the command line.
Dependency graphs
Below are dependency graphs, generated using Madge, for the three package manager entrypoints.
create
validate
publish
License
This repository is licensed under the Lesser General Public License (LGPL-3.0). Copyright © 2018, Springer Nature