Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 278x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x 106x | /**
* @file index.js
* @description The Avenx bundler: resolve, link, shake, emit.
*
* ## The boundary this file sits on
*
* The compiler owns everything Avenx-specific — template compilation,
* declaration processing, expression handling, Atlas, scoped CSS, the shape of
* a generated component class. It hands the bundler *modules*: some virtual
* (the classes it just generated), the rest real files on disk.
*
* The bundler owns everything module-specific — resolution, npm packages, the
* dependency graph, dead-code elimination, format interop, the final script and
* its source map. It knows nothing about components, bridges or pages, and it
* must stay that way: the moment the bundler needs to know what a `.page.js` is,
* the two halves have grown back together.
*
* ## Why Avenx has its own
*
* The same reason it has its own HTML tokenizer, its own expression parser and
* its own reference scanner: the build is dependency-free by policy. A bundler
* is a graph walk, a reachability analysis and a code generator, and each of
* those is a few hundred lines when it only has to serve one compiler.
* @module lib/bundler
*/
import { Resolver, ResolveError, isRuntimeSpecifier, AVENX_PACKAGE_ROOT } from './resolve.js';
import { buildGraph, BindingError, DynamicImportError } from './graph.js';
import { emitBundle, EmitError } from './emit.js';
import { shake } from './treeshake.js';
import { minify } from './minify.js';
import { ModuleParseError } from './parseModule.js';
export {
Resolver,
ResolveError,
BindingError,
DynamicImportError,
EmitError,
ModuleParseError,
isRuntimeSpecifier,
AVENX_PACKAGE_ROOT,
};
/**
* Bundles an application from one or more entry modules.
* @param {object} options - Bundle options.
* @param {string[]} options.entries - Entry specifiers or absolute paths.
* @param {Map<string, string>} [options.virtualModules] - Generated module id to source.
* @param {string} options.rootDir - The project root, for relative paths.
* @param {boolean} [options.treeShake] - Drop modules nothing needs. Default true.
* @param {Map<string, string[]>} [options.entryNeeds] - Export names an entry's
* consumer requires, so a footer that reads the entry namespace keeps it.
* @param {boolean} [options.minify] - Strip comments and indentation. Default false.
* @param {boolean} [options.sourceMap] - Emit a source map. Default false.
* @param {string} [options.banner] - Text before the bundle.
* @param {string} [options.footer] - Text after the bundle.
* @param {string} [options.file] - Output file name, used in the source map.
* @returns {{code: string, map: object|null, stats: object}} The bundle and what it contains.
* @throws {ResolveError|BindingError|EmitError|ModuleParseError} When the application does not link.
*/
export function bundle({
entries,
virtualModules = new Map(),
rootDir,
treeShake = true,
entryNeeds = new Map(),
minify: shouldMinify = false,
sourceMap = false,
banner = '',
footer = '',
file = 'bundle.js',
}) {
const resolver = new Resolver({ virtualModules, roots: [rootDir] });
const resolvedEntries = entries.map((entry) =>
virtualModules.has(entry) ? entry : resolver.resolve(entry, `${rootDir}/__avenx_entry__.js`),
);
const { graph, order } = buildGraph({ entries: resolvedEntries, resolver });
const included = treeShake ? shake({ graph, order, entryNeeds }) : new Set(order);
const emitted = emitBundle({
graph,
order,
included,
banner,
footer,
rootDir,
sourceMap,
file,
});
// Minification preserves line count, so the map stays valid for either form.
const code = shouldMinify ? minify(emitted.code) : emitted.code;
return {
code,
map: emitted.map,
stats: {
modulesInGraph: graph.modules.size,
modulesEmitted: emitted.modules,
modulesShaken: graph.modules.size - emitted.modules,
cycles: graph.cycles.length,
externals: [...graph.modules.values()].filter((module) => module.external && included.has(module.id)).length,
bytes: Buffer.byteLength(code, 'utf-8'),
},
graph,
included,
};
}
|