sst-custom
v0.0.11
Published
A Pulumi provider for defining custom SST components.
Downloads
28
Readme
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:
- Run
NO_BUN=1 sst install
to run the install withnpm
instead - Run
bun sst-custom-install
to manually install the components - 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.