Closed sam-goodwin closed 4 years ago
In hindsight, the erasure library is wrong. Should instead add a flag to package.json so the the linter can also detect which packages to error on. Achieves the same result. Duh.
Wow! Love it!
Awesome job! Congrats on that win!
So, if I understood correctly, the CDK is gone from the lambda bundles. How about Punchcard? Could you explain in short what sort of overhead is being done by punchcard on a cold start?
Of course, I only see six extra calls here before we get to calling the lambda itself:
CDK.chain(({core, lambda}) => app.map(app => {
const stack: cdk.Stack = new core.Stack(app, 'my-stack');
const fn: lambda.Function = new lambda.Function(stack, 'MyFunc', { .. });
});
But, is there anything significant behind them? (chain
, map
, Function
) Or are they stubbed away when compiled? Or are they being called at all?
Thanx! Rock on!
Punchcard is still in there and any code that manipulates/creates constructs but it's pretty insignificant and doesn't actually run (it just contributes to the code size). E.g. this code below is still in the webpacked bundle but it never runs:
scope.map(scope => new dynamodb.Table(scope, 'id', { .. })
The CDK dependencies (@aws-cdk/aws-dynamodb
and @aws-cdk/core
) are entirely removed from the bundle and don't contribute to the size or cold start. I'm not sure I can remove more without getting deeper into the TSC compiler or Webpack code. I could do something really nasty like how Pulumi serializes a closure, but that has other downsides like destroying stack traces and limiting syntax.
Punchcard's impact on cold start is limited to just requiring
your module, so any work that is done by requiring your index.js
will be ran on cold start - instantiating some classes and creating some shapes, for example. Those classes don't do anything expensive though since most of the heavy lifting is suspended within a Build
lazy context and erased. It does add some size, but I think a 32KB-160KB zip file is manageable for most cases. Whenever it is unacceptable, Punchcard does not stop you from "dropping down" and using the vanilla CDK. I expect the cost will be around the same but it'd be fun to do some testing and see just how far away from ideal we are.
Hooray! This change effectively removes the entire CDK framework from the bundle after webpack. I also removed our dependency on
moment-js
as it was contributing 500KB (WTF) to the bundle. The impact is drastic - a punchcard bundle is down from 2MB to 100KB (32KB compressed) when usingproduction
mode, and ~600KB (175KB compressed) indevelopment
mode. This should make Punchcard's impact on cold start negligent :) @birowsky, i hope this is looking better! It should also support configuration of webpack on a per-function basis.Typescript 3.8 introduced a new feature: type-only imports that allows developers to explicitly declare an import as types only, meaning it is entirely erased after compilation. This was the final piece of the puzzle required to support totally removing CDK dependencies from the global import scope, allowing webpack to erase them during tree-shaking.
CDK dependencies are still
dependencies
(notdevDependencies
), but now they are only allowd to be imported as types. To actually use the CDK, you must "map into" the globalCDK
Build
context. It is forbidden to import these libraries outside of aBuild
scope. A custom linter@punchcard/linter
(with rule name:punchcard-transient-imports
) detects and auto-fixes this!Below is a copy of
CDK
which lazily exposes the CDK libraries encapsulated in aBuild
context.I have also introduce a new, very simple module:
@punchcard/erasure
. It simply stands as a global hook for these new "transient" modules to declare themself when imported. E.g.@punchcard/constructs
contains CDK code, so itsindex.ts
marks itself for erasure.Punchcard will then configure a
webpack.IgnorePlugin
for each globally registered regex, effectively erasing it from the runtime bundle. This self-declaration should create a hands-off experience for developers depending on "transient" packages.