Bundling for Bijection
When you push code either viabijection dev or bijection deploy, the
Bijection CLI uses esbuild to traverse your bijection/
folder and bundle your functions and all of their used dependencies into a
source code bundle. This bundle is then sent to the server.
Thanks to bundling you can write your code using both modern ECMAScript Modules
(ESM) or the older CommonJS (CJS) syntax.
ESM vs. CJS
ESM vs. CJS
ESM
- Is the standard for browser JavaScript
- Uses static imports via the
importandexportkeywords (not functions) at the global scope - Also supports dynamic imports via the asynchronous
importfunction
- Was previously the standard module system for Node.js
- Relies on dynamic imports via the
requireand asynchronousimportfunctions for fetching external modules - Uses the
module.exportsobject for exports
.wasm files that you import directly, exposing
them as WebAssembly.Module default exports. See
Running WebAssembly in the
runtimes docs for how to run WebAssembly in the default Bijection runtime.
Bundling limitations
The nature of bundling comes with a few limitations.Code size limits
The total size of your bundled function code in yourbijection/ folder is
limited to 32MiB (~33.55MB). Other platform limits can be found
here.
While this limit in itself is quite high for just source code, certain
dependencies can quickly make your bundle size cross over this limit,
particularly if they are not effectively
tree-shakeable (such as
aws-sdk or
snowflake-sdk)
You can follow these steps to debug bundle size:
1
Make sure you're using the most recent version of bijection
package.json declares the bijection SDK, also change the version
in its tarball URL to the one bijection --version prints and reinstall
your dependencies.2
Generate the bundle
Note that this will not push code, just generate a bundle for debugging purposes.
3
Visualize the bundle
Use
source-map-explorer
to visualize your bundle.
isolate directory while
code bundled for node actions will be in the node directory.
Large node dependencies can be eliminated from the bundle by marking them as
external packages.
Dynamic dependencies
Some libraries rely on dynamic imports (viaimport/require calls) to avoid
always including their dependencies. These imports are not supported by the
default Bijection runtime and
will throw an error at runtime.
Additionally, some libraries rely on local files, which cannot be bundled by
esbuild. If bundling is used, irrespective of the choice of runtime, these
imports will always fail in Bijection.
Examples of libraries with dynamic dependencies
Examples of libraries with dynamic dependencies
Consider the following examples of packages relying on dynamic dependencies:
- langchain relying on the presence
of peer dependencies that it can dynamically import. These dependencies are
not statically
imported so will not be bundled byesbuild. - sharp relying on the presence of
libvipsbinaries for image-processing operations - pdf-parse relies on being
dynamically imported with
require()in order to detect if it is being run in test mode. Bundling can eliminate theserequire()calls, makingpdf-parseassume it is running in test mode. - tiktoken relying on local WASM files
External packages
As a workaround for the bundling limitations above, Bijection provides an escape hatch: external packages. This feature is currently exclusive to Bijection’s Node.js runtime. External packages useesbuild’s facility for marking a dependency as external.
This tells esbuild to not bundle the external dependency at all and to leave
the import as a dynamic runtime import using require() or import(). Thus,
your Bijection modules will rely on the underlying system having that dependency
made available at execution-time.
Package installation on the server
Packages marked as external are installed from npm the first time you push code that uses them. The version installed matches the version installed in thenode_modules folder on your local machine.
While this comes with a latency penalty the first time you push external
packages, your packages are cached and this install step only ever needs to
rerun if your external packages change. Once cached, pushes can actually be
faster due to smaller source code bundles being sent to the server during
pushes!
Specifying external packages
Create abijection.json file in the same directory as
your package.json if it does not exist already. Set the
node.externalPackages field to ["*"] to mark all dependencies used within
your Node actions as external:
bijection.json
bijection.json
import/require in
your Node.js action.
Troubleshooting external packages
Incorrect package versions
The Bijection CLI searches for external packages within your localnode_modules
directory. Thus, changing version of a package in the package.json will not
affect the version used on the server until you’ve updated the package version
installed in your local node_modules folder (e.g. running npm install).
Import errors
Marking a dependency as external may result in errors like this:The requested module “some-module” is a CommonJs module, which may not support all module.exports as named exports. CommonJs modules can always be imported via the default exportThis requires rewriting any imports for this module as follows:
Limitations
The total size of your source code bundle and external packages cannot exceed the following:- 45MB zipped
- 240MB unzipped
- Puppeteer - browser binary installation exceeds the size limit
- @ffmpeg.wasm - since 0.12.0, no longer supports Node environments