@parcel/core
Version:
538 lines (535 loc) • 18.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.INTERNAL_TRANSFORM = exports.INTERNAL_RESOLVE = exports.BuildError = void 0;
exports.createWorkerFarm = createWorkerFarm;
exports.default = void 0;
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
function _assert() {
const data = _interopRequireDefault(require("assert"));
_assert = function () {
return data;
};
return data;
}
function _diagnostic() {
const data = _interopRequireWildcard(require("@parcel/diagnostic"));
_diagnostic = function () {
return data;
};
return data;
}
var _Asset = require("./public/Asset");
var _Bundle = require("./public/Bundle");
var _BundleGraph = _interopRequireDefault(require("./public/BundleGraph"));
function _workers() {
const data = _interopRequireDefault(require("@parcel/workers"));
_workers = function () {
return data;
};
return data;
}
function _nullthrows() {
const data = _interopRequireDefault(require("nullthrows"));
_nullthrows = function () {
return data;
};
return data;
}
var _utils = require("./utils");
var _ParcelConfigRequest = require("./requests/ParcelConfigRequest");
var _ReporterRunner = _interopRequireDefault(require("./ReporterRunner"));
var _dumpGraphToGraphViz = _interopRequireDefault(require("./dumpGraphToGraphViz"));
var _resolveOptions = _interopRequireDefault(require("./resolveOptions"));
function _events() {
const data = require("@parcel/events");
_events = function () {
return data;
};
return data;
}
var _registerCoreWithSerializer = require("./registerCoreWithSerializer");
function _utils2() {
const data = require("@parcel/utils");
_utils2 = function () {
return data;
};
return data;
}
var _ParcelConfig = _interopRequireDefault(require("./ParcelConfig"));
function _logger() {
const data = _interopRequireDefault(require("@parcel/logger"));
_logger = function () {
return data;
};
return data;
}
var _RequestTracker = _interopRequireWildcard(require("./RequestTracker"));
var _ValidationRequest = _interopRequireDefault(require("./requests/ValidationRequest"));
var _ParcelBuildRequest = _interopRequireDefault(require("./requests/ParcelBuildRequest"));
var _AssetRequest = _interopRequireDefault(require("./requests/AssetRequest"));
var _PathRequest = _interopRequireDefault(require("./requests/PathRequest"));
var _Environment = require("./Environment");
var _Dependency = require("./Dependency");
function _sourceMap() {
const data = require("@parcel/source-map");
_sourceMap = function () {
return data;
};
return data;
}
function _rust() {
const data = require("@parcel/rust");
_rust = function () {
return data;
};
return data;
}
var _projectPath = require("./projectPath");
function _profiler() {
const data = require("@parcel/profiler");
_profiler = function () {
return data;
};
return data;
}
function _featureFlags() {
const data = require("@parcel/feature-flags");
_featureFlags = function () {
return data;
};
return data;
}
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 }; }
// eslint-disable-next-line no-unused-vars
(0, _registerCoreWithSerializer.registerCoreWithSerializer)();
const INTERNAL_TRANSFORM = exports.INTERNAL_TRANSFORM = Symbol('internal_transform');
const INTERNAL_RESOLVE = exports.INTERNAL_RESOLVE = Symbol('internal_resolve');
class Parcel {
#requestTracker /*: RequestTracker*/;
#config /*: ParcelConfig*/;
#farm /*: WorkerFarm*/;
#initialized /*: boolean*/ = false;
#disposable /*: Disposable */;
#initialOptions /*: InitialParcelOptions */;
#reporterRunner /*: ReporterRunner*/;
#resolvedOptions /*: ?ParcelOptions*/ = null;
#optionsRef /*: SharedReference */;
#watchAbortController /*: AbortController*/;
#watchQueue /*: PromiseQueue<?BuildEvent>*/ = new (_utils2().PromiseQueue)({
maxConcurrent: 1
});
#watchEvents /*: ValueEmitter<
| {|
+error: Error,
+buildEvent?: void,
|}
| {|
+buildEvent: BuildEvent,
+error?: void,
|},
> */;
#watcherSubscription /*: ?AsyncSubscription*/;
#watcherCount /*: number*/ = 0;
#requestedAssetIds /*: Set<string>*/ = new Set();
constructor(options) {
this.#initialOptions = options;
}
async _init() {
if (this.#initialized) {
return;
}
await _sourceMap().init;
await (_rust().init === null || _rust().init === void 0 ? void 0 : (0, _rust().init)());
let resolvedOptions = await (0, _resolveOptions.default)(this.#initialOptions);
this.#resolvedOptions = resolvedOptions;
let {
config
} = await (0, _ParcelConfigRequest.loadParcelConfig)(resolvedOptions);
this.#config = new _ParcelConfig.default(config, resolvedOptions);
(0, _featureFlags().setFeatureFlags)(resolvedOptions.featureFlags);
if (this.#initialOptions.workerFarm) {
if (this.#initialOptions.workerFarm.ending) {
throw new Error('Supplied WorkerFarm is ending');
}
this.#farm = this.#initialOptions.workerFarm;
} else {
this.#farm = createWorkerFarm({
shouldPatchConsole: resolvedOptions.shouldPatchConsole,
shouldTrace: resolvedOptions.shouldTrace
});
}
await resolvedOptions.cache.ensure();
let {
dispose: disposeOptions,
ref: optionsRef
} = await this.#farm.createSharedReference(resolvedOptions, false);
this.#optionsRef = optionsRef;
this.#disposable = new (_events().Disposable)();
if (this.#initialOptions.workerFarm) {
// If we don't own the farm, dispose of only these references when
// Parcel ends.
this.#disposable.add(disposeOptions);
} else {
// Otherwise, when shutting down, end the entire farm we created.
this.#disposable.add(() => this.#farm.end());
}
this.#watchEvents = new (_events().ValueEmitter)();
this.#disposable.add(() => this.#watchEvents.dispose());
this.#reporterRunner = new _ReporterRunner.default({
options: resolvedOptions,
reporters: await this.#config.getReporters(),
workerFarm: this.#farm
});
this.#disposable.add(this.#reporterRunner);
_logger().default.verbose({
origin: '@parcel/core',
message: 'Intializing request tracker...'
});
this.#requestTracker = await _RequestTracker.default.init({
farm: this.#farm,
options: resolvedOptions
});
this.#initialized = true;
}
async run() {
let startTime = Date.now();
if (!this.#initialized) {
await this._init();
}
let result = await this._build({
startTime
});
await this._end();
if (result.type === 'buildFailure') {
throw new BuildError(result.diagnostics);
}
return result;
}
async _end() {
this.#initialized = false;
await this.#requestTracker.writeToCache();
await this.#disposable.dispose();
}
async _startNextBuild() {
this.#watchAbortController = new AbortController();
await this.#farm.callAllWorkers('clearConfigCache', []);
try {
let buildEvent = await this._build({
signal: this.#watchAbortController.signal
});
this.#watchEvents.emit({
buildEvent
});
return buildEvent;
} catch (err) {
// Ignore BuildAbortErrors and only emit critical errors.
if (!(err instanceof _utils.BuildAbortError)) {
throw err;
}
}
}
async watch(cb) {
if (!this.#initialized) {
await this._init();
}
let watchEventsDisposable;
if (cb) {
watchEventsDisposable = this.#watchEvents.addListener(({
error,
buildEvent
}) => cb(error, buildEvent));
}
if (this.#watcherCount === 0) {
this.#watcherSubscription = await this._getWatcherSubscription();
await this.#reporterRunner.report({
type: 'watchStart'
});
// Kick off a first build, but don't await its results. Its results will
// be provided to the callback.
this.#watchQueue.add(() => this._startNextBuild());
this.#watchQueue.run();
}
this.#watcherCount++;
let unsubscribePromise;
const unsubscribe = async () => {
if (watchEventsDisposable) {
watchEventsDisposable.dispose();
}
this.#watcherCount--;
if (this.#watcherCount === 0) {
await (0, _nullthrows().default)(this.#watcherSubscription).unsubscribe();
this.#watcherSubscription = null;
await this.#reporterRunner.report({
type: 'watchEnd'
});
this.#watchAbortController.abort();
await this.#watchQueue.run();
await this._end();
}
};
return {
unsubscribe() {
if (unsubscribePromise == null) {
unsubscribePromise = unsubscribe();
}
return unsubscribePromise;
}
};
}
async _build({
signal,
startTime = Date.now()
} = {
/*::...null*/
}) {
this.#requestTracker.setSignal(signal);
let options = (0, _nullthrows().default)(this.#resolvedOptions);
try {
if (options.shouldProfile) {
await this.startProfiling();
}
if (options.shouldTrace) {
_profiler().tracer.enable();
}
await this.#reporterRunner.report({
type: 'buildStart'
});
this.#requestTracker.graph.invalidateOnBuildNodes();
let request = (0, _ParcelBuildRequest.default)({
optionsRef: this.#optionsRef,
requestedAssetIds: this.#requestedAssetIds,
signal
});
let {
bundleGraph,
bundleInfo,
changedAssets,
assetRequests
} = await this.#requestTracker.runRequest(request, {
force: true
});
this.#requestedAssetIds.clear();
await (0, _dumpGraphToGraphViz.default)(
// $FlowFixMe
this.#requestTracker.graph, 'RequestGraph', _RequestTracker.requestGraphEdgeTypes);
let event = {
type: 'buildSuccess',
changedAssets: new Map(Array.from(changedAssets).map(([id, asset]) => [id, (0, _Asset.assetFromValue)(asset, options)])),
bundleGraph: new _BundleGraph.default(bundleGraph, (bundle, bundleGraph, options) => _Bundle.PackagedBundle.getWithInfo(bundle, bundleGraph, options, bundleInfo.get(bundle.id)), options),
buildTime: Date.now() - startTime,
requestBundle: async bundle => {
let bundleNode = bundleGraph._graph.getNodeByContentKey(bundle.id);
(0, _assert().default)((bundleNode === null || bundleNode === void 0 ? void 0 : bundleNode.type) === 'bundle', 'Bundle does not exist');
if (!bundleNode.value.isPlaceholder) {
// Nothing to do.
return {
type: 'buildSuccess',
changedAssets: new Map(),
bundleGraph: event.bundleGraph,
buildTime: 0,
requestBundle: event.requestBundle,
unstable_requestStats: {}
};
}
for (let assetId of bundleNode.value.entryAssetIds) {
this.#requestedAssetIds.add(assetId);
}
if (this.#watchQueue.getNumWaiting() === 0) {
if (this.#watchAbortController) {
this.#watchAbortController.abort();
}
this.#watchQueue.add(() => this._startNextBuild());
}
let results = await this.#watchQueue.run();
let result = results.filter(Boolean).pop();
if (result.type === 'buildFailure') {
throw new BuildError(result.diagnostics);
}
return result;
},
unstable_requestStats: this.#requestTracker.flushStats()
};
await this.#reporterRunner.report(event);
await this.#requestTracker.runRequest((0, _ValidationRequest.default)({
optionsRef: this.#optionsRef,
assetRequests
}), {
force: assetRequests.length > 0
});
if (this.#reporterRunner.errors.length) {
throw this.#reporterRunner.errors;
}
return event;
} catch (e) {
if (e instanceof _utils.BuildAbortError) {
throw e;
}
let diagnostic = (0, _diagnostic().anyToDiagnostic)(e);
let event = {
type: 'buildFailure',
diagnostics: Array.isArray(diagnostic) ? diagnostic : [diagnostic],
unstable_requestStats: this.#requestTracker.flushStats()
};
await this.#reporterRunner.report(event);
return event;
} finally {
if (this.isProfiling) {
await this.stopProfiling();
}
await this.#farm.callAllWorkers('clearConfigCache', []);
}
}
async _getWatcherSubscription() {
(0, _assert().default)(this.#watcherSubscription == null);
let resolvedOptions = (0, _nullthrows().default)(this.#resolvedOptions);
let opts = (0, _RequestTracker.getWatcherOptions)(resolvedOptions);
let sub = await resolvedOptions.inputFS.watch(resolvedOptions.watchDir, async (err, events) => {
var _events$, _events$2;
if (err) {
_logger().default.verbose({
message: `File watch event error occured`,
meta: {
err
}
});
this.#watchEvents.emit({
error: err
});
return;
}
_logger().default.verbose({
message: `File watch event emitted with ${events.length} events. Sample event: [${(_events$ = events[0]) === null || _events$ === void 0 ? void 0 : _events$.type}] ${(_events$2 = events[0]) === null || _events$2 === void 0 ? void 0 : _events$2.path}`
});
let isInvalid = await this.#requestTracker.respondToFSEvents(events, Number.POSITIVE_INFINITY);
if (isInvalid && this.#watchQueue.getNumWaiting() === 0) {
if (this.#watchAbortController) {
this.#watchAbortController.abort();
}
this.#watchQueue.add(() => this._startNextBuild());
this.#watchQueue.run();
}
}, opts);
return {
unsubscribe: () => sub.unsubscribe()
};
}
// This is mainly for integration tests and it not public api!
_getResolvedParcelOptions() {
return (0, _nullthrows().default)(this.#resolvedOptions, 'Resolved options is null, please let parcel initialize before accessing this.');
}
async startProfiling() {
if (this.isProfiling) {
throw new Error('Parcel is already profiling');
}
_logger().default.info({
origin: '@parcel/core',
message: 'Starting profiling...'
});
this.isProfiling = true;
await this.#farm.startProfile();
}
stopProfiling() {
if (!this.isProfiling) {
throw new Error('Parcel is not profiling');
}
_logger().default.info({
origin: '@parcel/core',
message: 'Stopping profiling...'
});
this.isProfiling = false;
return this.#farm.endProfile();
}
takeHeapSnapshot() {
_logger().default.info({
origin: '@parcel/core',
message: 'Taking heap snapshot...'
});
return this.#farm.takeHeapSnapshot();
}
async unstable_transform(options) {
var _options$env;
if (!this.#initialized) {
await this._init();
}
let projectRoot = (0, _nullthrows().default)(this.#resolvedOptions).projectRoot;
let request = (0, _AssetRequest.default)({
...options,
filePath: (0, _projectPath.toProjectPath)(projectRoot, options.filePath),
optionsRef: this.#optionsRef,
env: (0, _Environment.createEnvironment)({
...options.env,
loc: ((_options$env = options.env) === null || _options$env === void 0 ? void 0 : _options$env.loc) != null ? {
...options.env.loc,
filePath: (0, _projectPath.toProjectPath)(projectRoot, options.env.loc.filePath)
} : undefined
})
});
let res = await this.#requestTracker.runRequest(request, {
force: true
});
return res.map(asset => (0, _Asset.assetFromValue)(asset, (0, _nullthrows().default)(this.#resolvedOptions)));
}
async unstable_resolve(request) {
var _request$env;
if (!this.#initialized) {
await this._init();
}
let projectRoot = (0, _nullthrows().default)(this.#resolvedOptions).projectRoot;
if (request.resolveFrom == null && _path().default.isAbsolute(request.specifier)) {
request.specifier = (0, _projectPath.fromProjectPathRelative)((0, _projectPath.toProjectPath)(projectRoot, request.specifier));
}
let dependency = (0, _Dependency.createDependency)(projectRoot, {
...request,
env: (0, _Environment.createEnvironment)({
...request.env,
loc: ((_request$env = request.env) === null || _request$env === void 0 ? void 0 : _request$env.loc) != null ? {
...request.env.loc,
filePath: (0, _projectPath.toProjectPath)(projectRoot, request.env.loc.filePath)
} : undefined
})
});
let req = (0, _PathRequest.default)({
dependency,
name: request.specifier
});
let res = await this.#requestTracker.runRequest(req, {
force: true
});
if (!res) {
return null;
}
return {
filePath: (0, _projectPath.fromProjectPath)(projectRoot, res.filePath),
code: res.code,
query: res.query,
sideEffects: res.sideEffects
};
}
}
exports.default = Parcel;
class BuildError extends _diagnostic().default {
constructor(diagnostic) {
super({
diagnostic
});
this.name = 'BuildError';
}
}
exports.BuildError = BuildError;
function createWorkerFarm(options = {}) {
return new (_workers().default)({
...options,
// $FlowFixMe
workerPath: process.browser ? '@parcel/core/src/worker.js' : require.resolve('./worker')
});
}