@parcel/core
Version:
416 lines (408 loc) • 16.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createBundleGraphRequest;
function _assert() {
const data = _interopRequireDefault(require("assert"));
_assert = function () {
return data;
};
return data;
}
function _nullthrows() {
const data = _interopRequireDefault(require("nullthrows"));
_nullthrows = function () {
return data;
};
return data;
}
function _logger() {
const data = require("@parcel/logger");
_logger = function () {
return data;
};
return data;
}
function _diagnostic() {
const data = _interopRequireWildcard(require("@parcel/diagnostic"));
_diagnostic = function () {
return data;
};
return data;
}
var _AssetGraph = _interopRequireDefault(require("../AssetGraph"));
var _BundleGraph = _interopRequireDefault(require("../public/BundleGraph"));
var _BundleGraph2 = _interopRequireWildcard(require("../BundleGraph"));
var _MutableBundleGraph = _interopRequireDefault(require("../public/MutableBundleGraph"));
var _Bundle = require("../public/Bundle");
var _ReporterRunner = require("../ReporterRunner");
var _dumpGraphToGraphViz = _interopRequireDefault(require("../dumpGraphToGraphViz"));
function _rust() {
const data = require("@parcel/rust");
_rust = function () {
return data;
};
return data;
}
var _PluginOptions = _interopRequireDefault(require("../public/PluginOptions"));
var _applyRuntimes = _interopRequireDefault(require("../applyRuntimes"));
var _constants = require("../constants");
var _utils = require("../utils");
var _ParcelConfigRequest = _interopRequireWildcard(require("./ParcelConfigRequest"));
var _DevDepRequest = require("./DevDepRequest");
var _InternalConfig = require("../InternalConfig");
var _ConfigRequest = require("./ConfigRequest");
var _projectPath = require("../projectPath");
var _AssetGraphRequest = _interopRequireDefault(require("./AssetGraphRequest"));
function _profiler() {
const data = require("@parcel/profiler");
_profiler = function () {
return data;
};
return data;
}
var _RequestTracker = require("../RequestTracker");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
// TODO: Rename to BundleGraphRequestResult
function createBundleGraphRequest(input) {
return {
type: _RequestTracker.requestTypes.bundle_graph_request,
id: 'BundleGraph',
run: async input => {
let {
options,
api,
invalidateReason
} = input;
let {
optionsRef,
requestedAssetIds,
signal
} = input.input;
let measurement = _profiler().tracer.createMeasurement('building');
let request = (0, _AssetGraphRequest.default)({
name: 'Main',
entries: options.entries,
optionsRef,
shouldBuildLazily: options.shouldBuildLazily,
lazyIncludes: options.lazyIncludes,
lazyExcludes: options.lazyExcludes,
requestedAssetIds
});
let {
assetGraph,
changedAssets,
assetRequests
} = await api.runRequest(request, {
force: options.shouldBuildLazily && requestedAssetIds.size > 0
});
measurement && measurement.end();
(0, _utils.assertSignalNotAborted)(signal);
// If any subrequests are invalid (e.g. dev dep requests or config requests),
// bail on incremental bundling. We also need to invalidate for option changes,
// which are hoisted to direct invalidations on the bundle graph request.
let subRequestsInvalid = Boolean(invalidateReason & _constants.OPTION_CHANGE) || input.api.getSubRequests().some(req => !input.api.canSkipSubrequest(req.id));
if (subRequestsInvalid) {
assetGraph.safeToIncrementallyBundle = false;
}
let configResult = (0, _nullthrows().default)(await input.api.runRequest((0, _ParcelConfigRequest.default)()));
(0, _utils.assertSignalNotAborted)(signal);
let parcelConfig = (0, _ParcelConfigRequest.getCachedParcelConfig)(configResult, input.options);
let {
devDeps,
invalidDevDeps
} = await (0, _DevDepRequest.getDevDepRequests)(input.api);
(0, _DevDepRequest.invalidateDevDeps)(invalidDevDeps, input.options, parcelConfig);
let bundlingMeasurement = _profiler().tracer.createMeasurement('bundling');
let builder = new BundlerRunner(input, parcelConfig, devDeps);
let res = await builder.bundle({
graph: assetGraph,
changedAssets: changedAssets,
assetRequests
});
bundlingMeasurement && bundlingMeasurement.end();
for (let [id, asset] of changedAssets) {
res.changedAssets.set(id, asset);
}
await (0, _dumpGraphToGraphViz.default)(
// $FlowFixMe Added in Flow 0.121.0 upgrade in #4381 (Windows only)
res.bundleGraph._graph, 'BundleGraph', _BundleGraph2.bundleGraphEdgeTypes);
return res;
},
input
};
}
class BundlerRunner {
constructor({
input,
api,
options
}, config, previousDevDeps) {
this.options = options;
this.api = api;
this.optionsRef = input.optionsRef;
this.config = config;
this.previousDevDeps = previousDevDeps;
this.devDepRequests = new Map();
this.configs = new Map();
this.pluginOptions = new _PluginOptions.default((0, _utils.optionsProxy)(this.options, api.invalidateOnOptionChange));
this.cacheKey = (0, _rust().hashString)(`${_constants.PARCEL_VERSION}:BundleGraph:${JSON.stringify(options.entries) ?? ''}${options.mode}${options.shouldBuildLazily ? 'lazy' : 'eager'}`) + '-BundleGraph';
}
async loadConfigs() {
// Load all configs up front so we can use them in the cache key
let bundler = await this.config.getBundler();
await this.loadConfig(bundler);
let namers = await this.config.getNamers();
for (let namer of namers) {
await this.loadConfig(namer);
}
let runtimes = await this.config.getRuntimes();
for (let runtime of runtimes) {
await this.loadConfig(runtime);
}
}
async loadConfig(plugin) {
let config = (0, _InternalConfig.createConfig)({
plugin: plugin.name,
searchPath: (0, _projectPath.toProjectPathUnsafe)('index')
});
await (0, _ConfigRequest.loadPluginConfig)(plugin, config, this.options);
await (0, _ConfigRequest.runConfigRequest)(this.api, config);
for (let devDep of config.devDeps) {
let devDepRequest = await (0, _DevDepRequest.createDevDependency)(devDep, this.previousDevDeps, this.options);
await this.runDevDepRequest(devDepRequest);
}
this.configs.set(plugin.name, config);
}
async runDevDepRequest(devDepRequest) {
let {
specifier,
resolveFrom
} = devDepRequest;
let key = `${specifier}:${(0, _projectPath.fromProjectPathRelative)(resolveFrom)}`;
this.devDepRequests.set(key, devDepRequest);
await (0, _DevDepRequest.runDevDepRequest)(this.api, devDepRequest);
}
async bundle({
graph,
changedAssets,
assetRequests
}) {
(0, _ReporterRunner.report)({
type: 'buildProgress',
phase: 'bundling'
});
await this.loadConfigs();
let plugin = await this.config.getBundler();
let {
plugin: bundler,
name,
resolveFrom
} = plugin;
// if a previous asset graph hash is passed in, check if the bundle graph is also available
let previousBundleGraphResult;
if (graph.safeToIncrementallyBundle) {
try {
previousBundleGraphResult = await this.api.getPreviousResult();
} catch {
// if the bundle graph had an error or was removed, don't fail the build
}
}
if (previousBundleGraphResult == null) {
graph.safeToIncrementallyBundle = false;
}
let internalBundleGraph;
let logger = new (_logger().PluginLogger)({
origin: name
});
let tracer = new (_profiler().PluginTracer)({
origin: name,
category: 'bundle'
});
try {
if (previousBundleGraphResult) {
internalBundleGraph = previousBundleGraphResult.bundleGraph;
for (let changedAssetId of changedAssets.keys()) {
// Copy over the whole node to also have correct symbol data
let changedAssetNode = (0, _nullthrows().default)(graph.getNodeByContentKey(changedAssetId));
(0, _assert().default)(changedAssetNode.type === 'asset');
internalBundleGraph.updateAsset(changedAssetNode);
}
} else {
var _this$configs$get;
internalBundleGraph = _BundleGraph2.default.fromAssetGraph(graph, this.options.mode === 'production');
(0, _assert().default)(internalBundleGraph != null); // ensures the graph was created
await (0, _dumpGraphToGraphViz.default)(
// $FlowFixMe
internalBundleGraph._graph, 'before_bundle', _BundleGraph2.bundleGraphEdgeTypes);
let mutableBundleGraph = new _MutableBundleGraph.default(internalBundleGraph, this.options);
let measurement;
let measurementFilename;
if (tracer.enabled) {
measurementFilename = graph.getEntryAssets().map(asset => (0, _projectPath.fromProjectPathRelative)(asset.filePath)).join(', ');
measurement = tracer.createMeasurement(plugin.name, 'bundling:bundle', measurementFilename);
}
// this the normal bundle workflow (bundle, optimizing, run-times, naming)
await bundler.bundle({
bundleGraph: mutableBundleGraph,
config: (_this$configs$get = this.configs.get(plugin.name)) === null || _this$configs$get === void 0 ? void 0 : _this$configs$get.result,
options: this.pluginOptions,
logger,
tracer
});
measurement && measurement.end();
if (this.pluginOptions.mode === 'production') {
let optimizeMeasurement;
try {
var _this$configs$get2;
if (tracer.enabled) {
optimizeMeasurement = tracer.createMeasurement(plugin.name, 'bundling:optimize', (0, _nullthrows().default)(measurementFilename));
}
await bundler.optimize({
bundleGraph: mutableBundleGraph,
config: (_this$configs$get2 = this.configs.get(plugin.name)) === null || _this$configs$get2 === void 0 ? void 0 : _this$configs$get2.result,
options: this.pluginOptions,
logger
});
} catch (e) {
throw new (_diagnostic().default)({
diagnostic: (0, _diagnostic().errorToDiagnostic)(e, {
origin: plugin.name
})
});
} finally {
optimizeMeasurement && optimizeMeasurement.end();
await (0, _dumpGraphToGraphViz.default)(
// $FlowFixMe[incompatible-call]
internalBundleGraph._graph, 'after_optimize');
}
}
// Add dev dependency for the bundler. This must be done AFTER running it due to
// the potential for lazy require() that aren't executed until the request runs.
let devDepRequest = await (0, _DevDepRequest.createDevDependency)({
specifier: name,
resolveFrom
}, this.previousDevDeps, this.options);
await this.runDevDepRequest(devDepRequest);
}
} catch (e) {
if (internalBundleGraph != null) {
this.api.storeResult({
bundleGraph: internalBundleGraph,
changedAssets: new Map(),
assetRequests: []
}, this.cacheKey);
}
throw new (_diagnostic().default)({
diagnostic: (0, _diagnostic().errorToDiagnostic)(e, {
origin: name
})
});
} finally {
(0, _assert().default)(internalBundleGraph != null); // ensures the graph was created
await (0, _dumpGraphToGraphViz.default)(
// $FlowFixMe[incompatible-call]
internalBundleGraph._graph, 'after_bundle', _BundleGraph2.bundleGraphEdgeTypes);
}
let changedRuntimes = new Map();
if (!previousBundleGraphResult) {
let namers = await this.config.getNamers();
// inline bundles must still be named so the PackagerRunner
// can match them to the correct packager/optimizer plugins.
let bundles = internalBundleGraph.getBundles({
includeInline: true
});
await Promise.all(bundles.map(bundle => this.nameBundle(namers, bundle, internalBundleGraph)));
changedRuntimes = await (0, _applyRuntimes.default)({
bundleGraph: internalBundleGraph,
api: this.api,
config: this.config,
options: this.options,
optionsRef: this.optionsRef,
pluginOptions: this.pluginOptions,
previousDevDeps: this.previousDevDeps,
devDepRequests: this.devDepRequests,
configs: this.configs
});
// Add dev deps for namers, AFTER running them to account for lazy require().
for (let namer of namers) {
let devDepRequest = await (0, _DevDepRequest.createDevDependency)({
specifier: namer.name,
resolveFrom: namer.resolveFrom
}, this.previousDevDeps, this.options);
await this.runDevDepRequest(devDepRequest);
}
this.validateBundles(internalBundleGraph);
// Pre-compute the hashes for each bundle so they are only computed once and shared between workers.
internalBundleGraph.getBundleGraphHash();
}
await (0, _dumpGraphToGraphViz.default)(
// $FlowFixMe
internalBundleGraph._graph, 'after_runtimes', _BundleGraph2.bundleGraphEdgeTypes);
this.api.storeResult({
bundleGraph: internalBundleGraph,
changedAssets: new Map(),
assetRequests: []
}, this.cacheKey);
return {
bundleGraph: internalBundleGraph,
changedAssets: changedRuntimes,
assetRequests
};
}
validateBundles(bundleGraph) {
let bundles = bundleGraph.getBundles();
let bundleNames = bundles.map(b => (0, _projectPath.joinProjectPath)(b.target.distDir, (0, _nullthrows().default)(b.name)));
let seenNames = new Set();
let duplicateNames = bundleNames.filter(name => {
let isDuplicate = seenNames.has(name);
seenNames.add(name);
return isDuplicate;
});
(0, _assert().default)(duplicateNames.length === 0, 'Bundles must have unique names. Conflicting names: ' + duplicateNames.join(', '));
}
async nameBundle(namers, internalBundle, internalBundleGraph) {
let bundle = _Bundle.Bundle.get(internalBundle, internalBundleGraph, this.options);
let bundleGraph = new _BundleGraph.default(internalBundleGraph, _Bundle.NamedBundle.get.bind(_Bundle.NamedBundle), this.options);
for (let namer of namers) {
let measurement;
try {
var _this$configs$get3;
measurement = _profiler().tracer.createMeasurement(namer.name, 'namer', bundle.id);
let name = await namer.plugin.name({
bundle,
bundleGraph,
config: (_this$configs$get3 = this.configs.get(namer.name)) === null || _this$configs$get3 === void 0 ? void 0 : _this$configs$get3.result,
options: this.pluginOptions,
logger: new (_logger().PluginLogger)({
origin: namer.name
}),
tracer: new (_profiler().PluginTracer)({
origin: namer.name,
category: 'namer'
})
});
if (name != null) {
internalBundle.name = name;
let {
hashReference
} = internalBundle;
internalBundle.displayName = name.includes(hashReference) ? name.replace(hashReference, '[hash]') : name;
return;
}
} catch (e) {
throw new (_diagnostic().default)({
diagnostic: (0, _diagnostic().errorToDiagnostic)(e, {
origin: namer.name
})
});
} finally {
measurement && measurement.end();
}
}
throw new Error('Unable to name bundle');
}
}