UNPKG

nuxt-generate-cluster

Version:
2,006 lines (1,687 loc) 50.3 kB
'use strict'; function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } function _interopNamespace(e) { if (e && e.__esModule) { return e; } else { var n = {}; if (e) { Object.keys(e).forEach(function (k) { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); }); } n['default'] = e; return n; } } const cluster = require('cluster'); const cluster__default = _interopDefault(cluster); const env = _interopDefault(require('std-env')); const figures = _interopDefault(require('figures')); const chalk = _interopDefault(require('chalk')); const uuid = _interopDefault(require('uuid')); const consola$2 = _interopDefault(require('consola')); const path = _interopDefault(require('path')); const Commands = { sendErrors: 'handleErrors', sendRoutes: 'requestRoutes', logSuccess: 'logSuccess', logError: 'logError' }; class MessageBroker { constructor ({ isMaster, masterId, alias, autoListen } = {}, masterRef) { this.id = uuid(); this.isMaster = isMaster !== undefined ? isMaster : cluster__default.isMaster; this.masterId = masterId || 'master'; this.masterRef = masterRef; this.alias = alias || (this.isMaster ? this.masterId : undefined); this.listening = false; this.proxies = {}; this.services = {}; // this._messageHandler if (autoListen !== false) { this.listen(); } } registerWithMaster () { this.send(this.masterId, '_register', { alias: this.alias }); } registerProxy ({ alias }, senderId, ref) { consola$2.debug(`registering ${senderId} ` + (alias ? `with alias ${alias}` : 'without alias') + (ref && ref.id ? ` and id ${ref.id}` : '')); this.proxies[senderId] = ref; if (alias) { this.proxies[alias] = ref; } } listen () { if (!this.isMaster) { this.registerWithMaster(); } else { this.on('_register', (...args) => { this.registerProxy(...args); }); } if (!this.listening) { if (this.isMaster) { this._messageHandler = (worker, message) => { /* istanbul ignore next */ this.handleMessage(message, worker); }; cluster__default.on('message', this._messageHandler); } else { this._messageHandler = (message) => { /* istanbul ignore next */ this.handleMessage(message); }; process.on('message', this._messageHandler); } this.listening = true; } } close () { if (this._messageHandler) { if (this.isMaster) { cluster__default.removeListener('message', this._messageHandler); } else { process.removeListener('message', this._messageHandler); } } } handleMessage (message, worker) { consola$2.trace((this.alias || this.id) + ' received message', message instanceof Object ? JSON.stringify(message) : message); const { receiverId } = message; if (receiverId !== undefined) { if ( receiverId === this.id || receiverId === this.alias || (this.isMaster && receiverId === this.masterId) ) { this.callService(message, worker); } else if (this.isMaster && this.proxies[receiverId]) { this.proxies[receiverId].send(message); } else { consola$2.warn(`Proxy ${receiverId} not registered`); } } } callService ({ senderId, serviceId, data }, worker) { if (serviceId in this.services) { this.services[serviceId](data, senderId, worker); } else { consola$2.warn(`Proxy '${this.alias || this.id}': Service ${serviceId} not registered`); } } on (serviceId, callback, overwrite) { if (serviceId in this.services && !overwrite) { consola$2.warn(`Service ${serviceId} already registered`); } else { this.services[serviceId] = callback; } } send (receiverIdOrAlias, serviceId, data) { const message = { receiverId: receiverIdOrAlias || this.masterId, senderId: this.id, serviceId, data }; this.sendMessage(message); } sendMessage (message) { if (!this.isMaster && !cluster__default.isMaster) { consola$2.trace('sending message through process', JSON.stringify(message)); process.send(message); } else if (!this.isMaster && this.masterRef) { return new Promise((resolve) => { consola$2.trace('sending message through promise', JSON.stringify(message)); const ref = {}; if (message.serviceId === '_register') { ref.send = (message) => { this.handleMessage(message); }; } this.masterRef.handleMessage(message, ref); resolve(); }) } else if (this.proxies[message.receiverId]) { consola$2.trace('sending message through proxy', JSON.stringify(message)); this.proxies[message.receiverId].send(message); } else if (message.receiverId === this.id || message.receiverId === this.alias) { this.handleMessage(message); } else { consola$2.error(`Unable to send message, unknown receiver ${message.receiverId}`); } } } const messaging = new MessageBroker(); // Consola Reporter class Reporter { log (logObj, { async } = {}) { if (logObj.type === 'success' && logObj.args[0].startsWith('Generated ')) { // Ignore success messages from Nuxt.Generator::generateRoute return } else if (logObj.type === 'error' && logObj.args[0].startsWith('Error generating ')) { // Ignore error messages from Nuxt.Generator::generateRoute return } if (global._ngc_log_tag) { logObj.tag = global._ngc_log_tag; } messaging.send(null, 'consola', { logObj, stream: { async } }); } } let _consola; if (global.__consolaSet === undefined) { _consola = global.consola; // Delete the global.consola set by consola self delete global.consola; } let consola = global.consola; // eslint-disable-line import/no-mutable-exports if (!consola) { consola = _consola.create({ level: env.debug ? 5 : 3, types: { ..._consola._types, ...{ cluster: { level: 4, color: 'blue', icon: chalk.magenta(figures.radioOn) }, master: { level: 2, color: 'blue', icon: chalk.cyan(figures.info) }, debug: { level: 5, color: 'grey' }, trace: { level: 6, color: 'white' } } } }); _consola = null; if (cluster.isMaster) { /* istanbul ignore next */ messaging.on('consola', ({ logObj, stream }) => { logObj.date = new Date(logObj.date); consola[logObj.type](...logObj.args); }); } else { /* istanbul ignore next */ consola.setReporters(new Reporter()); } global.__consolaSet = true; global.consola = consola; // Delete the loaded consola module from node's cache // so new imports use the above global.consola delete require.cache[require.resolve('consola')]; } const consola$1 = consola; // Copied from Nuxt.Utils const sequence = function sequence (tasks, fn) { return tasks.reduce( (promise, task) => promise.then(() => fn(task)), Promise.resolve() ) }; const Hookable = (Base) => { if (!Base) { Base = class {}; } return class extends Base { initHooks () { if (!this._hooks) { this._hooks = {}; } } hook (name, fn) { if (!name || typeof fn !== 'function') { return } this.initHooks(); this._hooks[name] = this._hooks[name] || []; this._hooks[name].push(fn); } async callHook (name, ...args) { if (!this.hasHooks(name)) { return } // debug(`Call ${name} hooks (${this._hooks[name].length})`) const ret = []; try { ret.push(await sequence(this._hooks[name], fn => fn(...args))); } catch (err) { consola$1.error(`> Error on hook "${name}":`); consola$1.error(err.message); } return ret.length === 1 ? ret[0] : ret } hasHooks (name) { return this._hooks && !!this._hooks[name] } } }; class Watchdog extends Hookable() { constructor () { super(); this.workers = {}; } *iterator () { const workerIds = Object.keys(this.workers); let i = 0; while (i < workerIds.length) { yield this.workers[workerIds[i]]; i++; } } addInfo (workerId, key, extraInfo) { if (arguments.length === 2) { extraInfo = key; key = undefined; } if (this.workers[workerId]) { if (key) { this.workers[workerId][key] = extraInfo; } else { this.workers[workerId] = Object.assign(this.workers[workerId], extraInfo || {}); } } } appendInfo (workerId, key, extraInfo) { if (this.workers[workerId]) { const keyType = typeof this.workers[workerId][key]; if (keyType === 'undefined') { consola$1.error(`Key ${key} is undefined for worker ${workerId}`); } else if (keyType === 'string') { this.workers[workerId][key] += extraInfo; } else if (keyType === 'number') { this.workers[workerId][key] += parseInt(extraInfo); } else if (Array.isArray(this.workers[workerId][key])) { Array.prototype.push.apply(this.workers[workerId][key], extraInfo); } else if (keyType === 'object') { this.workers[workerId][key] = Object.assign(this.workers[workerId][key], extraInfo || {}); } } } addWorker (workerId, extraInfo) { if (typeof this.workers[workerId] !== 'undefined') { consola$1.error(`A worker with workerId ${workerId} is already registered to the watchdog`); } this.workers[workerId] = Object.assign({ id: workerId, start: process.hrtime(), duration: 0, signal: 0, code: 0, routes: 0, errors: 0 }, extraInfo || {}); } exitWorker (workerId, extraInfo) { if (this.workers[workerId]) { const duration = process.hrtime(this.workers[workerId].start); this.workers[workerId].duration = duration[0] * 1E9 + duration[1]; if (extraInfo) { this.addInfo(workerId, extraInfo); } } } async countAlive () { const Iter = this.iterator(); let alive = 0; let worker; while ((worker = Iter.next()) && !worker.done) { if (typeof worker.value !== 'undefined') { const workerAlive = await this.callHook('isWorkerAlive', worker.value); if (workerAlive) { alive++; } } } return alive } allDead () { const Iter = this.iterator(); let worker; while ((worker = Iter.next()) && !worker.done) { if (typeof worker.value !== 'undefined') { // let isDead = await this.callHook('isWorkerDead', worker.value) const isDead = this.workers[worker.value.id].duration > 0; if (!isDead) { return false } } } return true } } var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal; var _freeGlobal = freeGlobal; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = _freeGlobal || freeSelf || Function('return this')(); var _root = root; /** Built-in value references. */ var Symbol = _root.Symbol; var _Symbol = Symbol; /** Used for built-in method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var nativeObjectToString = objectProto.toString; /** Built-in value references. */ var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined; /** * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. * * @private * @param {*} value The value to query. * @returns {string} Returns the raw `toStringTag`. */ function getRawTag(value) { var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag]; try { value[symToStringTag] = undefined; var unmasked = true; } catch (e) {} var result = nativeObjectToString.call(value); if (unmasked) { if (isOwn) { value[symToStringTag] = tag; } else { delete value[symToStringTag]; } } return result; } var _getRawTag = getRawTag; /** Used for built-in method references. */ var objectProto$1 = Object.prototype; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var nativeObjectToString$1 = objectProto$1.toString; /** * Converts `value` to a string using `Object.prototype.toString`. * * @private * @param {*} value The value to convert. * @returns {string} Returns the converted string. */ function objectToString(value) { return nativeObjectToString$1.call(value); } var _objectToString = objectToString; /** `Object#toString` result references. */ var nullTag = '[object Null]', undefinedTag = '[object Undefined]'; /** Built-in value references. */ var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined; /** * The base implementation of `getTag` without fallbacks for buggy environments. * * @private * @param {*} value The value to query. * @returns {string} Returns the `toStringTag`. */ function baseGetTag(value) { if (value == null) { return value === undefined ? undefinedTag : nullTag; } return (symToStringTag$1 && symToStringTag$1 in Object(value)) ? _getRawTag(value) : _objectToString(value); } var _baseGetTag = baseGetTag; /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = typeof value; return value != null && (type == 'object' || type == 'function'); } var isObject_1 = isObject; /** `Object#toString` result references. */ var asyncTag = '[object AsyncFunction]', funcTag = '[object Function]', genTag = '[object GeneratorFunction]', proxyTag = '[object Proxy]'; /** * Checks if `value` is classified as a `Function` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a function, else `false`. * @example * * _.isFunction(_); * // => true * * _.isFunction(/abc/); * // => false */ function isFunction(value) { if (!isObject_1(value)) { return false; } // The use of `Object#toString` avoids issues with the `typeof` operator // in Safari 9 which returns 'object' for typed arrays and other constructors. var tag = _baseGetTag(value); return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; } var isFunction_1 = isFunction; /** Used to detect overreaching core-js shims. */ var coreJsData = _root['__core-js_shared__']; var _coreJsData = coreJsData; /** Used to detect methods masquerading as native. */ var maskSrcKey = (function() { var uid = /[^.]+$/.exec(_coreJsData && _coreJsData.keys && _coreJsData.keys.IE_PROTO || ''); return uid ? ('Symbol(src)_1.' + uid) : ''; }()); /** * Checks if `func` has its source masked. * * @private * @param {Function} func The function to check. * @returns {boolean} Returns `true` if `func` is masked, else `false`. */ function isMasked(func) { return !!maskSrcKey && (maskSrcKey in func); } var _isMasked = isMasked; /** Used for built-in method references. */ var funcProto = Function.prototype; /** Used to resolve the decompiled source of functions. */ var funcToString = funcProto.toString; /** * Converts `func` to its source code. * * @private * @param {Function} func The function to convert. * @returns {string} Returns the source code. */ function toSource(func) { if (func != null) { try { return funcToString.call(func); } catch (e) {} try { return (func + ''); } catch (e) {} } return ''; } var _toSource = toSource; /** * Used to match `RegExp` * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; /** Used to detect host constructors (Safari). */ var reIsHostCtor = /^\[object .+?Constructor\]$/; /** Used for built-in method references. */ var funcProto$1 = Function.prototype, objectProto$2 = Object.prototype; /** Used to resolve the decompiled source of functions. */ var funcToString$1 = funcProto$1.toString; /** Used to check objects for own properties. */ var hasOwnProperty$1 = objectProto$2.hasOwnProperty; /** Used to detect if a method is native. */ var reIsNative = RegExp('^' + funcToString$1.call(hasOwnProperty$1).replace(reRegExpChar, '\\$&') .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); /** * The base implementation of `_.isNative` without bad shim checks. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a native function, * else `false`. */ function baseIsNative(value) { if (!isObject_1(value) || _isMasked(value)) { return false; } var pattern = isFunction_1(value) ? reIsNative : reIsHostCtor; return pattern.test(_toSource(value)); } var _baseIsNative = baseIsNative; /** * Gets the value at `key` of `object`. * * @private * @param {Object} [object] The object to query. * @param {string} key The key of the property to get. * @returns {*} Returns the property value. */ function getValue(object, key) { return object == null ? undefined : object[key]; } var _getValue = getValue; /** * Gets the native function at `key` of `object`. * * @private * @param {Object} object The object to query. * @param {string} key The key of the method to get. * @returns {*} Returns the function if it's native, else `undefined`. */ function getNative(object, key) { var value = _getValue(object, key); return _baseIsNative(value) ? value : undefined; } var _getNative = getNative; /* Built-in method references that are verified to be native. */ var nativeCreate = _getNative(Object, 'create'); var _nativeCreate = nativeCreate; /** * Removes all key-value entries from the hash. * * @private * @name clear * @memberOf Hash */ function hashClear() { this.__data__ = _nativeCreate ? _nativeCreate(null) : {}; this.size = 0; } var _hashClear = hashClear; /** * Removes `key` and its value from the hash. * * @private * @name delete * @memberOf Hash * @param {Object} hash The hash to modify. * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function hashDelete(key) { var result = this.has(key) && delete this.__data__[key]; this.size -= result ? 1 : 0; return result; } var _hashDelete = hashDelete; /** Used to stand-in for `undefined` hash values. */ var HASH_UNDEFINED = '__lodash_hash_undefined__'; /** Used for built-in method references. */ var objectProto$3 = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty$2 = objectProto$3.hasOwnProperty; /** * Gets the hash value for `key`. * * @private * @name get * @memberOf Hash * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function hashGet(key) { var data = this.__data__; if (_nativeCreate) { var result = data[key]; return result === HASH_UNDEFINED ? undefined : result; } return hasOwnProperty$2.call(data, key) ? data[key] : undefined; } var _hashGet = hashGet; /** Used for built-in method references. */ var objectProto$4 = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty$3 = objectProto$4.hasOwnProperty; /** * Checks if a hash value for `key` exists. * * @private * @name has * @memberOf Hash * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function hashHas(key) { var data = this.__data__; return _nativeCreate ? (data[key] !== undefined) : hasOwnProperty$3.call(data, key); } var _hashHas = hashHas; /** Used to stand-in for `undefined` hash values. */ var HASH_UNDEFINED$1 = '__lodash_hash_undefined__'; /** * Sets the hash `key` to `value`. * * @private * @name set * @memberOf Hash * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the hash instance. */ function hashSet(key, value) { var data = this.__data__; this.size += this.has(key) ? 0 : 1; data[key] = (_nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value; return this; } var _hashSet = hashSet; /** * Creates a hash object. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function Hash(entries) { var index = -1, length = entries == null ? 0 : entries.length; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } // Add methods to `Hash`. Hash.prototype.clear = _hashClear; Hash.prototype['delete'] = _hashDelete; Hash.prototype.get = _hashGet; Hash.prototype.has = _hashHas; Hash.prototype.set = _hashSet; var _Hash = Hash; /** * Removes all key-value entries from the list cache. * * @private * @name clear * @memberOf ListCache */ function listCacheClear() { this.__data__ = []; this.size = 0; } var _listCacheClear = listCacheClear; /** * Performs a * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * comparison between two values to determine if they are equivalent. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * * var object = { 'a': 1 }; * var other = { 'a': 1 }; * * _.eq(object, object); * // => true * * _.eq(object, other); * // => false * * _.eq('a', 'a'); * // => true * * _.eq('a', Object('a')); * // => false * * _.eq(NaN, NaN); * // => true */ function eq(value, other) { return value === other || (value !== value && other !== other); } var eq_1 = eq; /** * Gets the index at which the `key` is found in `array` of key-value pairs. * * @private * @param {Array} array The array to inspect. * @param {*} key The key to search for. * @returns {number} Returns the index of the matched value, else `-1`. */ function assocIndexOf(array, key) { var length = array.length; while (length--) { if (eq_1(array[length][0], key)) { return length; } } return -1; } var _assocIndexOf = assocIndexOf; /** Used for built-in method references. */ var arrayProto = Array.prototype; /** Built-in value references. */ var splice = arrayProto.splice; /** * Removes `key` and its value from the list cache. * * @private * @name delete * @memberOf ListCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function listCacheDelete(key) { var data = this.__data__, index = _assocIndexOf(data, key); if (index < 0) { return false; } var lastIndex = data.length - 1; if (index == lastIndex) { data.pop(); } else { splice.call(data, index, 1); } --this.size; return true; } var _listCacheDelete = listCacheDelete; /** * Gets the list cache value for `key`. * * @private * @name get * @memberOf ListCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function listCacheGet(key) { var data = this.__data__, index = _assocIndexOf(data, key); return index < 0 ? undefined : data[index][1]; } var _listCacheGet = listCacheGet; /** * Checks if a list cache value for `key` exists. * * @private * @name has * @memberOf ListCache * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function listCacheHas(key) { return _assocIndexOf(this.__data__, key) > -1; } var _listCacheHas = listCacheHas; /** * Sets the list cache `key` to `value`. * * @private * @name set * @memberOf ListCache * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the list cache instance. */ function listCacheSet(key, value) { var data = this.__data__, index = _assocIndexOf(data, key); if (index < 0) { ++this.size; data.push([key, value]); } else { data[index][1] = value; } return this; } var _listCacheSet = listCacheSet; /** * Creates an list cache object. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function ListCache(entries) { var index = -1, length = entries == null ? 0 : entries.length; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } // Add methods to `ListCache`. ListCache.prototype.clear = _listCacheClear; ListCache.prototype['delete'] = _listCacheDelete; ListCache.prototype.get = _listCacheGet; ListCache.prototype.has = _listCacheHas; ListCache.prototype.set = _listCacheSet; var _ListCache = ListCache; /* Built-in method references that are verified to be native. */ var Map = _getNative(_root, 'Map'); var _Map = Map; /** * Removes all key-value entries from the map. * * @private * @name clear * @memberOf MapCache */ function mapCacheClear() { this.size = 0; this.__data__ = { 'hash': new _Hash, 'map': new (_Map || _ListCache), 'string': new _Hash }; } var _mapCacheClear = mapCacheClear; /** * Checks if `value` is suitable for use as unique object key. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is suitable, else `false`. */ function isKeyable(value) { var type = typeof value; return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') ? (value !== '__proto__') : (value === null); } var _isKeyable = isKeyable; /** * Gets the data for `map`. * * @private * @param {Object} map The map to query. * @param {string} key The reference key. * @returns {*} Returns the map data. */ function getMapData(map, key) { var data = map.__data__; return _isKeyable(key) ? data[typeof key == 'string' ? 'string' : 'hash'] : data.map; } var _getMapData = getMapData; /** * Removes `key` and its value from the map. * * @private * @name delete * @memberOf MapCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function mapCacheDelete(key) { var result = _getMapData(this, key)['delete'](key); this.size -= result ? 1 : 0; return result; } var _mapCacheDelete = mapCacheDelete; /** * Gets the map value for `key`. * * @private * @name get * @memberOf MapCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function mapCacheGet(key) { return _getMapData(this, key).get(key); } var _mapCacheGet = mapCacheGet; /** * Checks if a map value for `key` exists. * * @private * @name has * @memberOf MapCache * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function mapCacheHas(key) { return _getMapData(this, key).has(key); } var _mapCacheHas = mapCacheHas; /** * Sets the map `key` to `value`. * * @private * @name set * @memberOf MapCache * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the map cache instance. */ function mapCacheSet(key, value) { var data = _getMapData(this, key), size = data.size; data.set(key, value); this.size += data.size == size ? 0 : 1; return this; } var _mapCacheSet = mapCacheSet; /** * Creates a map cache object to store key-value pairs. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function MapCache(entries) { var index = -1, length = entries == null ? 0 : entries.length; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } // Add methods to `MapCache`. MapCache.prototype.clear = _mapCacheClear; MapCache.prototype['delete'] = _mapCacheDelete; MapCache.prototype.get = _mapCacheGet; MapCache.prototype.has = _mapCacheHas; MapCache.prototype.set = _mapCacheSet; var _MapCache = MapCache; /** Used to stand-in for `undefined` hash values. */ var HASH_UNDEFINED$2 = '__lodash_hash_undefined__'; /** * Adds `value` to the array cache. * * @private * @name add * @memberOf SetCache * @alias push * @param {*} value The value to cache. * @returns {Object} Returns the cache instance. */ function setCacheAdd(value) { this.__data__.set(value, HASH_UNDEFINED$2); return this; } var _setCacheAdd = setCacheAdd; /** * Checks if `value` is in the array cache. * * @private * @name has * @memberOf SetCache * @param {*} value The value to search for. * @returns {number} Returns `true` if `value` is found, else `false`. */ function setCacheHas(value) { return this.__data__.has(value); } var _setCacheHas = setCacheHas; /** * * Creates an array cache object to store unique values. * * @private * @constructor * @param {Array} [values] The values to cache. */ function SetCache(values) { var index = -1, length = values == null ? 0 : values.length; this.__data__ = new _MapCache; while (++index < length) { this.add(values[index]); } } // Add methods to `SetCache`. SetCache.prototype.add = SetCache.prototype.push = _setCacheAdd; SetCache.prototype.has = _setCacheHas; var _SetCache = SetCache; /** * The base implementation of `_.findIndex` and `_.findLastIndex` without * support for iteratee shorthands. * * @private * @param {Array} array The array to inspect. * @param {Function} predicate The function invoked per iteration. * @param {number} fromIndex The index to search from. * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {number} Returns the index of the matched value, else `-1`. */ function baseFindIndex(array, predicate, fromIndex, fromRight) { var length = array.length, index = fromIndex + (fromRight ? 1 : -1); while ((fromRight ? index-- : ++index < length)) { if (predicate(array[index], index, array)) { return index; } } return -1; } var _baseFindIndex = baseFindIndex; /** * The base implementation of `_.isNaN` without support for number objects. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. */ function baseIsNaN(value) { return value !== value; } var _baseIsNaN = baseIsNaN; /** * A specialized version of `_.indexOf` which performs strict equality * comparisons of values, i.e. `===`. * * @private * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @param {number} fromIndex The index to search from. * @returns {number} Returns the index of the matched value, else `-1`. */ function strictIndexOf(array, value, fromIndex) { var index = fromIndex - 1, length = array.length; while (++index < length) { if (array[index] === value) { return index; } } return -1; } var _strictIndexOf = strictIndexOf; /** * The base implementation of `_.indexOf` without `fromIndex` bounds checks. * * @private * @param {Array} array The array to inspect. * @param {*} value The value to search for. * @param {number} fromIndex The index to search from. * @returns {number} Returns the index of the matched value, else `-1`. */ function baseIndexOf(array, value, fromIndex) { return value === value ? _strictIndexOf(array, value, fromIndex) : _baseFindIndex(array, _baseIsNaN, fromIndex); } var _baseIndexOf = baseIndexOf; /** * A specialized version of `_.includes` for arrays without support for * specifying an index to search from. * * @private * @param {Array} [array] The array to inspect. * @param {*} target The value to search for. * @returns {boolean} Returns `true` if `target` is found, else `false`. */ function arrayIncludes(array, value) { var length = array == null ? 0 : array.length; return !!length && _baseIndexOf(array, value, 0) > -1; } var _arrayIncludes = arrayIncludes; /** * This function is like `arrayIncludes` except that it accepts a comparator. * * @private * @param {Array} [array] The array to inspect. * @param {*} target The value to search for. * @param {Function} comparator The comparator invoked per element. * @returns {boolean} Returns `true` if `target` is found, else `false`. */ function arrayIncludesWith(array, value, comparator) { var index = -1, length = array == null ? 0 : array.length; while (++index < length) { if (comparator(value, array[index])) { return true; } } return false; } var _arrayIncludesWith = arrayIncludesWith; /** * Checks if a `cache` value for `key` exists. * * @private * @param {Object} cache The cache to query. * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function cacheHas(cache, key) { return cache.has(key); } var _cacheHas = cacheHas; /* Built-in method references that are verified to be native. */ var Set = _getNative(_root, 'Set'); var _Set = Set; /** * This method returns `undefined`. * * @static * @memberOf _ * @since 2.3.0 * @category Util * @example * * _.times(2, _.noop); * // => [undefined, undefined] */ function noop() { // No operation performed. } var noop_1 = noop; /** * Converts `set` to an array of its values. * * @private * @param {Object} set The set to convert. * @returns {Array} Returns the values. */ function setToArray(set) { var index = -1, result = Array(set.size); set.forEach(function(value) { result[++index] = value; }); return result; } var _setToArray = setToArray; /** Used as references for various `Number` constants. */ var INFINITY = 1 / 0; /** * Creates a set object of `values`. * * @private * @param {Array} values The values to add to the set. * @returns {Object} Returns the new set. */ var createSet = !(_Set && (1 / _setToArray(new _Set([,-0]))[1]) == INFINITY) ? noop_1 : function(values) { return new _Set(values); }; var _createSet = createSet; /** Used as the size to enable large array optimizations. */ var LARGE_ARRAY_SIZE = 200; /** * The base implementation of `_.uniqBy` without support for iteratee shorthands. * * @private * @param {Array} array The array to inspect. * @param {Function} [iteratee] The iteratee invoked per element. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new duplicate free array. */ function baseUniq(array, iteratee, comparator) { var index = -1, includes = _arrayIncludes, length = array.length, isCommon = true, result = [], seen = result; if (comparator) { isCommon = false; includes = _arrayIncludesWith; } else if (length >= LARGE_ARRAY_SIZE) { var set = iteratee ? null : _createSet(array); if (set) { return _setToArray(set); } isCommon = false; includes = _cacheHas; seen = new _SetCache; } else { seen = iteratee ? [] : result; } outer: while (++index < length) { var value = array[index], computed = iteratee ? iteratee(value) : value; value = (comparator || value !== 0) ? value : 0; if (isCommon && computed === computed) { var seenIndex = seen.length; while (seenIndex--) { if (seen[seenIndex] === computed) { continue outer; } } if (iteratee) { seen.push(computed); } result.push(value); } else if (!includes(seen, computed, comparator)) { if (seen !== result) { seen.push(computed); } result.push(value); } } return result; } var _baseUniq = baseUniq; /** * Creates a duplicate-free version of an array, using * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * for equality comparisons, in which only the first occurrence of each element * is kept. The order of result values is determined by the order they occur * in the array. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array The array to inspect. * @returns {Array} Returns the new duplicate free array. * @example * * _.uniq([2, 1, 2]); * // => [2, 1] */ function uniq(array) { return (array && array.length) ? _baseUniq(array) : []; } var uniq_1 = uniq; const localNodeModules = path.resolve(process.cwd(), 'node_modules'); // Prefer importing modules from local node_modules (for NPX and global bin) async function _import (modulePath) { let m; for (const mp of [path.resolve(localNodeModules, modulePath), modulePath]) { try { m = await new Promise(function (resolve) { resolve(_interopNamespace(require(mp))); }); } catch (e) { /* istanbul ignore next */ if (e.code !== 'MODULE_NOT_FOUND') { throw e } else if (mp === modulePath) { consola$2.fatal( `Module ${modulePath} not found.\n\n`, 'Please install missing dependency:\n\n', `Using npm: npm i ${modulePath}\n\n`, `Using yarn: yarn add ${modulePath}` ); } } } return m } const builder = () => _import('@nuxt/builder'); const webpack = () => _import('@nuxt/webpack'); const generator = () => _import('@nuxt/generator'); const core = () => _import('@nuxt/core'); const getNuxt = async function getNuxt (options) { const { Nuxt } = await core(); const nuxt = new Nuxt(options); await nuxt.ready(); return nuxt }; const getBuilder = async function getBuilder (nuxt) { const { Builder } = await builder(); const { BundleBuilder } = await webpack(); return new Builder(nuxt, BundleBuilder) }; const getGenerator = async function getGenerator (nuxt) { const { Generator } = await generator(); const builder = await getBuilder(nuxt); return new Generator(nuxt, builder) }; class Master extends Hookable() { constructor (options, { workerCount, workerConcurrency, failOnPageError, adjustLogLevel }) { super(); this.options = options; this.watchdog = new Watchdog(); this.startTime = process.hrtime(); this.workerCount = parseInt(workerCount); this.workerConcurrency = parseInt(workerConcurrency); this.failOnPageError = failOnPageError; if (adjustLogLevel) { consola$1.level = consola$1._defaultLevel + adjustLogLevel; this.options.__workerLogLevel = consola$1.level; } this.routes = []; this.errors = []; } async init () { if (this.generator) { return } const level = consola$1.level; const nuxt = await getNuxt(this.options); consola$1.level = level; // ignore whatever Nuxt thinks the level should be this.generator = await getGenerator(nuxt); this.workerCount = this.workerCount || parseInt(nuxt.options.generate.workers) || require('os').cpus().length; this.workerConcurrency = this.workerConcurrency || parseInt(nuxt.options.generate.workerConcurrency) || 500; } async run ({ build, params } = {}) { await this.init(); if (build) { await this.build(); await this.callHook('built', params); } else { await this.initiate(); } await this.getRoutes(params); if (this.routes.length < 1) { consola$1.warn('No routes so not starting workers'); return } let options = this.options; if (typeof this.options.generate.beforeWorkers === 'function') { options = this.options.generate.beforeWorkers(this.options) || this.options; } await this.startWorkers(options); } async initiate (build) { if (!build) { build = false; } await this.generator.initiate({ build, init: build }); } async build () { await this.initiate(true); } async getRoutes (params) { try { const routes = await this.generator.initRoutes(params); if (routes.length) { // add routes to any existing routes Array.prototype.push.apply(this.routes, routes); this.routes = uniq_1(this.routes); } return true } catch (e) { return false } } calculateBatchSize () { // Even the load between workers let workerConcurrency = this.workerConcurrency; if (this.routes.length < this.workerCount * this.workerConcurrency) { workerConcurrency = Math.ceil(this.routes.length / this.workerCount); } return workerConcurrency } getBatchRoutes () { const batchSize = this.calculateBatchSize(); const routes = this.routes.splice(0, batchSize); return routes } async done (workerInfo) { await this.generator.afterGenerate(); let duration = process.hrtime(this.startTime); duration = Math.round((duration[0] * 1E9 + duration[1]) / 1E8) / 10; const info = { duration, errors: this.errors, workerInfo: workerInfo || this.watchdog.workers }; if (this.options.generate && typeof this.options.generate.done === 'function') { await this.options.generate.done(info, this.generator.nuxt); } await this.callHook('done', info); this.errors = []; } startWorkers (options) { consola$1.error('Should be implemented by a derived class'); return false } } class Worker extends Hookable() { constructor (options, { failOnPageError } = {}) { super(); this.options = options; this.id = -1; this.failOnPageError = failOnPageError; if (this.options.__workerLogLevel) { consola$1.level = this.options.__workerLogLevel; } } setId (id) { this.id = id; } async init () { /* istanbul ignore next */ if (this.generator) { return } const level = consola$1.level; const nuxt = await getNuxt(this.options); consola$1.level = level; // ignore whatever Nuxt thinks the level should be this.generator = await getGenerator(nuxt); } async run () { await this.init(); await this.generator.initiate({ build: false, init: false }); } async generateRoutes (routes) { let errors = []; try { errors = await this.generator.generateRoutes(routes); } catch (err) { consola$1.error(`Worker ${process.pid}: Exception while generating routes, exiting`); consola$1.error('' + err); throw err } return errors } } class Master$1 extends Master { constructor (options, { workerCount, workerConcurrency, failOnPageError, setup, adjustLogLevel } = {}) { super(options, { adjustLogLevel, workerCount, failOnPageError, workerConcurrency }); if (setup) { cluster__default.setupMaster(setup); } cluster__default.on('fork', this.onFork.bind(this)); cluster__default.on('exit', this.onExit.bind(this)); global._ngc_log_tag = 'master'; messaging.on(Commands.sendRoutes, (data, senderId, worker) => { this.sendRoutes(senderId, worker); }); messaging.on(Commands.sendErrors, (data, senderId, worker) => { this.saveErrors(senderId, worker, data); }); this.watchdog.hook('isWorkerAlive', (worker) => { return typeof cluster__default.workers[worker.id] !== 'undefined' && cluster__default.workers[worker.id].isConnected() }); } async getRoutes (params) { consola$1.master('retrieving routes'); const success = await super.getRoutes(params); if (success) { consola$1.master(`${this.routes.length} routes will be generated`); } } sendRoutes (senderId, worker) { const routes = this.getBatchRoutes(); if (!routes.length) { consola$1.master(`no more routes, exiting worker ${worker.id}`); worker.disconnect(); } else { consola$1.cluster(`sending ${routes.length} routes to worker ${worker.id}`); this.watchdog.appendInfo(worker.id, 'routes', routes.length); messaging.send(senderId, Commands.sendRoutes, routes); } } saveErrors (senderId, worker, args) { if (typeof args !== 'undefined' && args.length) { Array.prototype.push.apply(this.errors, args); this.watchdog.appendInfo(worker.id, 'errors', args.length); } } async done () { const Iter = this.watchdog.iterator(); let worker; while ((worker = Iter.next()) && !worker.done) { worker = worker.value; let workerMsg = `worker ${worker.id} generated ${worker.routes} routes in ${Math.round(worker.duration / 1E8) / 10}s`; if (worker.errors > 0) { workerMsg += ` with ${worker.errors} error(s)`; } consola$1.cluster(workerMsg); } await super.done(); } async startWorkers (options) { // Dont start more workers then there are routes const maxWorkerCount = Math.min(this.workerCount, this.routes.length); for (let i = await this.watchdog.countAlive(); i < maxWorkerCount; i++) { cluster__default.fork({ args: JSON.stringify({ options, cliOptions: { failOnPageError: this.failOnPageError } }) }); } } onFork (worker) { const pid = worker.process.pid; consola$1.master(`worker ${worker.id} started with pid ${pid}`); this.watchdog.addWorker(worker.id, { pid }); } async onExit (worker, code, signal) { const workerId = worker.id; this.watchdog.exitWorker(workerId, { code, signal }); let message = `worker ${workerId} exited`; let fatal = false; if (code) { message += ` with status code ${code}`; fatal = true; } if (signal) { message += ` by signal ${signal}`; fatal = true; } if (fatal) { consola$1.fatal(message); } else { consola$1.master(message); } const allDead = await this.watchdog.allDead(); if (allDead) { await this.done(); } } } class Worker$1 extends Worker { constructor (options, cliOptions = {}) { super(options, cliOptions); if (cluster__default.isWorker) { this.setId(cluster__default.worker.id); } global._ngc_log_tag = `worker ${this.id}`; messaging.alias = `worker ${this.id}`; messaging.on(Commands.sendRoutes, (data) => { /* istanbul ignore next */ this.generateRoutes(data); }); } static start () { const args = JSON.parse(process.env.args); const worker = new Worker$1(args.options, args.cliOptions); worker.run(); return worker } async init () { await super.init(); let renderingStartTime; /* istanbul ignore next */ if (consola$1.level > 3) { const debug = consola$1.debug; consola$1.debug = (msg) => { if (msg.startsWith('Rendering url')) { renderingStartTime = process.hrtime(); } debug(msg); }; } this.generator.nuxt.hook('generate:routeCreated', ({ route, path, errors }) => { let durationMessage = ''; if (consola$1.level > 3) { const taken = process.hrtime(renderingStartTime); const duration = Math.round((taken[0] * 1e9 + taken[1]) / 1e6); durationMessage += ` (${duration}ms)`; } path = path.replace(this.generator.distPath, ''); if (errors.length) { consola$1.error(`error generating: ${path}` + durationMessage); } else { consola$1.success(`generated: ${path}` + durationMessage); } }); } async run () { await super.run(); messaging.send('master', Commands.sendRoutes); } async generateRoutes (args) { const routes = args; consola$1.cluster(`received ${routes.length} routes`); let errors; try { errors = await super.generateRoutes(routes); } catch (e) { /* istanbul ignore next */ if (cluster__default.isWorker) { process.exit(1); } } if (errors && errors.length) { errors = errors.map((error) => { error.workerId = this.id; /* istanbul ignore next */ if (error.type === 'unhandled') { // convert error stack to a string already, we cant send a stack object to the master process error.error = { stack: '' + error.error.stack }; if (this.failOnPageError) { consola$1.fatal(`Unhandled page error occured for route ${error.route}`); } } retu