5

Typescript recently introduced a new feature to work with monorepos: references. By specifying references you can build all interdependent packages using tsc -b (see also this blog post)

This seems ideal for use with a large mono repo where some packages are serverless services. These services typically depend on one or more packages of the monorepo. I've created an example here:

https://github.com/tommedema/serverless-mono-example

While building works well with tsc -b, the problem is that the serverless framework needs to upload a single artifact .zip (to AWS in my case). When building a serverless service, like this example, only the compiled files of the nearest source files will be bundled.

How would one use typescript's references feature for use with serverless mono repos?

Tom
  • 8,536
  • 31
  • 133
  • 232

1 Answers1

3

If it works for you to generate a single output file and use a module loader, you can use outFile and prepend.

If you want multiple output files, maybe it's worth filing a suggestion to ask for an option to bundle dependencies in that case; you would be the second person who has asked about this on Stack Overflow today. Edit: Suggestion is here.

Edit 2: After extensive discussion, the conclusion was to enable the nohoist option on the final Yarn workspace, which gives us symlinks from node_modules to the other workspaces. After we call tsc -b in the final workspace, the Serverless packaging tool follows the symlinks and produces a zip file with the correct structure. No bundling is needed at the TypeScript level. Caveat: Yarn seems to install devDependencies of dependencies in the final workspace, which seems wrong to me and confuses Serverless into unnecessarily including those modules in the bundle.

Matt McCutchen
  • 28,856
  • 2
  • 68
  • 75
  • I'm fine with usign `outFile`, but `lambda` requires the function code to have an entry point, i.e. a `module.exports = functionName`. The `outFile` option only allows for `amd` or `system` modules, and therefore doesn't seem compatible with lambda? – Tom Aug 20 '18 at 23:00
  • In other words, Lambda expects you to provide a CommonJS module? You may be able to use TypeScript's `amd` output and then add in [`amdefine`](https://requirejs.org/docs/node.html#nodeModules) to make the result loadable as a CommonJS module. But this is a hack. I'll file a suggestion for a better way. – Matt McCutchen Aug 20 '18 at 23:06
  • Exactly. Thanks for filing a suggestion! Would love to participate in the discussion – Tom Aug 20 '18 at 23:08
  • I also looked at using `amdefine` but this seems non-trivial, I'd have to somehow inject it (including its source since lambda requires all dependencies to be packaged) to the top of the built file. – Tom Aug 20 '18 at 23:13
  • Re `amdefine`: can you do that with a referenced project with `allowJs` and the `prepend` option? – Matt McCutchen Aug 20 '18 at 23:14
  • It says `Option 'allowJs' cannot be specified with option 'declaration'.` The declaration option seems quite important, so I guess not? – Tom Aug 20 '18 at 23:18
  • I got something sort of working at https://github.com/mattmccutchen/serverless-mono-example/tree/amdefine: I can `require('./packages/serverless-random/dist')` in the Node REPL and the function works. However, I realized another problem: there's no mechanism to copy `node_modules` from `random` to `serverless-random`, so you'd have to add all the dependencies of `random` to `serverless-random`, which is ugly. If you opt to instead use another tool to copy the `node_modules`, then the TypeScript suggestion is of questionable value, but then so is the existing `prepend` option. – Matt McCutchen Aug 21 '18 at 00:17
  • New idea: given that you are using Yarn workspaces and Yarn makes a symlink from `node_modules/@org/random` to `packages/random`, etc., is there a way you could get your packaging process to pick up `packages/random` via that symlink, the same way you pick up the rest of the dependencies? Then you don't need anything special from `tsc`. – Matt McCutchen Aug 21 '18 at 00:29
  • I don't really have a "packaging process", I thought that this is where the Typescript build feature could help. I expected Typescript to follow dependencies (hence the need to define `references`), such that it could bundle all deps to a single folder or file. Since this is not possible, perhaps my only way out is to resort to the old fashioned way of using webpack. There is an example here: https://github.com/serverless-heaven/serverless-webpack/tree/master/examples/typescript -- however there are several issues with this approach, hence me looking to use the new tsc -b feature. – Tom Aug 21 '18 at 03:04
  • [One example of such issue](https://github.com/serverless-heaven/serverless-webpack/issues/435) and [another](https://github.com/serverless-heaven/serverless-webpack/issues/436) – Tom Aug 21 '18 at 03:05
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/178405/discussion-between-matt-mccutchen-and-tom). – Matt McCutchen Aug 21 '18 at 03:16