floydspace / serverless-esbuild

💨 A Serverless framework plugin to bundle JavaScript and TypeScript with extremely fast esbuild
MIT License
453 stars 139 forks source link

Allow configuring additional entryPoints to ease use with Typeorm migrations #328

Open mishabruml opened 2 years ago

mishabruml commented 2 years ago

Is your feature request related to a problem? Please describe. I'm using typeorm with migrations. The generated migration files are named with a timestamp e.g. 12345-migration.ts. The common approach for including migrations in your Typeorm is providing a config option with a file glob eg:

migrations - Migrations to be loaded and used for this data source. Accepts both migration classes and directories to load from. Directories support glob patterns. Example: migrations: [FirstMigration, SecondMigration, "migration/*.js", "modules/**/migration/*.js"]. Learn more about Migrations. https://typeorm.io/data-source-options#common-data-source-options

Sadly esbuild cannot statically resolve this at build time and so the migrations files will not be available to the code at runtime in a lambda environment.

Due to this, my current workaround is to output the generated migrations files as js files and include them (via serverless framework)

package:
  individually: true
  include:
    - "src/migrations/*.js"

As long as the paths are correct, the bundled lambda code can then find the migrations files.

However, I did a little experiment and figured out that if you provide the migrations files as entrypoints for an esbuild script, the migrations files will be bundled too with the lambda code, which is the preferred approach for me (the migrations files can then be generated in TS which is just better for everybody). The caveat here is that I had to glob the migrations files directory for the entrypoints, but that was pretty easy https://github.com/evanw/esbuild/issues/381#issuecomment-691273255 or https://github.com/waspeer/esbuild-plugin-glob

Describe the solution you'd like Provide an option to describe additional entrypoints so that code that is required for runtime but not imported (in a way that esbuild can analyse) can be included in the bundle, so that handler code can access these files.

mishabruml commented 2 years ago

OK @samchungy I've managed to write a plugin to enable this, but its a bit brittle IMO.

Demo repo: https://github.com/mishabruml/typeorm-playground

The plugin is written in TS and gets compiled via esbuild and wired into serverless-esbuild via plugins file

The typeorm datasource globs migrations files conditionally on env var. This enables TS migrations files to be run via typeorm CLI (ts-node under the hood), or js files for the lambda execution environment. I couldn't just simply provide both globs as arg to the migrations option because the TS files contain imports form typeorm that are not available at lambda runtime when bundled with esbuild, and so produce runtime errors.

The lambda can be invoked locally, but in order to run this you'll need a postgres db running locally at postgres://postgres:postgrespw@localhost:55001 (I did this with docker)

I did find a limitation; the migrations directory (or any directory passed in to additionalEntrypoints option of additionalEntrypointsGlobPlugin) needs to live inside the src/handlers directory otherwise esbuild gets very confused resolving output build directory structure. This is something I'd like to understand more.

mishabruml commented 2 years ago

@floydspace I see that https://github.com/floydspace/serverless-esbuild/pull/323 has just been merged. I will try it out myself later, but what are the consequences of defining entryPoints via the config? Will it break the automatic entrypoints resolution from the serverless.yml file?