Optimize large bundles' build size with content source compilation dependency duplication
This feature was introduced in Engine 4.1.8 and 5.0.4 releases that brings additional compiler options using a new arc.config.json
configuration file. See arc.config.json documentation to learn more about other compiler options.
Introduction and Demo
When Engine compiles your bundle source code into Lambda-ready code, it produces individual server-side mini bundles for each of your content sources so that when a /pf/api/content
call is received, a leaner Lambda handler can be executed to fetch content. This process produces unnecessary code duplication when many content sources import the same dependencies. Depending on the number of content sources and imported dependencies, this caused the compiled server-side code to be bloated and resulted in deployment failures due to exceeding the AWS Lambda file size limitations.
This new feature utilizes webpack.externals
to minimize the duplication of dependencies inside the Lambda after compilation by allowing the exclusion of node_modules
to be removed from content sources. This is possible because content sources are invoked server-side.
Two new variables are exposed to engine through an optional file in the root of your bundle called arc.config.json
:
compiler.contentSources.excludeModules
is essentially a boolean flag for now, but allowing*
opens the possibility to support file globs in the future. When this property is set to*
, it will exclude all dependencies innode_modules
from being bundled into the content source.compiler.contentSources.includeModules
allows developers to explicitly bundle specific modules into the content source when this functionality is enabled. This allows customers to retain some backwards compatibility when opting into this. In this example, we are showcasing a common logging library for typescript (typescript-logging
) that has side effects when included fromnode_modules
. If importing a dependency fromnode_modules
affects the behavior of your content source, you may want to designate the dependency to be bundled directly into your content source to maintain the existing behavior.
-
Create or update the
arc.config.json
in the root of your bundle to have the following properties:{"compiler": {"contentSources": {"excludeModules": "*","includeModules": ["typescript-logging"]}}} -
Re-run the bundle and check the file sizes for
.fusion/build/content/sources
Benchmarks
We have tested a few bundles that exceed lambda size limits. After evaluating different build artifacts, we found that compiled content sources were the main culprit for deployment issues on the AWS Lambda filesystem.
By enabling this configuration, the PageBuilder compiler will exclude node_modules
from bundling into the content sources. In this example, the majority of content sources were importing the same dependency. The actual JavaScript in the content/sources
folder was quite optimized and DRY (don’t repeat yourself), but 1MB of dependencies multiplied by 100 content sources would previously generate 99MB of duplicated code. By removing this duplication during compilation, this yields a substantial file size reduction.
We simply enabled build configuration in the example above, and checked the total build folder size using the du -h -d 2 .fusion/build
command, that just calculates the directory sizes starting from .fusion/build
directory down to 2 levels deep.
Here are some examples we ran in our benchmarks:
Bundle1 - 77% size reduction
Before:
| After:
|
Bundle2 - 65% size reduction
Before:
| After:â–¶ du -h -d 2 .fusion/build 79M build/content/sources 79M build/content 6.0M build/components/output-types 6.2M build/components 12K build/environment 86M build |
Bundle 3 - 39% size reduction
Before:
| After:
|
Additional context about size limits
AWS Lambda enforces a 250MB total size limit that is shared between PageBuilder Engine core, Arc Blocks (if used), and the custom bundle code.