Skip to content

feat: resolve __SST_DIRNAME and __SST_FILENAME at built time #72

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

CorentinDoue
Copy link
Contributor

@CorentinDoue CorentinDoue commented Apr 19, 2025

ℹ️ Migration of Pull Request sst/sst#3348 from main SST repo.

Please see history of comment there.

Why

resolve sst/sst#1068

This enables to reference file paths as it can be done with __dirname or __filename on unbundled files.

This is useful for creating utils to link handler files to their trigger declaration in SST.

export const getHandlerPath = (
  dirname: string,
  handlerRelativePath = 'handler.main',
): string => {
  const processRunLocation = process.cwd();
  const relativeDirname = dirname.replace(processRunLocation + '/', '');

  return [relativeDirname, handlerRelativePath].join('/');
};

First example: declare triggers next to the handlers

├─ packages
|  └─ functions
|     └─ src
|        └─ myFunction
|           ├─ config.ts
|           └─ handler.ts
└─ stacks
   └─ MyStack.ts
// packages/functions/src/myFunction/config.ts
export const configureMyFunction = ({ api }: MyStackServices): void => {
  api.addRoutes(api, {
    "GET /myFunction": getHandlerPath(__SST_DIRNAME),
  });
}
// stacks/MyStack.ts
export const MyStack = ({ stack }: StackContext) => {
  const api = new Api(stack, "Api");

 const myStackServices: MyStackServices = { api };

 configureMyFunction(myStackServices);
};

Second example: declare handler paths next to the handler

├─ packages
|  └─ functions
|     └─ src
|        └─ myFunction
|           ├─ handlerPath.ts
|           └─ handler.ts
└─ stacks
   └─ MyStack.ts
// packages/functions/src/myFunction/handlerPath.ts
export const myFunctionPath = getHandlerPath(__SST_DIRNAME);
// stacks/MyStack.ts
export const MyStack = ({ stack }: StackContext) => {
  const api = new Api(stack, "Api", {
    routes: {
      "GET /myFunction": myFunctionPath,
    },
  });
};

In both cases:

  • it's easy to navigate from the handler to its trigger and the other way around with CMD+click.
  • no more hard-coded magic string

We use this util with Serverless Framework and CDK which supports __dirname. It's painful not to have an alternative in SST.

What

Create two new global variables __SST_DIRNAME and __SST_FILENAME:

  • They never really exist
  • But they are declared to lure typescript.
  • They are replaced by their dirname or filename at the built time by an esbuild plugin.

Impact

On my small project.

Without the plugin, the build of the config file takes ~3ms.

The esbuild plugin takes between 1 ms and 5 ms to parse a file. It becomes preponderant in the build process but it remains fast (~20ms). The parsed files are only the IaC files, files compiled for lambda runtime are not impacted.

For projects with thousands of IaC files, the build will be slower. But when you have a thousand lambdas you want to avoid having thousands of magic strings to link handlers to triggers 😜.

As this feature impacts performance, I propose to opt-in it. WDYT? What is the best way to do this? A new param advanced.enablePathInjection in SSTConfig?

TODO before merge

  • Discuss this with one of the core team @thdxr @fwang @jayair
  • Validate & implement opt-in if necessary
  • Document. Where is the appropriate place to document this?

Copy link

netlify bot commented Apr 19, 2025

Deploy Preview for sst-docs canceled.

Name Link
🔨 Latest commit 2926b2d
🔍 Latest deploy log https://app.netlify.com/sites/sst-docs/deploys/68037e0220a92700082f2863

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Passing a JS/TS lambda handler by reference instead of src path
1 participant