package bundler
Import Path
github.com/evanw/esbuild/internal/bundler (on go.dev)
Dependency Relation
imports 32 packages, and imported by one package
Package-Level Type Names (total 43, in which 2 are exported)
/* sort exporteds by: | */
entryPoints []uint32
files []file
fs fs.FS
res resolver.Resolver
(*T) Compile(log logger.Log, options config.Options) []OutputFile
This is done in parallel with linking because linking is a mostly serial
phase and there are extra resources for parallelism. This could also be done
during parsing but that would slow down parsing and delay the start of the
linking phase, which then delays the whole bundling process.
However, doing this during parsing would allow it to be cached along with
the parsed ASTs which would then speed up incremental builds. In the future
it could be good to optionally have this be computed during the parsing
phase when incremental builds are active but otherwise still have it be
computed during linking for optimal speed during non-incremental builds.
(*T) generateMetadataJSON(results []OutputFile, allReachableFiles []uint32, asciiOnly bool) []byte
(*T) lowestCommonAncestorDirectory(codeSplitting bool, allReachableFiles []uint32) string
func ScanBundle(log logger.Log, fs fs.FS, res resolver.Resolver, caches *cache.CacheSet, entryPoints []string, options config.Options) Bundle
AbsPath string
Contents []byte
IsExecutable bool
If "AbsMetadataFile" is present, this will be filled out with information
about this file in JSON format. This is a partial JSON file that will be
fully assembled later.
func (*Bundle).Compile(log logger.Log, options config.Options) []OutputFile
func (*Bundle).generateMetadataJSON(results []OutputFile, allReachableFiles []uint32, asciiOnly bool) []byte
entries []byte
(*T) bitwiseOrWith(other bitSet)
( T) copyFrom(other bitSet)
( T) equals(other bitSet) bool
( T) hasBit(bit uint) bool
( T) setBit(bit uint)
func newBitSet(bitCount uint) bitSet
The name of this chunk. This is initially empty for non-entry point chunks
because the file name contains a hash of the file contents, which haven't
been generated yet. Don't access this directly. Instead call "relPath()"
which first checks that the base name is not empty.
This is the representation-specific information
For code splitting
entryBits bitSet
// An index into "c.entryPoints"
filesInChunkInOrder []uint32
filesWithPartsInChunk map[uint32]bool
This information is only useful if "isEntryPoint" is true
partsInChunkInOrder []partRange
The path of this chunk's directory relative to the output directory. Note:
this must have OS-independent path separators (i.e. '/' not '\').
// An index into "c.sources"
Returns the path of this chunk relative to the output directory. Note:
this must have OS-independent path separators (i.e. '/' not '\').
This type is just so we can use Go's native sort function
( T) Len() int
( T) Less(i int, j int) bool
( T) Swap(i int, j int)
T : sort.Interface
T : github.com/aws/aws-sdk-go/aws/corehandlers.lener
( T) generate(c *linkerContext, chunk *chunkInfo) func(generateContinue) []OutputFile
*chunkReprCSS
*chunkReprJS
(*T) generate(c *linkerContext, chunk *chunkInfo) func(generateContinue) []OutputFile
*T : chunkRepr
For code splitting
crossChunkSuffixStmts []js_ast.Stmt
exportsToOtherChunks map[js_ast.Ref]string
importsFromOtherChunks map[uint32]crossChunkImportItemArray
(*T) generate(c *linkerContext, chunk *chunkInfo) func(generateContinue) []OutputFile
*T : chunkRepr
PrintResult js_printer.PrintResult
PrintResult.ExtractedComments map[string]bool
PrintResult.JS []byte
This source map chunk just contains the VLQ-encoded offsets for the "JS"
field above. It's not a full source map. The bundler will be joining many
source map chunks together to form the final source map.
If this is an entry point, this is optional code to stick on the end of
the chunk. This is used to for example trigger the lazily-evaluated
CommonJS wrapper for the entry point.
This is the line and column offset since the previous JavaScript string
or the start of the file if this is the first JavaScript string.
sourceIndex uint32
This type is just so we can use Go's native sort function
( T) Len() int
( T) Less(i int, j int) bool
( T) Swap(i int, j int)
T : sort.Interface
T : github.com/aws/aws-sdk-go/aws/corehandlers.lener
This type is just so we can use Go's native sort function
( T) Len() int
( T) Less(i int, j int) bool
( T) Swap(i int, j int)
T : sort.Interface
T : github.com/aws/aws-sdk-go/aws/corehandlers.lener
This type is just so we can use Go's native sort function
( T) Len() int
( T) Less(i int, j int) bool
( T) Swap(i int, j int)
T : sort.Interface
T : github.com/aws/aws-sdk-go/aws/corehandlers.lener
This is data related to source maps. It's computed in parallel with linking
and must be ready by the time printing happens. This is beneficial because
it is somewhat expensive to produce.
This data is for the printer. It maps from byte offsets in the file (which
are stored at every AST node) to UTF-16 column offsets (required by source
maps).
This contains the quoted contents of the original source file. It's what
needs to be embedded in the "sourcesContent" array in the final source
map. Quoting is precomputed because it's somewhat expensive.
// Optional, goes with sourceIndex, ignore if zero
Export star resolution happens first before import resolution. That means
it cannot yet determine if duplicate names from export star resolution are
ambiguous (point to different symbols) or not (point to the same symbol).
This issue can happen in the following scenario:
// entry.js
export * from './a'
export * from './b'
// a.js
export * from './c'
// b.js
export {x} from './c'
// c.js
export let x = 1, y = 2
In this case "entry.js" should have two exports "x" and "y", neither of
which are ambiguous. To handle this case, ambiguity resolution must be
deferred until import resolution time. That is done using this array.
ref js_ast.Ref
This is the file that the named export above came from. This will be
different from the file that contains this object if this is a re-export.
If this file ends up being used in the bundle, these are additional files
that must be written to the output directory. It's used by the "file"
loader.
The minimum number of links in the module graph to get from an entry point
to this file
This holds all entry points that can reach this file. It will be used to
assign the parts in this file to a chunk.
The path of this entry point relative to the lowest common ancestor
directory containing all entry points. Note: this must have OS-independent
path separators (i.e. '/' not '\').
If true, this file was listed as not having side effects by a package.json
file in one of our containing directories with a "sideEffects" field.
This is optional additional information about "ignoreIfUnused" for errors
isEntryPoint bool
If "AbsMetadataFile" is present, this will be filled out with information
about this file in JSON format. This is a partial JSON file that will be
fully assembled later.
loader config.Loader
pluginData interface{}
repr fileRepr
source logger.Source
sourceMap *sourcemap.SourceMap
func findReachableFiles(files []file, entryPoints []uint32) []uint32
func newLinkerContext(options *config.Options, log logger.Log, fs fs.FS, res resolver.Resolver, files []file, entryPoints []uint32, reachableFiles []uint32, dataForSourceMaps func() []dataForSourceMap) linkerContext
This contains linker-specific metadata corresponding to a "file" struct
from the initial scan phase of the bundler. It's separated out because it's
conceptually only used for a single linking operation and because multiple
linking operations may be happening in parallel with different metadata for
the same file.
If true, all exports must be reached via property accesses off a call to
the CommonJS wrapper for this module. In addition, all ES6 exports for
this module must be added as getters to the CommonJS "exports" object.
If true, the module must be bundled CommonJS-style like this:
// foo.ts
let require_foo = __commonJS((exports, module) => {
...
});
// bar.ts
let foo = flag ? require_foo() : null;
The index of the automatically-generated part used to represent the
CommonJS wrapper. This part is empty and is only useful for tree shaking
and code splitting. The CommonJS wrapper can't be inserted into the part
because the wrapper contains other parts, which can't be represented by
the current part system.
The index of the automatically-generated part containing export statements
for every export in the entry point. This also contains the call to the
require wrapper for CommonJS-style entry points.
If true, the "__export(exports, { ... })" call will be force-included even
if there are no parts that reference "exports". Otherwise this call will
be removed due to the tree shaking pass. This is used when for entry point
files when code related to the current output format needs to reference
the "exports" variable.
Imports are matched with exports in a separate pass from when the matched
exports are actually bound to the imports. Here "binding" means adding non-
local dependencies on the parts in the exporting file that declare the
exported symbol to all parts in the importing file that use the imported
symbol.
This must be a separate pass because of the "probably TypeScript type"
check above. We can't generate the part for the export namespace until
we've matched imports with exports because the generated code must omit
type-only imports in the export namespace code. And we can't bind exports
to imports until the part for the export namespace is generated since that
part needs to participate in the binding.
This array holds the deferred imports to bind so the pass can be split
into two separate passes.
This is only for TypeScript files. If an import symbol is in this map, it
means the import couldn't be found and doesn't actually exist. This is not
an error in TypeScript because the import is probably just a type.
Normally we remove all unused imports for TypeScript files during parsing,
which automatically removes type-only imports. But there are certain re-
export situations where it's impossible to tell if an import is a type or
not:
import {typeOrNotTypeWhoKnows} from 'path';
export {typeOrNotTypeWhoKnows};
Really people should be using the TypeScript "isolatedModules" flag with
bundlers like this one that compile TypeScript files independently without
type checking. That causes the TypeScript type checker to emit the error
"Re-exporting a type when the '--isolatedModules' flag is provided requires
using 'export type'." But we try to be robust to such code anyway.
This is set when we need to pull in the "__export" symbol in to the part
at "nsExportPartIndex". This can't be done in "createExportsForFile"
because of concurrent map hazards. Instead, it must be done later.
needsMarkAsModuleSymbolFromRuntime bool
This is the index to the automatically-generated part containing code that
calls "__export(exports, { ... getters ... })". This is used to generate
getters on an exports object for ES6 export statements, and is both for
ES6 star imports and CommonJS-style modules.
partMeta []partMeta
This includes both named exports and re-exports.
Named exports come from explicit export statements in the original file,
and are copied from the "NamedExports" field in the AST.
Re-exports come from other files and are the result of resolving export
star statements (i.e. "export * from 'foo'").
WARNING: This is an interop mess. Different tools do different things and
there really isn't a good solution that will always work. More information:
https://github.com/evanw/esbuild/issues/532.
The value of the "default" export differs between node's ESM
implementation and Babel's cross-compiled ESM-to-CommonJS
implementation. The default export will always be "module.exports"
in node but will be "module.exports.default" with Babel if the
property "module.exports.__esModule" is true (indicating a
cross-compiled ESM file):
// esm-file.mjs
import defaultValue from "./import.cjs"
console.log(defaultValue)
// import.cjs (cross-compiled from "import.esm")
Object.defineProperty(exports, '__esModule', { value: true })
exports.default = 'default'
// import.mjs (original source code for "import.cjs")
export default 'default'
Code that respects the "__esModule" flag will print "default" but node
will print "{ default: 'default' }". There is no way to work with both.
Damned if you do, damned if you don't. It would have been ideal if node
behaved consistently with the rest of the ecosystem, but they decided to
do their own thing instead. Arguably no approach is "more correct" than
the other one.
We need to behave like Babel when we cross-compile ESM to CommonJS but
we need to behave like a mix of Babel and node for compatibility with
existing libraries on npm. So we deliberately skip calling "__toModule"
only for ESM files that we ourselves have converted to CommonJS during
the build so that we at least don't break ourselves.
Never iterate over "resolvedExports" directly. Instead, iterate over this
array. Some exports in that map aren't meant to end up in generated code.
This array excludes these exports and is also sorted, which avoids non-
determinism due to random map iteration order.
( T) importRecords() *[]ast.ImportRecord
*reprCSS
*reprJS
const importCommonJS
const importCommonJSWithoutExports
const importDisabled
const importExternal
const importFound
const importNoMatch
const importProbablyTypeScriptType
// Optional, goes with sourceIndex, ignore if zero
ref js_ast.Ref
sourceIndex uint32
importRef js_ast.Ref
// Optional, goes with sourceIndex, ignore if zero
sourceIndex uint32
const inputKindEntryPoint
const inputKindNormal
const inputKindStdin
columns int
lines int
(*T) advanceBytes(bytes []byte)
(*T) advanceString(text string)
This helps avoid an infinite loop when matching imports to exports
This represents the parallel computation of source map related data.
Calling this will block until the computation is done. The resulting value
is shared between threads and must be treated as immutable.
entryPoints []uint32
files []file
fs fs.FS
This is the relative path for automatically-generated code splitting chunks
relative to the output directory
hasErrors bool
log logger.Log
options *config.Options
We should avoid traversing all files in the bundle, because the linker
should be able to run a linking operation on a large bundle where only
a few files are needed (e.g. an incremental compilation scenario). This
holds all files that could possibly be reached through the entry points.
If you need to iterate over all files in the linking operation, iterate
over this array. This array is also sorted in a deterministic ordering
to help ensure deterministic builds (source indices are random).
res resolver.Resolver
This maps from unstable source index to stable reachable file index. This
is useful as a deterministic key for sorting if you need to sort something
containing a source index (such as "js_ast.Ref" symbol references).
symbols js_ast.SymbolMap
We may need to refer to the CommonJS "module" symbol for exports
(*T) addExportsForExportStar(resolvedExports map[string]exportData, sourceIndex uint32, sourceIndexStack []uint32)
(*T) addPartToFile(sourceIndex uint32, part js_ast.Part, partMeta partMeta) uint32
(*T) addRangeError(source logger.Source, r logger.Range, text string)
(*T) addRangeErrorWithNotes(source logger.Source, r logger.Range, text string, notes []logger.MsgData)
(*T) advanceImportTracker(tracker importTracker) (importTracker, importStatus, []importToBind)
(*T) chunkFileOrder(chunk *chunkInfo) (js []uint32, jsParts []partRange, css []uint32)
(*T) chunkHashForFileName(chunk *chunkInfo, bytes []byte) string
(*T) computeChunks() []chunkInfo
(*T) computeCrossChunkDependencies(chunks []chunkInfo)
(*T) convertStmtsForChunk(sourceIndex uint32, stmtList *stmtList, partStmts []js_ast.Stmt)
(*T) createExportsForFile(sourceIndex uint32)
(*T) generateChunksInParallel(chunks []chunkInfo) []OutputFile
(*T) generateCodeForFileInChunkJS(r renamer.Renamer, waitGroup *sync.WaitGroup, partRange partRange, entryBits bitSet, chunkAbsDir string, commonJSRef js_ast.Ref, toModuleRef js_ast.Ref, result *compileResultJS, dataForSourceMaps []dataForSourceMap)
(*T) generateCodeForLazyExport(sourceIndex uint32)
(*T) generateGlobalNamePrefix() string
(*T) generateSourceMapForChunk(results []compileResultJS, chunkAbsDir string, dataForSourceMaps []dataForSourceMap) []byte
(*T) generateUseOfSymbolForInclude(part *js_ast.Part, fileMeta *fileMeta, useCount uint32, ref js_ast.Ref, otherSourceIndex uint32)
Code splitting may cause an assignment to a local variable to end up in a
separate chunk from the variable. This is bad because that will generate
an assignment to an import, which will fail. Make sure these parts end up
in the same chunk in these cases.
(*T) includeFile(sourceIndex uint32, entryPointBit uint, distanceFromEntryPoint uint32)
(*T) includePart(sourceIndex uint32, partIndex uint32, entryPointBit uint, distanceFromEntryPoint uint32)
(*T) includePartsForRuntimeSymbol(part *js_ast.Part, fileMeta *fileMeta, useCount uint32, name string, entryPointBit uint, distanceFromEntryPoint uint32)
(*T) isCommonJSDueToExportStar(sourceIndex uint32, visited map[uint32]bool) bool
(*T) isExternalDynamicImport(record *ast.ImportRecord) bool
(*T) link() []OutputFile
(*T) markPartsReachableFromEntryPoints()
(*T) matchImportWithExport(tracker importTracker) (result matchImportResult)
(*T) matchImportsWithExportsForFile(sourceIndex uint32)
(*T) pathBetweenChunks(fromRelDir string, toRelPath string) string
Marking a symbol as unbound prevents it from being renamed or minified.
This is only used when a module is compiled independently. We use a very
different way of handling exports and renaming/minifying when bundling.
(*T) renameSymbolsInChunk(chunk *chunkInfo, filesInOrder []uint32) renamer.Renamer
(*T) scanImportsAndExports()
(*T) shouldIncludePart(repr *reprJS, part js_ast.Part) bool
(*T) shouldRemoveImportExportStmt(sourceIndex uint32, stmtList *stmtList, partStmts []js_ast.Stmt, loc logger.Loc, namespaceRef js_ast.Ref, importRecordIndex uint32) bool
Sort cross-chunk exports by chunk name for determinism
Sort cross-chunk imports by chunk name for determinism
func newLinkerContext(options *config.Options, log logger.Log, fs fs.FS, res resolver.Resolver, files []file, entryPoints []uint32, reachableFiles []uint32, dataForSourceMaps func() []dataForSourceMap) linkerContext
absResolveDir string
loader config.Loader
pluginData interface{}
pluginName string
func runOnLoadPlugins(plugins []config.Plugin, res resolver.Resolver, fs fs.FS, fsCache *cache.FSCache, log logger.Log, source *logger.Source, importSource *logger.Source, importPathRange logger.Range, pluginData interface{}, isWatchMode bool) (loaderPluginResult, bool)
const matchImportAmbiguous
const matchImportCycle
const matchImportIgnore
const matchImportNamespace
const matchImportNormal
const matchImportNormalAndNamespace
const matchImportProbablyTypeScriptType
alias string
kind matchImportKind
// Optional, goes with sourceIndex, ignore if zero
namespaceRef js_ast.Ref
// Optional, goes with otherSourceIndex, ignore if zero
otherSourceIndex uint32
ref js_ast.Ref
sourceIndex uint32
caches *cache.CacheSet
fs fs.FS
ignoreIfUnused bool
ignoreIfUnusedData *resolver.IgnoreIfUnusedData
importPathRange logger.Range
importSource *logger.Source
inject chan config.InjectedFile
keyPath logger.Path
log logger.Log
options config.Options
pluginData interface{}
prettyPath string
res resolver.Resolver
results chan parseResult
skipResolve bool
sourceIndex uint32
func parseFile(args parseArgs)
This contains linker-specific metadata corresponding to a "js_ast.Part" struct
from the initial scan phase of the bundler. It's separated out because it's
conceptually only used for a single linking operation and because multiple
linking operations may be happening in parallel with different metadata for
the same part in the same file.
This holds all entry points that can reach this part. It will be used to
assign this part to a chunk.
nextSibling uint32
These are dependencies that come from other files via import statements.
If present, this is a circular doubly-linked list of all other parts in
this file that need to be in the same chunk as this part to avoid cross-
chunk assignments, which are not allowed in ES6 modules.
This used to be an array but that was generating lots of allocations.
Changing this to a circular doubly-linked list was a substantial speedup.
partIndexBegin uint32
partIndexEnd uint32
sourceIndex uint32
func appendOrExtendPartRange(ranges []partRange, sourceIndex uint32, partIndex uint32) []partRange
func appendOrExtendPartRange(ranges []partRange, sourceIndex uint32, partIndex uint32) []partRange
ast css_ast.AST
If present, this is the JavaScript stub corresponding to this CSS file.
A JavaScript stub is automatically generated for a CSS file when it's
imported from a JavaScript file.
(*T) importRecords() *[]ast.ImportRecord
*T : fileRepr
ast js_ast.AST
If present, this is the CSS file that this JavaScript stub corresponds to.
A JavaScript stub is automatically generated for a CSS file when it's
imported from a JavaScript file.
meta fileMeta
(*T) importRecords() *[]ast.ImportRecord
*T : fileRepr
astMap map[runtimeCacheKey]js_ast.AST
astMutex sync.Mutex
definesMap map[config.Platform]*config.ProcessedDefines
definesMutex sync.Mutex
(*T) parseRuntime(options *config.Options) (source logger.Source, runtimeAST js_ast.AST, ok bool)
(*T) processedDefines(key config.Platform) (defines *config.ProcessedDefines)
var globalRuntimeCache
caches *cache.CacheSet
fs fs.FS
log logger.Log
options config.Options
remaining int
res resolver.Resolver
resultChannel chan parseResult
This is not guarded by a mutex because it's only ever modified by a single
thread. Note that not all results in the "results" array are necessarily
valid. Make sure to check the "ok" flag before using them.
visited map[logger.Path]uint32
(*T) addEntryPoints(entryPoints []string) []uint32
(*T) allocateSourceIndex(path logger.Path, kind cache.SourceIndexKind) uint32
This returns the source index of the resulting file
(*T) preprocessInjectedFiles()
(*T) processScannedFiles() []file
(*T) scanAllDependencies()
These statements are for an entry point and come at the end of the chunk
Order doesn't matter for these statements, but they must be outside any
CommonJS wrapper since they are top-level ES6 import/export statements
These statements come last, and can be inside the CommonJS wrapper
These statements come first, and can be inside the CommonJS wrapper
Package-Level Functions (total 21, in which 2 are exported)
func ScanBundle(log logger.Log, fs fs.FS, res resolver.Resolver, caches *cache.CacheSet, entryPoints []string, options config.Options) Bundle func applyOptionDefaults(options *config.Options) func extractSourceMapFromComment(log logger.Log, fs fs.FS, fsCache *cache.FSCache, res resolver.Resolver, source *logger.Source, comment js_ast.Span, absResolveDir string) (logger.Path, *string)
Find all files reachable from all entry points. This order should be
deterministic given that the entry point order is deterministic, since the
returned order is the postorder of the graph traversal and import record
order within a given file is deterministic.
func guessMimeType(extension string, contents string) string func hashForFileName(hashBytes [20]byte) string func isASCIIOnly(text string) bool func logPluginMessages(res resolver.Resolver, log logger.Log, name string, msgs []logger.Msg, thrown error, importSource *logger.Source, importPathRange logger.Range) bool
Identify the path by its lowercase absolute path name. This should
hopefully avoid path case issues on Windows, which has case-insensitive
file system paths.
"var a = 1; var b = 2;" => "var a = 1, b = 2;"
func newLinkerContext(options *config.Options, log logger.Log, fs fs.FS, res resolver.Resolver, files []file, entryPoints []uint32, reachableFiles []uint32, dataForSourceMaps func() []dataForSourceMap) linkerContext func runOnLoadPlugins(plugins []config.Plugin, res resolver.Resolver, fs fs.FS, fsCache *cache.FSCache, log logger.Log, source *logger.Source, importSource *logger.Source, importPathRange logger.Range, pluginData interface{}, isWatchMode bool) (loaderPluginResult, bool) func runOnResolvePlugins(plugins []config.Plugin, res resolver.Resolver, log logger.Log, fs fs.FS, importSource *logger.Source, importPathRange logger.Range, path string, kind ast.ImportKind, absResolveDir string, pluginData interface{}) (*resolver.ResolveResult, bool) func sanetizeLocation(res resolver.Resolver, loc *logger.MsgLocation)
Package-Level Variables (only one, which is unexported)
Package-Level Constants (total 17, none are exported)
The imported file is CommonJS and has unknown exports
The import was treated as a CommonJS import but the file is known to have no exports
The imported file was disabled by mapping it to false in the "browser"
field of package.json
The imported file is external and has unknown exports
The imported file has a matching export
The imported file has no matching export
This is a missing re-export in a TypeScript file, so it's probably a type
The import resolved to multiple symbols via "export * from"
The import could not be evaluated due to a cycle
The import is either external or undefined
"namespaceRef" and "alias" are in use
"sourceIndex" and "ref" are in use
Both "matchImportNormal" and "matchImportNamespace"
The import is missing but came from a TypeScript file
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |