Skip to content

Commit

Permalink
Update monorepo example
Browse files Browse the repository at this point in the history
  • Loading branch information
julienp committed Mar 14, 2024
1 parent b161b0c commit d74695b
Show file tree
Hide file tree
Showing 24 changed files with 178 additions and 119 deletions.
109 changes: 64 additions & 45 deletions nx-monorepo/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Nx Monorepo

This example shows how to use Nx to organize a mono repo and track dependencies between the packages in the monorepo.
This example shows how to use Nx to organize a monorepo and track dependencies between the packages in the monorepo.

The example consists of the following components:

- packages/s3folder: a [ComponentResource](https://www.pulumi.com/docs/concepts/resources/components/) that manages a S3 bucket and its access policies.
- packages/website-deploy: [ComponentResource](https://www.pulumi.com/docs/concepts/resources/components/) resource that manages files in a S3 bucket
- packages/website: A website built with [Astro](https://astro.build).
- infra: Pulumi program that uses the `s3folder` and `website-deploy` resources to deploy the generated website.
- **components/s3folder**: A [Component Resource](https://www.pulumi.com/docs/concepts/resources/components/) that manages a S3 bucket and its access policies.
- **components/website-deploy**: A [Component Resource](https://www.pulumi.com/docs/concepts/resources/components/) that manages files in a S3 bucket
- **website**: A website built with [Astro](https://astro.build).
- **infra**: A Pulumi program that uses the `s3folder` and `website-deploy` resources to deploy the generated `website`.

The components are written in TypeScript and have a build step to compile them.

Expand Down Expand Up @@ -59,11 +59,11 @@ npx nx deploy infra
```

```
4/4 dependent project tasks succeeded [0 read from cache]
3/3 dependent project tasks succeeded [0 read from cache]
Hint: you can run the command with --verbose to see the full dependent project outputs
———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> nx run infra:build
Expand All @@ -79,55 +79,53 @@ npx nx deploy infra
> [email protected] deploy
> pulumi up --stack dev
The stack 'dev' does not exist.
If you would like to create this stack now, please press <ENTER>, otherwise press ^C:
Created stack 'dev'
Previewing update (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/julienp/nx-monorepo/dev/previews/fc7630fd-7dc4-4c7e-baa0-3d6e014fc90a
View in Browser (Ctrl+O): https://app.pulumi.com/v-julien-pulumi-corp/nx-monorepo/dev/previews/19e33681-e8fa-49f0-b830-494cfd996c50
Type Name Plan
+ pulumi:pulumi:Stack nx-monorepo-dev create
+ ├─ pulumi:examples:WebsiteDeploy my-website create
+ │ └─ aws:s3:BucketObject index.html create
+ │ ├─ aws:s3:BucketObject index.html create
+ │ └─ aws:s3:BucketObject favicon.svg create
+ └─ pulumi:examples:S3Folder my-folder create
+ ├─ aws:s3:Bucket my-folder create
+ ├─ aws:s3:BucketPublicAccessBlock public-access-block create
+ └─ aws:s3:BucketPolicy bucketPolicy create
Outputs:
bucketId : output<string>
websiteUrl: output<string>
Resources:
+ 7 to create
+ 8 to create
Do you want to perform this update? yes
Updating (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/julienp/nx-monorepo/dev/updates/1
View in Browser (Ctrl+O): https://app.pulumi.com/v-julien-pulumi-corp/nx-monorepo/dev/updates/25
Type Name Status
+ pulumi:pulumi:Stack nx-monorepo-dev created (6s)
+ ├─ pulumi:examples:S3Folder my-folder created (5s)
+ │ ├─ aws:s3:Bucket my-folder created (1s)
+ │ ├─ aws:s3:BucketPublicAccessBlock public-access-block created (0.76s)
+ │ └─ aws:s3:BucketPolicy bucketPolicy created (0.85s)
+ └─ pulumi:examples:WebsiteDeploy my-website created (2s)
+ └─ aws:s3:BucketObject index.html created (0.80s)
+ ├─ pulumi:examples:WebsiteDeploy my-website created (1s)
+ │ ├─ aws:s3:BucketObject favicon.svg created (0.94s)
+ │ └─ aws:s3:BucketObject index.html created (1s)
+ └─ pulumi:examples:S3Folder my-folder created (5s)
+ ├─ aws:s3:Bucket my-folder created (2s)
+ ├─ aws:s3:BucketPublicAccessBlock public-access-block created (0.85s)
+ └─ aws:s3:BucketPolicy bucketPolicy created (1s)
Outputs:
websiteUrl: "my-folder-a64ab3c.s3-website.eu-central-1.amazonaws.com"
bucketId : "my-folder-c073a6e"
websiteUrl: "http:https://my-folder-c073a6e.s3-website.eu-central-1.amazonaws.com"
Resources:
+ 7 created
Duration: 9s
+ 8 created
Duration: 10s
———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
NX Successfully ran target deploy for project infra and 5 tasks it depends on (42s)
———————————————————————————————————————————————————————————————————————————
```

To destroy the stack, we run:
Expand All @@ -137,6 +135,20 @@ npx nx destroy infra
```

```
✔ 2/2 dependent project tasks succeeded [2 read from cache]
Hint: you can run the command with --verbose to see the full dependent project outputs
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> nx run infra:build [existing outputs match the cache, left as is]
> [email protected] build
> tsc
> nx run infra:destroy
Expand All @@ -145,49 +157,56 @@ npx nx destroy infra
Previewing destroy (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/julienp/nx-monorepo/dev/previews/b640cce7-a9df-49a5-b004-3fbdbe65c4eb
View in Browser (Ctrl+O): https://app.pulumi.com/v-julien-pulumi-corp/nx-monorepo/dev/previews/8cfe44be-b3e1-4858-8d48-8bf3223a344c
Type Name Plan
- pulumi:pulumi:Stack nx-monorepo-dev delete
- ├─ pulumi:examples:S3Folder my-folder delete
- │ ├─ aws:s3:BucketPolicy bucketPolicy delete
- │ ├─ aws:s3:BucketPublicAccessBlock public-access-block delete
- │ └─ aws:s3:Bucket my-folder delete
- │ ├─ aws:s3:Bucket my-folder delete
- │ └─ aws:s3:BucketPolicy bucketPolicy delete
- └─ pulumi:examples:WebsiteDeploy my-website delete
- ├─ aws:s3:BucketObject favicon.svg delete
- └─ aws:s3:BucketObject index.html delete
Outputs:
- websiteUrl: "my-folder-a64ab3c.s3-website.eu-central-1.amazonaws.com"
- bucketId : "my-folder-c073a6e"
- websiteUrl: "http:https://my-folder-c073a6e.s3-website.eu-central-1.amazonaws.com"
Resources:
- 7 to delete
- 8 to delete
Do you want to perform this destroy? yes
Destroying (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/julienp/nx-monorepo/dev/updates/2
View in Browser (Ctrl+O): https://app.pulumi.com/v-julien-pulumi-corp/nx-monorepo/dev/updates/26
Type Name Status
- pulumi:pulumi:Stack nx-monorepo-dev deleted (0.31s)
- ├─ pulumi:examples:WebsiteDeploy my-website deleted (0.60s)
- │ └─ aws:s3:BucketObject index.html deleted (0.88s)
- └─ pulumi:examples:S3Folder my-folder deleted (0.82s)
- ├─ aws:s3:BucketPolicy bucketPolicy deleted (0.96s)
- ├─ aws:s3:BucketPublicAccessBlock public-access-block deleted (0.91s)
- └─ aws:s3:Bucket my-folder deleted (0.74s)
- pulumi:pulumi:Stack nx-monorepo-dev deleted (0.25s)
- ├─ pulumi:examples:WebsiteDeploy my-website deleted (0.31s)
- │ ├─ aws:s3:BucketObject favicon.svg deleted (1s)
- │ └─ aws:s3:BucketObject index.html deleted (1s)
- └─ pulumi:examples:S3Folder my-folder deleted (0.56s)
- ├─ aws:s3:BucketPolicy bucketPolicy deleted (0.86s)
- ├─ aws:s3:BucketPublicAccessBlock public-access-block deleted (0.88s)
- └─ aws:s3:Bucket my-folder deleted (0.71s)
Outputs:
- websiteUrl: "my-folder-a64ab3c.s3-website.eu-central-1.amazonaws.com"
- bucketId : "my-folder-c073a6e"
- websiteUrl: "http:https://my-folder-c073a6e.s3-website.eu-central-1.amazonaws.com"
Resources:
- 7 deleted
- 8 deleted
Duration: 7s
Duration: 8s
The resources in the stack have been deleted, but the history and configuration associated with the stack are still maintained.
If you want to remove the stack completely, run `pulumi stack rm dev`.
———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
NX Successfully ran target destroy for project infra and 3 tasks it depends on (33s)
Nx read the output from the cache instead of running the command for 3 out of 4 tasks.
NX Successfully ran target destroy for project infra (18s)
```
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ export class S3Folder extends pulumi.ComponentResource {
readonly bucket: pulumi.Output<aws.s3.Bucket>;
readonly websiteUrl: pulumi.Output<string>;

/**
* S3Folder manages a S3 bucket and configures it to serve a static website.
* @param bucketName The name of the S3 bucket.
* @param opts
*/
constructor(bucketName: string, opts: pulumi.ComponentResourceOptions) {
super("pulumi:examples:S3Folder", bucketName, {}, opts);

// Create a bucket and expose a website index document
let siteBucket = new aws.s3.Bucket(bucketName, {
const siteBucket = new aws.s3.Bucket(bucketName, {
website: {
indexDocument: "index.html",
},
Expand All @@ -21,7 +26,7 @@ export class S3Folder extends pulumi.ComponentResource {
}, { parent: this });

// Set the access policy for the bucket so all objects are readable
let bucketPolicy = new aws.s3.BucketPolicy("bucketPolicy", {
const bucketPolicy = new aws.s3.BucketPolicy("bucketPolicy", {
bucket: siteBucket.bucket,
policy: siteBucket.bucket.apply(this.publicReadPolicyForBucket),
}, { parent: this, dependsOn: publicAccessBlock }); // specify resource parent
Expand Down
12 changes: 12 additions & 0 deletions nx-monorepo/components/s3folder/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "s3folder",
"main": "dist/index.js",
"version": "1.0.0",
"dependencies": {
"@pulumi/pulumi": "latest",
"@pulumi/aws": "^6.23.0"
},
"scripts": {
"build": "tsc"
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,34 @@ import * as mime from "mime";
import * as path from "path";

export class WebsiteDeploy extends pulumi.ComponentResource {
constructor(name: string, bucket: pulumi.Input<aws.s3.Bucket>, directory: string, opts: pulumi.ComponentResourceOptions) {

/**
* WebsiteDeploy uploads files from a directory to an S3 bucket.
* @param name The name of the resource.
* @param bucket The S3 bucket to upload files to.
* @param directory The directory to upload files from.
* @param opts
*/
constructor(name: string, bucketId: pulumi.Input<string>, directory: string, opts: pulumi.ComponentResourceOptions) {
super("pulumi:examples:WebsiteDeploy", name, {}, opts);

// For each file in the directory, create an S3 object stored in `bucket`
walk(directory, (filePath: string) => {
const name = path.relative(directory, filePath);
let object = new aws.s3.BucketObject(name, {
bucket: bucket,
const object = new aws.s3.BucketObject(name, {
bucket: bucketId,
source: new pulumi.asset.FileAsset(filePath), // use FileAsset to point to a file
contentType: mime.getType(filePath) || undefined, // set the MIME type of the file
}, { parent: this }); // specify resource parent
})
}
}

// Walk recursively walks the file tree at dir and calls callback for each file found.
function walk(dir: string, callback: (path: string) => void) {
for (let f of fs.readdirSync(dir)) {
let filePath = path.join(dir, f);
let isDirectory = fs.statSync(filePath).isDirectory();
for (const f of fs.readdirSync(dir)) {
const filePath = path.join(dir, f);
const isDirectory = fs.statSync(filePath).isDirectory();
isDirectory ? walk(filePath, callback) : callback(filePath);
}
}
16 changes: 16 additions & 0 deletions nx-monorepo/components/website-deploy/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "website-deploy",
"main": "dist/index.js",
"version": "1.0.0",
"dependencies": {
"@pulumi/aws": "^6.23.0",
"@pulumi/pulumi": "latest",
"mime": "^2.6.0"
},
"scripts": {
"build": "tsc"
},
"devDependencies": {
"@types/mime": "^3.0.4"
}
}
6 changes: 4 additions & 2 deletions nx-monorepo/infra/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import * as websiteDeploy from "website-deploy"

// Create the folder to hold our website files
const folder = new s3folder.S3Folder("my-folder", {})

export const bucketId = folder.bucket.id;
export const websiteUrl = folder.websiteUrl.apply(url => `http:https://${url}`)

// Deploy the website to the folder
const websiteFiles = path.join("..", "..", "packages", "website", "dist")
const website = new websiteDeploy.WebsiteDeploy("my-website", folder.bucket, websiteFiles, {})
const websiteFiles = path.join("..", "..", "website", "dist")
const website = new websiteDeploy.WebsiteDeploy("my-website", bucketId, websiteFiles, {})

13 changes: 10 additions & 3 deletions nx-monorepo/infra/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,28 @@
"dependencies": {
"@pulumi/pulumi": "latest",
"s3folder": "*",
"website-deploy": "*",
"website": "*"
"website": "*",
"website-deploy": "*"
},
"scripts": {
"build": "tsc",
"deploy": "pulumi up --stack dev",
"destroy": "pulumi destroy --stack dev"
"destroy": "pulumi destroy --stack dev",
"refresh": "pulumi refresh --stack dev"
},
"nx": {
"targets": {
"deploy": {
"cache": true,
"dependsOn": [
"build",
"website:generate"
]
},
"destroy": {
"dependsOn": [
"build"
]
}
}
}
Expand Down
24 changes: 12 additions & 12 deletions nx-monorepo/nx.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"extends": "nx/presets/npm.json",
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"targetDefaults": {
"build": {
"cache": true,
"dependsOn": [
"^build"
],
"outputs": [
"{projectRoot}/dist"
]
"extends": "nx/presets/npm.json",
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"targetDefaults": {
"build": {
"cache": true,
"dependsOn": [
"^build"
],
"outputs": [
"{projectRoot}/dist"
]
}
}
}
}
7 changes: 4 additions & 3 deletions nx-monorepo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
"devDependencies": {
"@nx/js": "18.0.5",
"nx": "18.0.5",
"typescript": "^5.3.3"
"typescript": "^5.4.2"
},
"workspaces": [
"packages/*",
"infra"
"components/*",
"infra",
"website"
]
}
Loading

0 comments on commit d74695b

Please sign in to comment.