Usage
The constructs defined in this package may be used within a
TypeScriptESMProject or added to other projects.
When using within a TypeScriptESMProject, it is preferred
to use the options flags for the TypeScriptESMProject
to cause the other constructs to be added. This is not
required, just suggested.
Sections
- TypeScriptESMProject
- PreCommitConfigFile
- ReadmeSampleFile
- PnpmWorkspace
- DocsIndexSampleFile
- TypdocJson
TypeScriptESMProject (typescript-esm)
This project type represents a project which is TypeScript code, expected to be compiled and run in ESM mode (either in browser or Node-like environments).
The simplest instantiation of the project type resembles:
const project = new TypeScriptESMProject({
defaultReleaseBranch: 'main',
devDeps: ['@ncfour-us/projen-utils'],
name: 'test-proj',
packageManager: javascript.NodePackageManager.PNPM,
projenrcTs: true,
// deps: [], /* Runtime dependencies of this module. */
// description: undefined, /* The description is just a string that helps people understand the purpose of the package. */
// packageName: undefined, /* The "name" in package.json. */
// repoBuildPackageModel: RepoBuildPackageModel.LOCAL_DEV_BUILD_REGISTRY, /* Type of repository, packaging, and release model to use. */
});
In this case, all the default choices for setting up the project will be used. The resulting project can be built and tested immediately after generation using the command:
pnpm build
Sample code is provided in the initial project along with a sample unit test which runs the sample code.
Options
The TypeScriptESMProject project extends TypeScriptProject. All options
which can be specified for the TypeScriptProject can be used in the
construct options for TypeScriptESMProject.
Where there are conflicts, the TypeScriptESMProject will over-ride settings
as necessary when calling the TypeScriptProject constructor.
See the API documentation for the type/syntax of each of these options. The following sub-sections describe how to use the options and what effect setting their values will have on the project structure and behavior.
precommitConfig
By setting this flag, a PreCommitConfigFile construct is added to the project
setting up the pre-commit processing to handle TypeScript code along with
setting up checking that git commit messages conform to the
Conventional Commits.
The automated build/versioning processing in the project relies on convential commmit
message adherance within git commit messages, so it is recommended that
the pre-commit support be enabled.
After enabling this for the project, it is also necessary to install/activate
the pre-commit tool in the local development environment. Follow instructions
from the pre-commit site for getting the pre-commit
tool installed.
Further, because both pre-commit and commit-msg hooks are used, activating the hooks for the locally cloned git repository requires the following command to be run (from a folder inside the git repository clone):
pre-commit install --hook-type commit-msg --hook-type pre-commit
Once this is configured and activated, checks for eslint, prettier, end-of-file,
trailing-whitespace, and commit message format will be run on every git commit
command invocation (including when run within an IDE environment).
The eslint and prettier checks rely on their respective configuration in the repository
and MAY cause changes in files when they run. In this case, those files should
be added (git add .) to the staged commit files before re-running the git commit
command to commit the changes to the local repository.
addVersionFile
If activated, this will cause a src/version.ts file to be created/maintained
during build processing. This file will include a single exported string value:
export const LIB_VERSION = '0.0.0';
This is sometimes useful when source code inside the project would like to check
or display the version of the package. The value is pulled from package.json
during build processing (pre-compile stage).
NOTE: when running in development, the value for LIB_VERSION will almost always
be 0.0.0. This is because the projen-provided build processing for managing
package versioning is only used during release processing (build/packaging of
a “release” package artifact (.tgz file)). The LIB_VERSION in ./lib/version.js
in the packaged .tgz file for the package WILL have the value corresponding
to the version field in package.json in that same packaged .tgz file.
eslintFlatConfig
The default format for the ESLint configuration chosen by projen is JSON format
(.eslintrc.json). However, newer versions of ESLint are deprecating the JSON
configuration format in favor of the “flat config” format (eslint.config.ts).
By setting this flag, the project will generate (as a Sample file) a eslint.config.ts
file. It is then the responsibility of the project team to maintain the
eslint.config.ts file (ESLint config options for the TypeScriptProject
are ignored).
prettierFlatConfig
The default format for the Prettier configuration chosen by projen is JSON format
(.prettierrc). However, newer versions of prettier are deprecating the JSON
configuration format in favor of the “flat config” format (prettier.config.ts).
By setting this flag, the project will generate (as a Sample file) a prettier.config.ts
file. It is then the responsibility of the project team to maintain the
prettier.config.ts file (Prettier config options for the TypeScriptProject
are ignored).
Be careful when setting configuration for Prettier as there are @stylistic ESLint
configuration settings which also mutate/change the format of TypeScript source files.
The initial configuration of prettier.config.ts and eslint.config.ts are set
up so that they are compatible with one another.
commands
This option can be used to list additional TypeScript files which implement command-line
tools and should be added as commands when the package is installed. The commands
listed (and their corresponding source file names) are added to BOTH the scripts
and bins clauses of package.json.
The source file names should be relative to the src folder. For example,
if there are two additional commands implemented in source files src/cmd/command1.ts
and src/cmd/command2.ts, the option should be specified as:
...
commands: [
{
name: 'command-1',
file: 'cmd/command1.js',
},
{
name: 'command-2',
file: 'cmd/command2.js',
},
],
...
Note the change from .ts to .js in the file attribute.
docsIndex
This option is used to generate a Sample file in the docs folder/directory of the
repository. The resulting markdown can then be used when setting up a GitHub Pages
site which documents the package (once the git repository is hosted on GitHub, and
GitHub Pages publishing is enabled for the repository).
The file is only created once. The project team must then update the file with the appropriate information.
If API documentation (see apiDocumentation) is specified, this option MUST also be specified.
apiDocumentation
This option enabled Typedoc generation of API documentation for the exported classes/enums/constants/types from the project.
Be sure to update the TypeScript source files with block comments above ALL exported types/constants/classes.
apiEntryPoints
This option can be used, when apiDocumentation is enabled, to configure the
entryPoints attribute in the typedoc.json file. This option is only
needed if there is a difference between what should be documented vs. what
is exported for the project since Typedoc will use the exported entry points
from package.json if no other configuration is provided.
repoBuildPackagingModel
The TypeScriptESMProject provides a VERY opinionated implementation of
build/packaging processing for the project. This implementation builds on the
base support provided by projen. However, the implementation focuses on
a staged adoption of build/packaging automation, starting with the creation
of a project that is built/packaged entirely local (local git repository,
no remote repository on GitHub) with subsequent adjustments/refinements
to the configuration to enable/use a remote git repository on GitHub and
package registry on NPMJS.
Subsequent configuration can then be enabled which shifts build/packaging processing to GitHub actions, with local build processing used ONLY for development, debugging, and patching/fixing.
This path was chosen because it enables quick local development followed by
successive build/package automation and staged publishing to public locations.
The user learns how the build/packaging model works, including automated
Semantic Versioning management provided by the
projen build/packaging automation,
in close coordination/usage of git tagging.
If a project wishes to use the ESM support for the project type, but handle
build/packaging configuration on its own, this is possible by using the
RepoBuildPackagingModel.SKIP_SETUP configuration setting
for the repoBuildPackagingModel option.
NOTE however, that SKIP_SETUP is NOT the default configuration.
The default configuration for the project is RepoBuildPackagingModel.LOCAL_BUILD_PACKAGE.
In this build/packaging mode, a remote git repository MAY be configured,
but it is treated as a remote target with changes pushed to the target.
This is appropriate when a project is just getting started, usually by
a single person or very small team working on the project.
Once the project is ready for its first couple of releases, then remote build/packaging publishing targets can be specified with the locally-initiated build/packaging causing publishing to those remote targets to be done at the end of build/packaging processing.
SKIP_SETUP
This build/packaging mode turns OFF any build/packaging setup by
the TypeScriptESMProject. All build/packaging setup configuration
is the responsibility of the project team.
LOCAL_BUILD_PACKAGE / LOCAL_DEV_BUILD_REGISTRY
This build/packaging mode enables/implements local (from the local
git repository) build/packaging processing, including package publishing.
Two commands are used for build and packaging: build and release.
The build command will compile, test, and package up a package
deployment artifact (.tgz file) which can be used for integration
testing.
The built artifact can be installed into another project
using the file://<filename>.tgz format in that project’s package.json file.
The release command will perform all build processing AND
create a versioned project build artifact. The versioning
follows Semantic Versioning, relies on
git commits being on the main branch of the code repository,
and will set tags in the git repository which correspond
to the release version that is built/packaged. The resulting .tgz
file will contain the version identfier in the filename.
Furthermore, a CHANGELOG.md file will be created/updated
in the git repository, with information pulled from
git commit messages (based on those messages conforming
to the Conventional Commits format).
Note that semantic versioning changes rely heavily on the format of the commit messages in order to determine whether to change patch, minor, or major version numbers when calculating the version number to build/package.
The first time release is run, when on the main branch in the repository,
a package will be built at version 0.0.0 with a tag being
added to the git repository with value v0.0.0.
From that point forward, when pnpm release is run while on the main
branch, a new version will be created, bumping the patch, minor, and major
versions of the package as dictated by the git commit messages between the
last tagged commit on the main branch and the current commit on the main
branch.
Semantic versioning changes are a bit different when the major version is 0
versus when the value is 1 or greater. When 0, “breaking” changes
cause the minor level to increment (resetting the patch value to 0).
All other updates cause the patch level to increment. When 1 or greater,
“breaking” changes will increment the major version (if minMajorVersion is set),
updates which include features will increment the minor version (resetting the patch
value to 0), and bug fixes or other fixes will increment the patch value.
Each time release is run, a new tag will be added to the git repository and
the CHANGELOG.md file will be updated.
Three additional configuration options control where released packages are
“published” to: releaseToLocal, releaseToNpm, and releaseToGithub.
When set to true, the release processing will attempt to publish to those
locations, order:
1) remote Git repo (git push) - only if the repository option is set
1) local - based on the localPackageArchiveDir option and releaseToLocal set to true
1) NPM Registry - if releaseToNpm is set to true
1) GitHub release - if releaseToGithub is set to true
This build/packaging model is implemented using the projen support
for ReleaseTrigger.manual().
IMPORTANT: Publishing to the remote locations depends on the local environment having connectivity, active login credentials, and appropriate pre-requisite tools installed. See options below for details on what tools are used for publishing to each location.
GITHUB_BUILD_PACKAGE
In this mode (STILL UNDER CONSTRUCTION), GitHub actions are used
to manage packaging and release to associated repositories. This mode
depends heavily on the built-in support for build/packaging using
GitHub actions provided by the projen project.
This build/packaging model is (WILL BE) implemented using the projen support
for ReleaseTrigger.continuous().
localPackageArchiveDir
This option specifies a folder, on the local workstation, where release-level
packages (.tgz files) should be copied to when “publishing to local”.
This folder MUST be writable to by the user running the pnpm release
command.
When releaseToLocal is true, the release-level .tgz file (file-name
contains the version number) will be copied to the localPackageArchiveDir folder.
The default for this value is ~/.local-build-packages.
releaseToLocal
The default value for this option is true.
When set to true, built packages during release processing will be copied
to the localPackageArchiveDir.
releaseToNpm
The default value for this option is false.
When set to true, built packages during release processing will be
published to the NPM Registry using the publish
command of the package manager used by the project.
For example, if pnpm is the package manager, then the pnpm publish
command is used.
NOTE the local user MUST have active credentials and authority to
publish the package to the NPM registry. The user WILL be prompted
to authenticate during this publishing step, responding to whatever 2FA
or MFA authentication is required for the publish command to succeed.
releaseToGithub
The default value for this option is false.
When set to true, the Github CLI tool (gh) will be used to create
a “Github release” using the gh release create command.
More information on installing and using the gh command can be found
on the gh CLI page.
NOTE the local user MUST have active credentials and authority to
run the gh release create command on the remote git repository
(see repository configuration setting). A user can chech their
authentication status using the gh auth status command.
buildTagTask
The default value for this option is false.
When set to true, and additional command is enabled for the project
which enables the build/packaging of any level of the code which has
a corresponding git tag defined. This can be used to re-build/package
a version of the package at a prior release level.
Building at a prior release level can be useful for re-creating problems or debugging issues discovered by users.
When activated, a local user can run:
pnpm build:tag v0.0.0
to build the package at release level 0.0.0. The resulting package (.tgz)
file will be placed in the dist/js folder, with the file-name containing
the release level that was built.
If a version 1.3.15 exists in the local repository, run:
pnpm build:tag v1.3.15
to build/package the project at that level.
Use:
git log --oneline --tags --no-walk`
or
git tag -l
to find the tags defined in the local git repository.
Use command:
git describe --tags --abbrev=0
to find the “nearest” tag to the current commit point in the local repository.
Specifying a tag value that does not exist results in an error.
Specifying multiple tag values results in an error.
PreCommitConfigFile
This construct can be used with a TypeScriptESMProject or any other project.
To use it with a TypeScriptESMProject, we recommend using
the precommitConfig option for that project type.
This is not, however, required.
To separately define the construct, instantiate it in .projenrc.ts:
...
new PreCommitConfigFile(project, {
fileTypes: [
PreCommitConfigFileTypes.TYPESCRIPT
],
packageManager: NodePackageManager.PNPM,
});
...
This will result in a managed file named .pre-commit-config.yaml to be
created at the top of the project.
After enabling this for the project, it is also necessary to install/activate
the pre-commit tool in the local development environment. Follow instructions
from the pre-commit site for getting the pre-commit
tool installed.
Further, because both pre-commit and commit-msg hooks are used, activating the hooks for the locally cloned git repository requires the following command to be run (from a folder inside the git repository clone):
pre-commit install --hook-type commit-msg --hook-type pre-commit
The checks defined in the file will then be applied whenever a git commit
command is issued for the local repository.
ReadmeSampleFile
This construct can be used with a TypeScriptESMProject or any other project.
The sample README.md file is normally configured using the readme
project option. However, since it is VERY difficult to set this option
when creating a new project, and the file is a Sample file, it
can be a bit tricky to get a different README.md file template
created for the project.
There are two ways to use change/specify a different README.md template:
1) specify the readme option in the project’s constructor options
1) instantiate a ReadmeSampleFile object and associate it with the project
In both cases, in order for the README.md file to actually be changed,
the README.md file MUST be removed from the project folder immediately
prior to the next run of the projen command which generates the project
files.
The steps to follow are:
1) update .projenrc.ts to specify the new configuration
1) remove the README.md file from the local folder tree (e.g. rm README.md command)
1) update the project files using pnpm projen.
The last command will cause the README.md file to be generated as a Sample, based
on the configuration set in the first step.
If the changes look good, then the changes can be commmited to the local repository using
git add . and git commit -m "fix: update README.md".
To use the readme option for the project, add something like:
...
readme: sampleReadmeProps({
namespace: '@my-npm-namespace', // NPM scope
projectName: 'my-project', // NPM package name
organization: 'my-org', // GitHub organization or user name
author: 'My First and Last Name', // Author name
authorEmail: 'myemail@example.com', // Author e-mail
authorGithubUser: 'my-github-username', // Author GitHub userid
license: 'MIT', // license ('MIT', 'Apache 2.0', etc.)
}),
...
To use the ReadmeSampleFile construct, add something like:
new ReadmeSampleFile(project, {
namespace: '@my-npm-namespace', // NPM scope
projectName: 'my-project', // NPM package name
organization: 'my-org', // GitHub organization or user name
author: 'My First and Last Name', // Author name
authorEmail: 'myemail@example.com', // Author e-mail
authorGithubUser: 'my-github-username', // Author GitHub userid
license: 'MIT', // license ('MIT', 'Apache 2.0', etc.)
});
to your .projenrc.ts file.
The construct will search for an existing SampleReadme construct in
the project and remove it, if found, replacing the README.md sample
file with the one created by this construct.
PnpmWorkspace
This construct can be used with a TypeScriptESMProject or any other project.
Use this construct to create a managed pnpm-workspace.yaml file at the
top of the project. This file controls configuration settings for the pnpm
command and package manager. For more information on the options for this file
refer to pnpm-workspace.yaml documentation.
To use the PnpmWorkspace construct, add something like:
new PnpmWorkspace(project, {
packages: [],
});
to your .projenrc.ts file.
The following attributes are set in the file:
packages: defaults to[ 'packages/*' ]. Set to[]in a project that does not have sub-projects/packagesminimumReleaseAge: defaults to1440blockExoticSubdeps: defaults totruetrustPolicy: defaults tono-downgradeallowBuilds: defaults to{ electron: true, esbuild: true }
DocsIndexSampleFile
This construct can be used with a TypeScriptESMProject or any other project.
Use this construct to initialize a documentation folder named docs in the project
in preparation for publishing this documentation
using GitHub Pages.
The construct creates a index.md file inside the docs folder.
To use the DocsIndexSampleFile construct, add:
new DocsIndexSampleFile(project);
to your .projenrc.ts file.
A sample file (un-managed) named docs/index.md will be created in the project.
After creating the file, edit the file to adjust as appropriate for documenting how to use the project. The sample suggests adding additional markdown files to describe:
- installation (
install.md) - usage (
usage.md) - examples (
exampile.md) - API documentation (see TypedocJson construct)
These additional files are not created. The docs/index.md file
can be edited to remove these references or add additional references
as you see fit to document your project.
TypedocJson
This construct can be used with a TypeScriptESMProject or any other project.
Use this construct to create a typedoc.json configuration file
for using typedoc to generate API documentation for your project.
For more information about typedoc, refer to the
Typedoc documentation.
To use the TypedocJson construct, add:
new TypedocJson(project, {
entryPoints: ['src/index.ts'],
});
to your .projenrc.ts file.
NOTE This construct only defines the typedoc.json configuration
file. Additional configuration is required to add the use of
typedoc into the build processing for the project.
If using a TypeScriptESMProject
and the apiDocumentation option
this additional processing is added to the project on your behalf.
To add the typedoc processing to another project the following
sample code can be used as a guide:
...
// install typedoc and markdown plugin
project.addDevDeps("typedoc", "typedoc-plugin-markdown");
// add scripts to run API documentation generation
const buildDocsTask = project.addTask("build:docs", {
description: "Generate Typedoc documentation",
exec: `pnpm typedoc`,
});
project.addPackageIgnore("docs");
// add API generation to the post-compile processing
project.postCompileTask.addSteps({
spawn: buildDocsTask.name,
});
...
The code snippet adds as task called build:docs to the project
and then adds this task to the post-compile stage of the build
task.