sst-custom
TypeScript icon, indicating that this package has built-in type declarations

0.0.11 • Public • Published

sst-custom

A custom pulumi provider, providing support for defining custom SST components as if they were standard.

Why?

If you've defined custom sst components in the past, you may have run into issues in CI or installing everything from scratch. The main issue is when components import from the generated .sst directory; when doing this, the files imported into the custom components must exist before sst has generated them otherwise errors are thrown! This means you have to commit ALL (transitively) dependent sst-generated files into source control and ensure they are always there before running sst install.

This package gets around that, allowing you to define custom components as you'd expect.

Usage

Add the provider:

sst add sst-custom

Configure the provider in your sst.config.ts:

/// <reference path="./.sst/platform/config.d.ts" />

export default $config({
	app(input) {
		return {
			name: "my-sst-app",
			removal: input?.stage === "production" ? "retain" : "remove",
			home: "aws",
			providers: {
				"sst-custom": { root: "./infra/custom" },
			},
		};
	},
  async run() {
    // ....
  }
});

Define your components in /infra/custom/platform/src/components/. For example, ./infra/custom/platform/src/components/cloudflare/my-custom-component.ts:

import { Component } from "../../component";

export interface MyCustomComponentArgs {
   // ... define args
}

export class MyCustomComponent extends Component {
  	constructor(
		name: string,
		args: MyCustomComponentArgs,
		opts: $util.ComponentResourceOptions = {}
	) {
		super(__pulumiType, name, args, opts);

    // ... Implementation
  }
}

// Following sst standards
const __pulumiType = "sst:cloudflare:MyCustomComponent";
// @ts-expect-error
MyCustomComponent.__pulumiType = __pulumiType;

Use your component in your sst.config.ts:

  // ... rest of config
  async run() {
    new sst.cloudflare.MyCustomComponent('MyComponent', { ... })
  }

Bun

If sst is configured to use bun, then your custom components will not be installed when you run sst add or sst install because Bun will block the postinstall script. In this case, you can either:

  1. Run NO_BUN=1 sst install to run the install with npm instead
  2. Run bun sst-custom-install to manually install the components
  3. See this FAQ

In either case, you will have to use that option in place of sst install whenever you want to install your custom components.

Imports

You should use typescript rootDirs to resolve imports in your custom components relative to the .sst directory. This means you can import, for example, from the aws directory as if your file was in there already.

For example, if your custom components were located in $ROOT/infra/custom, you could use the following tsconfig.json, placed at $ROOT/infra/custom/tsconfig.json:

{
	"compilerOptions": {
		"rootDirs": ["./../../.sst", "."],
		"lib": ["esnext"],
		"moduleResolution": "bundler",
		"module": "esnext",
		"target": "esnext",
		"types": ["@types/node"]
	},
	"include": ["./../../.sst/platform/**/*", "./platform/**/*"],
}

Platforms

Built-In Platforms

If you want to add a new component to an existing platform (i.e., aws or cloudflare), define it in platform/src/components/[PLATFORM] and it will be copied over to .sst/platform/src/components/[PLATFORM] and it will be added under the platform namespace so you can use it as e.g.,:

new sst.cloudflare.MyCustomComponent('MyComponent', { ... })

New Platforms

For new platforms, you must define the index.ts barrel file yourself, exporting all necessary components. A custom namespace for this platform will then be generated in .sst/platform/src/components/index.ts:

new sst.myplatform.MyCustomComponent('MyComponent', { ... })

Functions

You can add functions in the platform/functions directory and they will also be copied over to .sst/platform/functions.

FAQ

When should I use this?

When you have custom SST components that import from the generated .sst folder. If you have custom components that do not import from .sst, you do not need this.

Why not place the components in .sst myself?

The .sst folder gets destroyed on every .sst install

Why not place my components in a source code directory and leave it as-is?

You would need to then commit any files that you import (and any files they import, and so on). SST does release updates often so you'll find yourself having to commit updates on almost every update.

It says my components are not defined

Verify your custom components have been installed correctly by inspecting .sst/platform/src/.... If your components are not there, run sst install.

However, if sst is configured to use bun, check out the bun section.

How do I update my components

Whenever you make change to the source code of your components, you must run sst install again (or one of the options in the bun section).

Where should I place my utils?

Do not place your utils in a directory directly under platform/src/components e.g., platform/src/components/utils/index.ts, otherwise it will be available as sst.utils, which may be undesired - just place it in a nested directory or outside of src/components, or just do not name the file index.ts.

I keep getting sst is not defined errors

You should not be using the sst namespace in your custom components as this is only resolved at dev/deploy time - you should be directly importing the modules you need, just like the standard sst components do. The same is true for any Pulumi providers you may be referencing.

For example, if we want to create a custom component wrapping sst.aws.Function, we would import Function from ./sst/platform/src/components/aws/function.ts

// Assuming your file is in `infra/custom/platform/src/components/aws/mycomponent.ts
import { Function } from "./function"

// ... and use it in your code instead of `sst.aws.Function`.

Instead of sst.aws.Function.

How can I use other Pulumi providers

Like the sst namespace, you should not be using the Pulumi provider namespace that sst creates in your custom components. Instead, install the provider manually (adding it to your root package.json) and import from that module instead.

For example, if we want to use a Pulumi component from @pulumi/gcp, we'd add @pulumi/gcp to the root package.json and then use imports like

import gcp from "@pulumi/gcp";

Instead of using the global gcp namespace that sst would add if we ran sst add gcp

I keep forgetting to update my components!

You can add the following import to the top of your sst.config.ts so components are reinstalled on every deploy/dev:

import "sst-custom/install";

There's also an install method that you can call in your run function of your sst.config.ts if you'd like to be more explicit:

  // ... rest of config
  async run() {
    sstcustom.install();
  }

Both do the same thing and it is personal preference.

Readme

Keywords

Package Sidebar

Install

npm i sst-custom

Weekly Downloads

1

Version

0.0.11

License

MIT

Unpacked Size

103 kB

Total Files

24

Last publish

Collaborators

  • ernxst