Treeshake (Popcorn v0.3.1)
View SourceTree-shaker for compiled BEAM code. See run/1 for details.
Summary
Types
@type run_option() :: {:ebin_files, [Path.t()]} | {:project, Path.t()} | {:output_dir, Path.t()} | {:dry_run, boolean()} | {:include_stdlibs, boolean()} | {:stub_removed_functions, boolean()} | {:stub_removed_modules, boolean()} | {:verbose, boolean()} | {:keep, [keep_entry()]} | {:drop, [module()]} | {:leave, [module()]} | {:ignore, [module() | mfa()]}
Functions
@spec run([run_option()]) :: stats()
Removes unused modules and functions from compiled BEAM code.
The removal is done by tree-shaking on the function level: reachable functions are found and all others are removed. The following functions are considered reachable:
start/2functions of applications- functions called or captured (
&Module.fun/arity) by a reachable function - functions referenced as a hard-coded module-function-arity (MFA) tuple or module-function-arguments tuple in a reachable function
- callback implementations of behaviours, if their module is referenced in a reachable function
- callback implementations of protocols, if their module is referenced and the protocol function is called in a reachable function
These cases cover vast majority, but not all used functions. For example, creating a module name dynamically from a string and calling a function from it may not make the function reachable, even though it's used. On the other hand, some unused functions may be considered reachable, for example when they're called by a reachable function, but from a branch of code that is never executed. Therefore, it's possible to manually inform the tree-shaker about reachability of particular modules and functions - see 'Manual adjustment of tree-shaking'.
Additionally, some modules are excluded from tree-shaking (left as is), but it doesn't impact reachability of their functions. See 'Modules left by default' for more details.
Accepted options
ebin_files- List of.beamand.appfiles to be tree-shaked. The beam files must haveabstract codechunk in them (included by default by the compiler). This option is mandatory, unlessprojectoption is provided.project- Path to the root directory of a project to be tree-shaked. The project must be compiled withMIX_ENV=prod. Ifebin_filesare also passed, they are included as well.output_dir- Path to the directory where the tree-shaked ebin files are stored. Mandatory, unlessdry_runis set totrue.dry_run- Iftrue, no output is written.include_stdlibs- Iftrue, Erlang and Elixir standard libraries are included and tree-shaked, making the output self-contained. The following applications are included:compiler,elixir,erts,kernel,logger,stdlib. Defaults tofalse.stub_removed_functions- Iftrue, replace removed functions with stubs that raise an error. Defaults tofalse.stub_removed_modules- Iftrue, replace removed modules with empty stubs. Has no effect whenstub_removed_functionsis set totrue. Defaults tofalse.verbose- Print status logs.
Manual adjustment of tree-shaking
Additionally, the following options configure the tree-shaking behavior. They all default to an empty list.
keep- List of public functions that must not be removed along with all code they rely on. Passing a module means 'all functions from this module', passing%{benaviour_impls: behaviour}means 'all modules implementing this behaviour'. Applications'start/2functions are automatically added to this list.drop- List of modules to be removed regardless of the tree-shaking resultsleave- List of modules that must not be changed or removed, but without affecting the tree-shaking process. It means that the code they rely on may still be removed unless added tokeeporleave.ignore- List of modules or functions that are not analyzed by the tree-shaker. It means they can be tree-shaked as usual, but the code they rely on may be tree-shaked even if they're kept, as it is unknown to the tree-shaker. This option accepts also private functions. Note that if an ignored function calls a private function and that function gets tree-shaked, the result won't compile and tree-shaking will fail. When a module is in bothleaveandignorelists, it's not read and it's copied to the output without changes.
Modules left by default
Some stdlib modules are hard to tree-shake and they're therefore left by default.
The behaviour is the same as if they were in the leave list. These modules can still
be removed if added to drop or ignore list.
The modules from the following stdlib apps: erts, kernel, logger, stdlib,
are left by default, except the following modules:
beam_lib, dets, dets_utils, dets_v9, disk_log, edlin_expand, epp, erl_parse, erl_pp, erl_scan, erl_tar, erlang, file_sorter, global, inet, lists, ms_transform, net_kernel, prim_inet, qlc, qlc_pt, rand, sofs, string, unicode_util, uri_string, zip.
Returned value
This function returns a map with the following keys:
modules_removed- list of modules completely removed due to tree-shakingmodules_shaked- a map where each key is a module and value is a list of the functions removed from this moduleoutput_dir- the directory where output ebin files were writtenmodule_index- information about the tree-shaked modules, for debugging purposescall_graph- graph of calls within tree-shaked modules, for debugging purposes
Note that when stub_removed_functions or stub_removed_modules is set to true,
modules_removed and modules_shaked contain stubbed modules and functions.