UNPKG

@parcel/core

Version:
538 lines (535 loc) • 18.6 kB
"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') }); }