Package software.aws.awsprototypingsdk.pdk_projen
pdk_projen
This package contains a set of Projen project types which can be used to configure complex project configuration through code.
These project types synthesize project configuration files such as package.json, .gitignore, nx.json, eslint, jest, etc from well-typed definitions.
Prerequisites
Ensure you have the following packages installed globally:
Getting Started
To create a new project, run the following command and follow the instructions for the specific project type below:
mkdir my-project cd my-project npx projen new --from aws-prototyping-sdk <project-type>
The following are the currently supported project types, along with instructions on how to get started:
- nx-monorepo - Vends a NX based monorepo with support for polygot builds.
nx-monorepo
The nx-monorepo project type will bootstrap a NX based monorepo with support for
polygot builds, build caching, dependency graph visualization and much more.
This project type does the heavy lifting of managing your packages/subprojects to be compatible with NX by performing the following actions:
- Generates an
nx.jsonfile in the root directory which is responsible for configuring project defaults including what targets should be cached, what implicit dependencies there are, etc. - Generate a
package.jsonfor any non-node project. This is needed as a facade so that nx can call a target, regardless of language. All targets in this package.json file defer to projen tasks. - Installs a plugin (owned by pdk) which handles polygot dependency linking.
After running the npx projen new --from aws-prototyping-sdk nx-monorepo command, a .projenrc.ts will be created which
looks like this:
import { pdk_projen } from "aws-prototyping-sdk";
const project = new pdk_projen.NxMonorepoProject({
defaultReleaseBranch: "main",
devDeps: ["aws-prototyping-sdk"],
name: "my-project",
});
project.synth();
This will be the main mechanism for adding new subprojects, configuring/changing aspects of the generated packages, etc.
Adding Subprojects
Now that you have a monorepo set up, it's time to add Subprojects. You can add Subprojects by simply instantiating new instances of classes which extend the native Projen's Project class, and providing the monorepo project as a parent.
Examples of currently supported project types are listed on the Projen Github Website.
Example 1 - Explicit dependencies
NX ships pre-configured to detect explicit dependencies within the package.json files of Sub projects. If your use case relies solely on Typescript then this example will apply to you.
Let's create a sample application with two Subprojects:
- An Infrastructure project based on Typescript which creates some basic CDK infrastructure.
- A React webapp written in Typescript.
import { pdk_projen } from "aws-prototyping-sdk";
import { AwsCdkTypeScriptApp } from "projen/lib/awscdk";
import { ReactTypeScriptProject } from "projen/lib/web";
const project = new pdk_projen.NxMonorepoProject({
defaultReleaseBranch: "main",
devDeps: ["aws-prototyping-sdk"],
name: "my-project",
});
const webapp = new ReactTypeScriptProject({
defaultReleaseBranch: "mainline",
name: "webapp",
parent: project,
outdir: "packages/webapp",
});
new AwsCdkTypeScriptApp({
cdkVersion: "2.0.0",
defaultReleaseBranch: "mainline",
name: "infra",
devDeps: [webapp.package.packageName], // CDK App depends on the webapp
parent: project,
outdir: "packages/infra",
});
project.synth();
It is important to note that both the parent and outdir properties are mandatory.
Now from the root directory, we will synthesize these packages by running npx projen. After
running this command we will notice our directory will resemble the following:
root
|- packages
|- infra
|- webapp
The npx projen command would have also linked these two packages by adding a dev dependency to webapp in infra's
package.json and also updating the workspace property in the root package.json.
If we wanted to build infra, we can run the following command: npx nx build infra.
npx nx build infra > NX Running target build for project infra and 1 task(s) it depends on ————————————————————————————————————————————————————————————————————————————————— > nx build webapp ... Done in 12.06s. > nx build infra ... Done in 25.59s. ————————————————————————————————————————————————————————————————————————————————— > NX Successfully ran target build for project infra
As you can see from the above logs, the webapp build target was executed first as this is a dependency of infra. NX will also cache builds, so if the same command is re-run (without modifying anything) you will notice the build completes in a fraction of the time.
Example 2 - Implicit dependencies
Some project require implementing components in different languages and as such a mechanism must exist to declare implicit build dependencies between these various packages.
Let's extend the previous example by adding an additional python based lambda as follows:
import { pdk_projen } from "aws-prototyping-sdk";
import { AwsCdkTypeScriptApp } from "projen/lib/awscdk";
import { ReactTypeScriptProject } from "projen/lib/web";
import { PythonProject } from "projen/lib/python";
const project = new pdk_projen.NxMonorepoProject({
defaultReleaseBranch: "main",
devDeps: ["aws-prototyping-sdk"],
name: "my-project",
});
const webapp = new ReactTypeScriptProject({
defaultReleaseBranch: "mainline",
name: "webapp",
parent: project,
outdir: "packages/webapp",
});
const infra = new AwsCdkTypeScriptApp({
cdkVersion: "2.0.0",
defaultReleaseBranch: "mainline",
name: "infra",
devDeps: [webapp.package.packageName], // CDK App depends on the webapp
parent: project,
outdir: "packages/infra",
});
const lambda = new PythonProject({
authorEmail: "foo@bar.com",
authorName: "foo bar",
moduleName: "python_lambda",
name: "python_lambda",
version: "0.0.0",
parent: project,
outdir: "packages/python_lambda",
});
project.addImplicitDependency(infra, lambda);
project.synth();
Now from the root directory, we will synthesize these packages by running npx projen. After
running this command we will notice our directory will resemble the following:
root
|- packages
|- infra
|- webapp
|- lambda
If we wanted to build infra, we can run the following command: npx nx run infra:build.
npx nx build infra > NX Running target build for project infra and 2 task(s) it depends on ——————————————————————————————————————————————————————————————————————————————— > nx build python_lambda ... Done in 0.62s. > nx build webapp ... Done in 10.79s. > nx build infra ... Done in 22.65s. ————————————————————————————————————————————————————————————————————————————————— > NX Successfully ran target build for project infra
As you can see from the above logs, the build was executed sequentially for each package in the correct order.
FAQ
How do I run a target just on a specific package?
To run a package specific target, you can do the following:
cd packages/<my-package> npx projen <target>
How do I add a new target to a projen Sub Project?
In your .projenrc.ts, do the following:
const infra = new AwsCdkTypeScriptApp({
cdkVersion: "2.0.0",
defaultReleaseBranch: "mainline",
name: "infra",
devDeps: [webapp.package.packageName], // CDK App depends on the webapp
parent: project,
outdir: "packages/infra",
});
infra.addTask("new-target", {
exec: "echo \"hi\""
});
As usual, ensure you run npx projen in the root directory to synthesize your change.
From here is it just a case of executing npx projen new-target in the package directory.
I have added a project in .projenrc.ts but it isn't synthesizing?
- Ensure that the
parentproperty of the project is set to the monorepo project. - Ensure that an
outdiris configured i.e:packages/mypackage. - run
npx projenin the root of the monorepo.
How do I visualize my dependencies?
From the root of the monorepo run npx nx graph. This will open a browser showing how all your packages are related.
I have updated a dependency, however the build or graph viz is not detecting any changes.
- Ensure you have run
npx projenfrom the root of the monorepo. - Sometimes the nx cache can become stale and can be cleared by running
npx nx clear-cache.
How do I build everything in my monorepo without a specific target package?
npx nx run-many --target=build --all
I am running a different target, however the dependencies are not being executed.
By default, only the build target is configured to rely on it's dependencies. To configure additional targets, update
the NXMonorepoProject as follows:
const project = new pdk_projen.NxMonorepoProject({
defaultReleaseBranch: "main",
devDeps: ["aws-prototyping-sdk"],
name: "my-project",
targetDependencies: {
test: [
{
target: "test",
projects: "dependencies",
}
]
}
});
In this example, the test target will now wait until the test target has run successfully in all dependent projects.
My subproject is not caching even though I haven't changed anything.
This can happen if NX detects changes in generated/compiled files. Examples of this include if your build target creates a zip file or generates test artifacts with timestamps. To resolve this, add an nxIgnore pattern as follows:
const project = new pdk_projen.NxMonorepoProject({
defaultReleaseBranch: "main",
devDeps: ["aws-prototyping-sdk"],
name: "my-project",
nxIgnorePatterns: ["generated-tst", "dist"]
});
As per the above configuration, NX will ignore anything within generated-tst or dist folders within any
package in your monorepo.
-
Interface Summary Interface Description NxMonorepoProjectOptions Configuration options for the NxMonorepoProject.PDKPipelinePyProjectOptions Configuration options for the PDKPipelinePyProject.PDKPipelineTsProjectOptions Configuration options for the PDKPipelineTsProject.TargetDependency Represents an NX Target Dependency. -
Enum Summary Enum Description SampleLanguage Supported languages to generate sample code.TargetDependencyProject Supported enums for a TargetDependency.