# Create and Publish CDK Constructs Using projen and jsii
This project tests and describes the workflow of creating an [AWS CDK](https://aws.amazon.com/cdk/) construct using [projen](https://github.com/projen/projen) + [jsii](https://github.com/aws/jsii) and publishing it to various repositories like npm, Maven Central, PyPi and NuGet.
In order to verify the process is working as expected, this project contains an [`LambdaConstruct`](src/LambdaConstruct.ts).
It only creates a very simple Lambda function using inline code that prints out the event it's receiving.
Btw. did you know there are multiple [ways to bundle an AWS Lambda function in a CDK construct](https://www.sebastianhesse.de/2021/01/16/5-ways-to-bundle-a-lambda-function-within-an-aws-cdk-construct/)?
**Note:** If you are reading this on npm, NuGet, or PyPi as part of the package description, then please head over to https://github.com/seeebiii/projen-test.
Otherwise the links might not work properly.
## Questions?
Do you have further questions?
Feel free to reach out via [Twitter](https://twitter.com/seeebiii) or visit my website - I'm a [Freelance Software Engineer](https://www.sebastianhesse.de) focusing on serverless cloud projects.
There's also a [CDK developer Slack workspace](https://cdk.dev/) that you can join to ask questions.
## Table of Contents
* [About projen](#about-projen)
* [About jsii](#about-jsii)
* [Requirements](#requirements)
* [Setup Project](#setup-project)
* [Write CDK Construct](#write-cdk-construct)
* [Connect to GitHub](#connect-to-github)
* [Publish to Different Repositories](#publishing-to-different-repositories)
* [Verify Your CDK Construct](#verify-your-cdk-construct)
* [Next Steps](#next-steps)
* [Additional Help](#additional-help)
## About projen
[projen](https://github.com/projen/projen) is a tool to write your project configuration using code instead of managing it yourself.
It was initially created to help you writing CDK constructs but can also be used to create any other project stub like a React app.
The important thing to note is that you only define the project configuration in the [.projenrc.js](.projenrc.js) file and it will generate everything for you, like `package.json` or other files.
**Remember:** do not manually change the generated files, otherwise changes will be lost after you run `projen` again.
Besides that, it is recommended to create an alias in your command line to avoid typing `npx projen` over and over again.
For example: `alias pj='npx projen'`
Further links:
* [A Beginner's Guide to Create AWS CDK Construct Library with projen](https://dev.to/aws-builders/a-beginner-s-guide-to-create-aws-cdk-construct-library-with-projen-5eh4)
* [Converting a CDK construct to using projen](https://www.matthewbonig.com/2020/10/04/converting-to-projen/)
## About jsii
[jsii](https://github.com/aws/jsii) is the technology behind the AWS CDK that allows you to write CDK constructs in TypeScript/JavaScript and compile them to other languages like Java or Python.
There's an [AWS blog post](https://aws.amazon.com/blogs/opensource/generate-python-java-dotnet-software-libraries-from-typescript-source/) about how it works.
There are a few jsii related projects that support us in the steps below, e.g. for releasing our artifacts.
## Requirements
* ~30 of your time (maybe more if you run into errors or need to read through a few documents)
* Node.js/npm installed on your machine
* AWS CDK installed on your machine
* GitHub Account (free account is enough)
### Optional
* AWS Account (for verification)
* Java + Maven (for local packaging & verification)
* Python (for local packaging & verification)
## Steps For Creating a New CDK Construct Using projen
In case you want to test `projen` as well, here are the steps I've performed.
### Setup Project
1. Initialize a new project using `projen`:
```shell
mkdir projen-test
cd projen-test
npx projen new awscdk-construct
```
2. Now create a new Git repository using `git init` and connect an existing Git project using `git remote add origin <REMOTE_URL>`.
(Create your Git repository in GitHub first before you call `git remote add ...`)
* Note: if your local branch is `master` but your remote branch is `main`, then use `git branch -M main` to rename the local branch.
3. Create an alias for your command-line if you haven't done already: `alias pj='npx projen'`
4. Adjust the `projen` options in `.projenrc.js` a bit. For example:
* adjust metadata like `name`, `author`, `authorName`, `authorAddress`, `repositoryUrl`.
By default `name` is also used as the `name` in the generated `package.json`.
However, you can define a custom one by using `packageName`.
* add `projectType: ProjectType.LIB` since we'll create a library
* add `cdkAssert: true` for being able to test my CDK construct
* add `cdkDependencies: ['@aws-cdk/core', '@aws-cdk/aws-lambda']` to let `projen` add these CDK dependencies for me
* optional: add `mergify: false` if you don't want to use it at the moment
* optional: explicitly add `docgen: true` so it automatically generates API documentation ð
* optional: explicitly add `eslint: true` to make sure you use common coding standards
* optional: add `dependabot: true` and `dependabotOptions: {...}` to enable [Dependabot](https://dependabot.com/) if you hate manually managing dependency updates
* optional: add `gitignore: ['.idea']` if you love using IntelliJ â¥ï¸ but don't want to commit its settings - or if you want to ignore any other files :)
* optional: use `packageManager: NodePackageManager.NPM` if you want to use `npm` instead of `yarn` - might be important in case you are migrating an existing CDK Construct to `projen`.
Don't forget to add necessary imports in the config file when applying the `projen` settings, e.g. for using `ProjectType` or `NodePackageManager`.
5. Set a version number in [version.json](version.json), e.g. `0.0.1`.
6. Run `pj` again on your command-line.
This will update all project files like [package.json](package.json) based on what you have configured in [.projenrc.js](.projenrc.js).
Remember to not manually update these files as `projen` will override your changes otherwise.
**ð¡ Hint:** I can recommend to play around with the options a little bit and run `pj` after each change.
Then observe what happens and how the project files differ.
If you commit the changes to Git each time after running `pj`, you can easily compare the Git diff ð
### Write CDK Construct
1. Write a simple CDK construct in `src/index.ts`.
There are already great tutorials like [cdkworkshop.com](https://cdkworkshop.com/) available about how to write constructs.
Here's a small code snippet for a simple Lambda function using inline code:
```python
# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
Function(self, "SampleFunction",
runtime=Runtime.NODEJS_12_X,
code=Code.from_inline("exports.handler = function (e, ctx, cb) { console.log(\"Event: \", e); cb(); };"),
handler="index.handler",
timeout=Duration.seconds(10)
)
```
Have a look at [LambdaConstruct.ts](src/index.ts) for an examples construct that declares various Lambda functions.
Instead of using a Lambda function, you can also use whatever you like.
2. Write a simple test for this construct in [test/index.test.ts](test/index.test.ts).
Here's also a small code snippet which ensures that our Lambda function is created in the stack:
```python
# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826
test("Simple test", () => {
const app = new cdk.App();
const stack = new cdk.Stack(app, 'TestStack');
new LambdaConstruct(stack, 'LambdaConstruct');
expectCDK(stack).to(countResources('AWS::Lambda::Function', 1));
})
```
The test is creating a