AfterPack 的选项可以在 afterpack.json 中设置,也可以作为环境变量、CLI 参数或插件选项设置,或者只针对源代码中的某一区域设置(Pro)。后面的位置会覆盖前面的位置。
不做任何设置的构建使用 light 预设。afterpack.json 会从工作目录向上查找,使用最近的一个。
接受列表的选项会替换其默认列表。列表项不会被追加,因此要保留的默认项需要重复写出。
Protection
How strongly the output is protected.
preset
A named level of protection. Sets complexity; output size follows from that target. light encodes string literals, renames identifiers and rewrites syntax, and adds no structural layers; medium and above drive every token toward the target. Setting complexity explicitly overrides the target, and a value set directly applies to every token, even on light.
- Type
- enum
- Default
- light
- Values
{ "preset": "hard" }complexity
How much protection the engine applies. 0 applies none; higher values let it negotiate more and heavier transformations per build, with no fixed feature-per-level schedule. There is no upper bound, and output size grows with the value.
- Type
- number ≥ 0
- Default
- the preset's value; light is 5
{ "complexity": 40 }inflation.max
The maximum output size as a multiple of the input size. A build that would grow past a value you set fails. Left unset, the preset's complexity target decides how much the output grows; typical sizes are on the Performance page.
From engine 0.2.3, the finished file is checked against the limit and string encoding always completes. In 0.2.2, a tight limit could stop string encoding early and leave some strings readable.
- Type
- number ≥ 0, or "unlimited"
- Default
- unset
{ "inflation": { "max": 4 } }strings.encode
Encodes every string literal so that none remains readable in the output.
- Type
- boolean
- Default
- true at any positive complexity; false at 0
{ "strings": { "encode": false } }strings.minLength
The shortest string strings.encode encodes. Shorter strings stay readable. Raising it reduces output size at the cost of leaving short literals in the clear.
- Type
- integer ≥ 0
- Default
- 0
{ "strings": { "minLength": 4 } }strings.leaks.max
Fails the build when more than this many readable string literals remain in the output. Unset never fails.
- Type
- integer ≥ 0
- Default
- unset; the count is reported but never fails a build
{ "strings": { "leaks": { "max": 0 } } }strings.preserveLiterals
String values kept exactly as written, never encoded. Use it for placeholders a later build step replaces, such as a content hash or a manifest token.
- Type
- string[]
- Default
- []
{ "strings": { "preserveLiterals": ["__BUILD_HASH__"] } }transforms.<kind>.enabled
Enables or disables one kind of transformation. false reliably removes that kind at any complexity; true permits it, and the engine still decides per build whether to apply it. Outside a region you raise, the only kinds light applies are string encoding and comparisonHardening. comparisonHardening and selfIntegrity are Pro, and selfIntegrity needs code at medium or above.
From engine 0.2.3, turning off scopeDeepen at medium or above can leave part of a file short of its target, and the build then fails with DIAG_TARGET_NOT_REACHED. A selfIntegrity build with no code at medium or above fails with DIAG_SELF_INTEGRITY_INERT.
- Type
- boolean
- Default
- true; the two Pro kinds default to false
{ "transforms": { "controlFlowFlatten": { "enabled": false } } }regionsPro
Region overrides supplied by a build tool instead of source comments. Each entry names a span of your original source and the keys to override inside it.
- Type
- { start, end, …keys }[]
- Default
- []
{ "regions": [{ "start": 1200, "end": 1840, "complexity": 25 }] }skipPro
Drops the region to complexity 0, so no transformation is applied inside it and its string literals stay readable. Identifiers inside it are still renamed.
Identifier renaming applies to the whole program and has no per-region form. To keep a name, list it in identifiers.reserved.
- Type
- boolean
- Default
- false
Only meaningful in a directive.
Scope and preservation
Files, names and runtime patterns AfterPack must leave alone.
paths.include
Globs that re-admit what the CLI's directory walk skips. Nested node_modules/ is skipped by default; **/node_modules/** walks it and takes every .js/.mjs/.cjs inside. It only ever adds files, and paths.exclude still wins over it.
A walk-only key: it does nothing in a bundled build, where the bundler has already inlined your dependencies into the chunks and no node_modules path is left to match. Same glob grammar as paths.exclude, which means an unanchored pattern is tried at every path segment, so any non-empty value lets the walk descend into node_modules/ and ["src/**"] matches dependency files under node_modules/*/src/ too. Lead with / to anchor a pattern to one absolute location. Quote the glob on a command line or the shell expands it first.
- Type
- glob[]
- Default
- []
{ "paths": { "include": ["**/node_modules/**"] } }paths.exclude
Files to leave untouched, as globs. A matching file is copied to the output unchanged. Applies to files, not to code a bundler has already merged into your bundle.
- Type
- glob[]
- Default
- []
{ "paths": { "exclude": ["**/*.min.js", "dist/vendor/**"] } }identifiers.rename
Renames identifiers. false keeps every name and is meant for debugging; use identifiers.reserved to keep specific names. Exported and reflected names are never renamed.
- Type
- boolean
- Default
- true
{ "identifiers": { "rename": false } }identifiers.globals.rename
Also renames the top-level names of a classic script. Safe only for a script nothing else calls into, in a single-file build.
- Type
- boolean
- Default
- false
{ "identifiers": { "globals": { "rename": true } } }identifiers.methods.rename
Obfuscates class method names, including what Function.prototype.name returns. false keeps them, for code that reads fn.name, such as a dependency-injection container or a serializer.
- Type
- boolean
- Default
- true
{ "identifiers": { "methods": { "rename": false } } }identifiers.reserved
Identifier names that are never renamed. A plain name applies to the whole build. Use it for names other code expects, such as a bundled library's public API.
An item can also be { "glob": "src/legacy/**", "names": ["jQuery"] }, which applies only inside matching files. That form is afterpack.json and plugin options only; a flag or a variable carries plain names.
- Type
- (string | { glob: string, names: string[] })[]
- Default
- []
{ "identifiers": { "reserved": ["Hls", "gtag"] } }reflection.allow
Runtime reflection patterns your code relies on. AfterPack fails the build when it detects a pattern you have not listed. angular and nestjs expand to the patterns those frameworks need.
- Type
- enum[]
- Default
- []
- Values
{ "reflection": { "allow": ["functionToString"] } }Output
Files a build writes next to your code.
sourceMap.enabled
Writes a source map next to the output. In development, AfterPack writes its own map, with your original source in it, when an input map exists. A production build also deletes the source maps your bundler wrote, because they contain your original source: .map files, hidden and inline maps, sourceMappingURL comments and CSS maps. With this option on, AfterPack's map replaces the bundler's JavaScript map and CSS maps are kept. A map that can't be removed fails the build. A published map reverses the obfuscation. Never deploy it.
Maps inside node_modules, or inside a folder of the build directory that has its own package.json, are left alone.
- Type
- boolean
- Default
- false; true in development mode when an input map exists
{ "sourceMap": { "enabled": false } }sourceMap.sourcesContent
Embeds your original source in the map. Never publish a map with this on.
- Type
- boolean
- Default
- false; true in development mode
{ "sourceMap": { "sourcesContent": false } }sourceMap.emitUrl
Appends the //# sourceMappingURL= comment to the output. The map file is written regardless.
- Type
- boolean
- Default
- false; true in development mode
{ "sourceMap": { "emitUrl": false } }protectionMap.enabled
Writes the Protection Map, an HTML report of what was applied to each part of your source, into .afterpack/. A Pro cloud build writes no local file: its map is stored in the dashboard, and the build prints a link to it. Off by default in CI (CI=true or CI=1) unless you set it. The report contains your full source. Never publish it.
- Type
- boolean
- Default
- true when the bundler emitted a source map, outside CI
{ "protectionMap": { "enabled": false } }protectionMap.detailed
Lists, for every region of the Protection Map, the transformations applied to it. false makes the report smaller.
- Type
- boolean
- Default
- true
{ "protectionMap": { "detailed": false } }Build
How a build runs.
seed
The random seed for the build. Unset, every build gets a new seed and different output, and a plugin gives every content-hashed file a new name, so browsers download it again. Set a number, any string, or "git" for the current commit to reproduce a build.
- Type
- number | string | "git"
- Default
- a new random seed per build
{ "seed": "git" }build.mode
Selects production or development defaults for output settings such as source maps and backups. A build is development only when build.mode is development, set in afterpack.json, as --build.mode=development, as AFTERPACK_build_mode or as a plugin option, or when NODE_ENV=development. Parcel builds follow Parcel's own mode. Everything else is production: an unset NODE_ENV, NODE_ENV=test, any CI value and a local npx afterpack. webpack, Vite and Rollup's own mode is not read, so set NODE_ENV=development or build.mode for a development build.
- Type
- enum
- Default
- production, unless NODE_ENV is development
- Values
{ "build": { "mode": "production" } }sourceType
Whether the engine reads your output as ES modules or classic scripts. A classic script's top-level names are globals other scripts can use; a module's are not. With auto, a file with import or export, or a .mjs file, is a module, and the framework plugins and the CLI set the value from your build when they can tell.
Needs engine 0.2.3 or later; an older engine rejects the key. The plugins and the CLI send their own value only to an engine that accepts it. Set it yourself only to correct a wrong guess.
- Type
- enum
- Default
- auto
- Values
{ "sourceType": "module" }build.autorun
Runs AfterPack automatically at the end of your bundler's build. With false the plugin only reads directives, and you run the engine yourself.
- Type
- boolean
- Default
- true
{ "build": { "autorun": false } }build.backup
Keeps a verbatim copy of every original file, so a run can be undone. The CLI writes a backup DIRECTORY for each build directory, .afterpack/backups/<build dir>/ at your project root, with a manifest recording what each file became, and afterpack restore puts the originals back under their original names; it is on there by default. A framework plugin writes a .backup.<hash> sibling beside each output file instead, and only when you set this to true.
Either form is your source verbatim. The plugin's sibling lands inside the tree you deploy; the CLI's directory sits outside it, gitignored. Never deploy either.
- Type
- boolean
- Default
- false for an in-place pass; the CLI's own backup directory is on by default
{ "build": { "backup": true } }directives.enabled
Reads @afterpack comments in your source and applies them as region overrides. Plugins only: the CLI runs on built output and refuses true.
- Type
- boolean
- Default
- true
{ "directives": { "enabled": false } }diagnostics.level
How much a build prints. summary prints errors in full and counts the rest. all prints everything. none silences the progress and summary lines; errors still print.
- Type
- enum
- Default
- summary
- Values
{ "diagnostics": { "level": "all" } }diagnostics.format
Switches the CLI's own output between human-readable text and one JSON document on stdout, with every human-readable line moved to stderr. This is the shape a CI step or an AI agent should read.
CLI only; a plugin build accepts and ignores it, since a bundler owns its own build output, not stdout.
- Type
- enum
- Default
- text
- Values
{ "diagnostics": { "format": "json" } }telemetry.enabled
Sends an anonymous report when a build reports an error-level diagnostic (a refused or partial build): the diagnostic code, byte offsets, and the tool, OS and architecture versions. Never source, paths or file names. A clean build sends nothing.
- Type
- boolean
- Default
- true
{ "telemetry": { "enabled": false } }keyPro
Your Pro API key. With a key, builds run in AfterPack's cloud with Pro protection. Set it through the environment or a CI secret rather than a committed file.
- Type
- string
- Default
- unset; builds run locally
{ "key": "ap_v1_…" }afterpack.json 示例
{
"preset": "hard",
"strings": { "minLength": 4 },
"identifiers": { "reserved": ["Hls"] },
"paths": { "exclude": ["**/*.min.js", "dist/vendor/**"] },
"protectionMap": { "enabled": true }
}下一步
- 预设:每个预设设置了什么。
- 复杂度:随数值升高的是什么,以及配置可以关闭哪些变换。
- 指令:对源代码中的某一区域采用不同的保护方式。
- Protection Map:检查一次构建实际应用了什么。