UNPKG

guess-webpack

Version:

Webpack plugins for the Machine Learning-driven bundler

1,048 lines (988 loc) 41.6 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("path"), require("lodash.template"), require("memory-fs"), require("webpack"), require("webpack-sources"), require("chalk"), require("table"), require("google-oauth2-node"), require("guess-ga"), require("flat-cache"), require("googleapis")); else if(typeof define === 'function' && define.amd) define(["path", "lodash.template", "memory-fs", "webpack", "webpack-sources", "chalk", "table", "google-oauth2-node", "guess-ga", "flat-cache", "googleapis"], factory); else { var a = typeof exports === 'object' ? factory(require("path"), require("lodash.template"), require("memory-fs"), require("webpack"), require("webpack-sources"), require("chalk"), require("table"), require("google-oauth2-node"), require("guess-ga"), require("flat-cache"), require("googleapis")) : factory(root["path"], root["lodash.template"], root["memory-fs"], root["webpack"], root["webpack-sources"], root["chalk"], root["table"], root["google-oauth2-node"], root["guess-ga"], root["flat-cache"], root["googleapis"]); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } })(global, function(__WEBPACK_EXTERNAL_MODULE__0__, __WEBPACK_EXTERNAL_MODULE__4__, __WEBPACK_EXTERNAL_MODULE__5__, __WEBPACK_EXTERNAL_MODULE__6__, __WEBPACK_EXTERNAL_MODULE__11__, __WEBPACK_EXTERNAL_MODULE__13__, __WEBPACK_EXTERNAL_MODULE__14__, __WEBPACK_EXTERNAL_MODULE__16__, __WEBPACK_EXTERNAL_MODULE__17__, __WEBPACK_EXTERNAL_MODULE__18__, __WEBPACK_EXTERNAL_MODULE__19__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 7); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__0__; /***/ }), /* 1 */ /***/ (function(module, exports) { module.exports = require("fs"); /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path_1 = __webpack_require__(0); exports.defaultPrefetchConfig = { '4g': 0.15, '3g': 0.3, '2g': 0.45, 'slow-2g': 0.6 }; var validateInput = function (routes, graph, logger, debug) { var routesInReport = new Set(); Object.keys(graph).forEach(function (r) { routesInReport.add(r); Object.keys(graph[r]).forEach(function (c) { return routesInReport.add(c); }); }); routes .map(function (r) { return r.path; }) .filter(function (x) { return !routesInReport.has(x); }) .forEach(function (r) { if (debug) { logger.debug("The route " + r + " is not present in the report or in the route declarations"); } }); }; exports.buildMap = function (routes, graph, logger, debug) { validateInput(routes, graph, logger, debug); var result = {}; var routeFile = {}; routes.forEach(function (r) { routeFile[r.path] = r.modulePath; }); Object.keys(graph).forEach(function (route) { result[route] = []; var sum = Object.keys(graph[route]).reduce(function (a, n) { return a + graph[route][n]; }, 0); Object.keys(graph[route]).forEach(function (n) { result[route].push({ route: n, probability: graph[route][n] / sum, file: routeFile[n] }); }); result[route] = result[route].sort(function (a, b) { return b.probability - a.probability; }); }); return result; }; exports.stripExtension = function (path) { return path.replace(/\.(j|t)sx?$/, ''); }; var getChunkJsFile = function (chunk) { return chunk.files.filter(function (f) { return f.endsWith('.js'); }).shift(); }; var getChunkDependencyGraph = function (stats) { var chunkGraph = {}; var chunkIdToChunk = {}; stats.chunks.forEach(function (chunk) { return chunkIdToChunk[chunk.id] = chunk; }); var moduleIdToModule = {}; stats.modules.forEach(function (module) { return moduleIdToModule[module.id] = module; }); stats.modules.forEach(function (module) { var moduleChunks = module.chunks.map(function (id) { return chunkIdToChunk[id]; }); module.reasons.forEach(function (reason) { var dependent = moduleIdToModule[reason.moduleId]; if (!dependent) { return; } var dependentChunks = dependent.chunks.map(function (id) { return chunkIdToChunk[id]; }); dependentChunks.forEach(function (dependentChunk) { var file = getChunkJsFile(dependentChunk); if (!file) { return; } chunkGraph[file] = chunkGraph[file] || new Set(); moduleChunks.forEach(function (dependencyChunk) { if (dependencyChunk.initial) { return; } var dependencyFile = getChunkJsFile(dependencyChunk); if (!dependencyFile) { return; } chunkGraph[file].add(dependencyFile); }); }); }); }); return chunkGraph; }; exports.getCompilationMapping = function (compilation, entryPoints, logger) { var mainName = null; var mainPriority = Infinity; function getModulePath(moduleName) { var cwd = process.cwd(); var relativePath = moduleName .split(' ') .filter(function (p) { return /(\.)?(\/|\\)/.test(p); }) .pop(); if (relativePath === undefined) { return null; } var jsPath = exports.stripExtension(relativePath.replace(/\.ngfactory\.js$/, '.js')); return path_1.join(cwd, jsPath); } var jsonStats = compilation.getStats().toJson(); var chunkDepGraph = getChunkDependencyGraph(jsonStats); logger.debug('Chunk dependency graph', chunkDepGraph); var fileChunk = {}; jsonStats .chunks.forEach(function (c) { var jsFile = getChunkJsFile(c); if (!jsFile) { return; } if (c.initial) { var pickers = [ function (f) { return f.startsWith('main') && f.endsWith('.js'); }, function (f) { return f.indexOf('/main') >= 0 && f.endsWith('.js'); }, function (f) { return f.startsWith('runtime') && f.endsWith('.js'); }, function (f) { return f.indexOf('/runtime') >= 0 && f.endsWith('.js'); }, function (f) { return f.startsWith('vendor') && f.endsWith('.js'); }, function (f) { return f.indexOf('/vendor') >= 0 && f.endsWith('.js'); }, function (f) { return f.startsWith('common') && f.endsWith('.js'); }, function (f) { return f.endsWith('.js'); }, ]; var currentMain = null; var currentPriority = 0; while (!currentMain && pickers.length) { currentMain = c.files.filter(pickers.shift()).pop(); currentPriority++; } if (mainPriority > currentPriority) { mainName = currentMain; mainPriority = currentPriority; } } if (c.modules && c.modules.length) { var existingEntries = c.modules.filter(function (m) { var path = getModulePath(m.name); if (!path) { return false; } return entryPoints.has(path); }); if (existingEntries.length > 1) { logger.debug('There are more than two entry points associated with chunk', jsFile); } else if (existingEntries.length === 0) { logger.debug('Cannot find entry point for chunk: ' + jsFile); } else { var path = getModulePath(existingEntries[0].name); if (path) { fileChunk[path] = fileChunk[path] || { file: jsFile, deps: chunkDepGraph[jsFile] }; } } } else { logger.debug('Cannot find modules for chunk', jsFile); } }); return { mainName: mainName, fileChunk: fileChunk }; }; /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spread = (this && this.__spread) || function () { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; }; Object.defineProperty(exports, "__esModule", { value: true }); var LogLevel; (function (LogLevel) { LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG"; LogLevel[LogLevel["INFO"] = 1] = "INFO"; LogLevel[LogLevel["WARN"] = 2] = "WARN"; LogLevel[LogLevel["ERROR"] = 3] = "ERROR"; LogLevel[LogLevel["OFF"] = 4] = "OFF"; })(LogLevel = exports.LogLevel || (exports.LogLevel = {})); var Logger = /** @class */ (function () { function Logger(level) { if (level === void 0) { level = LogLevel.INFO; } this.level = level; } Logger.prototype.setLevel = function (newLevel) { this.level = newLevel; }; Logger.prototype.debug = function () { var msg = []; for (var _i = 0; _i < arguments.length; _i++) { msg[_i] = arguments[_i]; } this.print(LogLevel.DEBUG, 'DEBUG', msg); }; Logger.prototype.info = function () { var msg = []; for (var _i = 0; _i < arguments.length; _i++) { msg[_i] = arguments[_i]; } this.print(LogLevel.INFO, 'INFO', msg); }; Logger.prototype.warn = function () { var msg = []; for (var _i = 0; _i < arguments.length; _i++) { msg[_i] = arguments[_i]; } this.print(LogLevel.WARN, 'WARN', msg); }; Logger.prototype.error = function () { var msg = []; for (var _i = 0; _i < arguments.length; _i++) { msg[_i] = arguments[_i]; } this.print(LogLevel.ERROR, 'ERROR', msg); }; Logger.prototype.print = function (level, label, msg) { if (level >= this.level) { switch (level) { case LogLevel.DEBUG: console.debug.apply(console, __spread([this.prettify(label)], msg)); break; case LogLevel.INFO: console.info.apply(console, __spread([this.prettify(label)], msg)); break; case LogLevel.WARN: console.warn.apply(console, __spread([this.prettify(label)], msg)); break; case LogLevel.ERROR: console.error.apply(console, __spread([this.prettify(label)], msg)); break; default: console.log.apply(console, __spread([this.prettify(label)], msg)); break; } } }; Logger.prototype.prettify = function (label) { return label + "::" + Date.now() + "::"; }; return Logger; }()); exports.Logger = Logger; /***/ }), /* 4 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__4__; /***/ }), /* 5 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__5__; /***/ }), /* 6 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__6__; /***/ }), /* 7 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; function __export(m) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } Object.defineProperty(exports, "__esModule", { value: true }); __export(__webpack_require__(8)); /***/ }), /* 8 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); var prefetch_plugin_1 = __webpack_require__(9); var prefetch_aot_plugin_1 = __webpack_require__(12); var ga_provider_1 = __webpack_require__(15); var asset_observer_1 = __webpack_require__(20); var extractRoutes = function (config) { if (config.routeProvider === false || config.routeProvider === undefined) { return Promise.resolve([]); } if (typeof config.routeProvider === 'function') { return Promise.resolve(config.routeProvider()); } throw new Error('The routeProvider should be either set to false or a function which returns the routes in the app.'); }; var GuessPlugin = /** @class */ (function () { function GuessPlugin(_config) { this._config = _config; if ((this._config.GA || this._config.jwt) && this._config.reportProvider) { throw new Error('Only a single report provider is allowed. You have specified `GA` and/or ' + 'a GA authentication provider (used by Google Analytics provider) and `reportProvider`'); } if (!this._config.GA && !this._config.reportProvider) { throw new Error('Report provider not specified. You should specify either a `GA` (Google Analytics view ID) or `reportProvider`.'); } } GuessPlugin.prototype.apply = function (compiler) { var _this = this; var assetObserver = new asset_observer_1.AssetObserver(); if (!this._config.runtime || !this._config.runtime.delegate) { compiler.hooks.assetEmitted.tapAsync('GuessPlugin', function (file, _, callback) { return assetObserver.addAsset({ name: file, callback: callback }); }); } compiler.hooks.emit.tapAsync({ stage: 0, name: 'GuessPlugin' }, function (compilation, cb) { return _this._execute(compiler, compilation, assetObserver, cb); }); }; GuessPlugin.prototype._execute = function (compiler, compilation, assetObserver, cb) { var _this = this; extractRoutes(this._config).then(function (routes) { return __awaiter(_this, void 0, void 0, function () { var data, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this._getReport(routes)]; case 1: data = _a.sent(); return [2 /*return*/, this._executePrefetchPlugin(data, routes, compiler, compilation, assetObserver, cb)]; case 2: err_1 = _a.sent(); console.error(err_1); cb(); throw err_1; case 3: return [2 /*return*/]; } }); }); }); }; GuessPlugin.prototype._getReport = function (routes) { if (this._config.GA) { return ga_provider_1.getReport({ jwt: this._config.jwt, viewId: this._config.GA, routes: routes, formatter: this._config.routeFormatter, period: this._config.period }); } else { return this._config.reportProvider(); } }; GuessPlugin.prototype._executePrefetchPlugin = function (data, routes, compiler, compilation, assetObserver, cb) { var runtime = this._config.runtime; if (runtime && runtime.delegate) { new prefetch_plugin_1.PrefetchPlugin({ data: data, debug: this._config.debug, basePath: runtime ? runtime.base === undefined ? '' : runtime.base : '', prefetchConfig: runtime ? runtime.prefetchConfig : undefined, routes: routes, delegate: runtime ? !!runtime.delegate : true }).execute(compilation, cb); } else { new prefetch_aot_plugin_1.PrefetchAotPlugin({ data: data, debug: this._config.debug, base: runtime ? runtime.base === undefined ? '' : runtime.base : '', prefetchConfig: runtime ? runtime.prefetchConfig : undefined, routes: routes }).execute(compiler, compilation, assetObserver, cb); } }; return GuessPlugin; }()); exports.GuessPlugin = GuessPlugin; /***/ }), /* 9 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var fs_1 = __webpack_require__(1); var compress_1 = __webpack_require__(10); var path_1 = __webpack_require__(0); var utils_1 = __webpack_require__(2); var logger_1 = __webpack_require__(3); var template = __webpack_require__(4); var ConcatSource = __webpack_require__(11).ConcatSource; var PrefetchPlugin = /** @class */ (function () { function PrefetchPlugin(_config) { this._config = _config; this.logger = new logger_1.Logger(); if (!_config.data) { throw new Error('Page graph not provided'); } } PrefetchPlugin.prototype.execute = function (compilation, callback) { var mainName = null; var fileChunk = {}; try { var res = utils_1.getCompilationMapping(compilation, new Set(this._config.routes.map(function (r) { return utils_1.stripExtension(r.modulePath); })), this.logger); mainName = res.mainName; fileChunk = res.fileChunk; } catch (e) { callback(); console.error(e); } if (mainName === null) { callback(); throw new Error('Cannot find the main chunk of the application'); } var newConfig = {}; var initialGraph = utils_1.buildMap(this._config.routes.map(function (r) { return __assign({}, r, { modulePath: utils_1.stripExtension(r.modulePath), parentModulePath: r.parentModulePath ? utils_1.stripExtension(r.parentModulePath) : null }); }), this._config.data, this.logger, !!this._config.debug); Object.keys(initialGraph).forEach(function (c) { newConfig[c] = []; initialGraph[c].forEach(function (p) { var node = fileChunk[p.file]; var newTransition = { probability: p.probability, route: p.route, // In delegate mode we don't care about chunks // so it's fine if the mapping file/chunk is missing. chunk: (node || { file: '' }).file }; newConfig[c].push(newTransition); }); }); var old = compilation.assets[mainName]; var _a = compress_1.compressGraph(newConfig, 3), graph = _a.graph, graphMap = _a.graphMap; var codeTemplate = 'runtime.tpl'; var runtimeTemplate = fs_1.readFileSync(path_1.join(__dirname, codeTemplate)).toString(); var runtimeLogic = template(runtimeTemplate)({ BASE_PATH: this._config.basePath, GRAPH: JSON.stringify(graph), GRAPH_MAP: JSON.stringify(graphMap), THRESHOLDS: JSON.stringify(Object.assign({}, utils_1.defaultPrefetchConfig, this._config.prefetchConfig)) }); var MemoryFileSystem = __webpack_require__(5); var memoryFs = new MemoryFileSystem(); memoryFs.mkdirpSync('/src'); memoryFs.writeFileSync('/src/index.js', runtimeLogic, 'utf-8'); memoryFs.writeFileSync('/src/guess.js', fs_1.readFileSync(path_1.join(__dirname, 'guess.js')).toString(), 'utf-8'); memoryFs.writeFileSync('/src/runtime.js', fs_1.readFileSync(path_1.join(__dirname, 'runtime.js')).toString(), 'utf-8'); var compiler = __webpack_require__(6)({ context: '/src/', mode: 'production', entry: './index.js', target: 'node', output: { filename: './output.js' } }); compiler.inputFileSystem = memoryFs; compiler.outputFileSystem = memoryFs; compiler.resolvers.normal.fileSystem = memoryFs; compiler.resolvers.context.fileSystem = memoryFs; compiler.run(function (err, stats) { if (err) { callback(); throw err; } compilation.assets[mainName] = new ConcatSource(stats.compilation.assets['./output.js'], '\n', old.source()); callback(); }); }; return PrefetchPlugin; }()); exports.PrefetchPlugin = PrefetchPlugin; /***/ }), /* 10 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.compressGraph = function (input, precision) { var currentChunk = 0; var currentRoute = 0; var chunks = []; var routes = []; var chunkToID = {}; var routeToID = {}; var graphMap = { chunks: chunks, routes: routes }; var graph = []; Object.keys(input).forEach(function (route) { if (routeToID[route] === undefined) { routes[currentRoute] = route; routeToID[route] = currentRoute++; } graph[routeToID[route]] = []; input[route].forEach(function (n) { if (routeToID[n.route] === undefined) { routes[currentRoute] = n.route; routeToID[n.route] = currentRoute++; } if (chunkToID[n.chunk] === undefined) { chunks[currentChunk] = n.chunk; chunkToID[n.chunk] = currentChunk++; } graph[routeToID[route]].push([ parseFloat(n.probability.toFixed(precision)), routeToID[n.route], chunkToID[n.chunk] ]); }); }); return { graph: graph, graphMap: graphMap }; }; /***/ }), /* 11 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__11__; /***/ }), /* 12 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spread = (this && this.__spread) || function () { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; }; Object.defineProperty(exports, "__esModule", { value: true }); var fs_1 = __webpack_require__(1); var path_1 = __webpack_require__(0); var chalk_1 = __webpack_require__(13); var utils_1 = __webpack_require__(2); var logger_1 = __webpack_require__(3); var template = __webpack_require__(4); var table = __webpack_require__(14).table; var alterChunk = function (compiler, chunkName, original, toAlter, toBundle) { var promise = !toBundle ? Promise.resolve(toAlter) : new Promise(function (resolve, reject) { var MemoryFileSystem = __webpack_require__(5); var memoryFs = new MemoryFileSystem(); memoryFs.mkdirpSync('/src'); memoryFs.writeFileSync('/src/index.js', toAlter, 'utf-8'); memoryFs.writeFileSync('/src/guess-aot.js', fs_1.readFileSync(path_1.join(__dirname, 'guess-aot.js')).toString(), 'utf-8'); var inMemoryCompiler = __webpack_require__(6)({ context: '/src/', mode: 'production', entry: './index.js', target: 'node', output: { filename: './output.js' } }); inMemoryCompiler.inputFileSystem = memoryFs; inMemoryCompiler.outputFileSystem = memoryFs; inMemoryCompiler.resolvers.normal.fileSystem = memoryFs; inMemoryCompiler.resolvers.context.fileSystem = memoryFs; inMemoryCompiler.run(function (err, stats) { if (err) { reject(); throw err; } resolve(stats.compilation.assets['./output.js'].source()); }); }); return promise.then(function (output) { return new Promise(function (resolve, reject) { fs_1.writeFile(path_1.join(compiler.outputPath, chunkName), original + '\n' + output, function (err) { if (err) { reject(err); } resolve(); }); }); }); }; var PrefetchAotPlugin = /** @class */ (function () { function PrefetchAotPlugin(_config) { this._config = _config; this.logger = new logger_1.Logger(); if (!_config.data) { throw new Error('Page graph not provided'); } if (this._config.debug) { this.logger.setLevel(logger_1.LogLevel.DEBUG); } } PrefetchAotPlugin.prototype.execute = function (compiler, compilation, assetObserver, callback) { var _this = this; this.logger.debug('Inside PrefetchAotPlugin'); var mainName = null; var fileChunk = {}; try { var res = utils_1.getCompilationMapping(compilation, new Set(this._config.routes.map(function (r) { return utils_1.stripExtension(r.modulePath); })), this.logger); mainName = res.mainName; fileChunk = res.fileChunk; } catch (e) { callback(); this.logger.error(e); return; } this.logger.debug('Mapping between chunk name and entry point', JSON.stringify(fileChunk, null, 2)); if (!mainName) { callback(); throw new Error('Cannot find the main chunk of the application'); } var newConfig = {}; var chunkRoute = {}; var initialGraph = utils_1.buildMap(this._config.routes.map(function (r) { return __assign({}, r, { modulePath: utils_1.stripExtension(r.modulePath), parentModulePath: r.parentModulePath ? utils_1.stripExtension(r.parentModulePath) : null }); }), this._config.data, this.logger, !!this._config.debug); this.logger.debug('Initial mapping between routes and probability', JSON.stringify(initialGraph, null, 2)); Object.keys(initialGraph).forEach(function (route) { newConfig[route] = []; initialGraph[route].forEach(function (neighbor) { var node = fileChunk[neighbor.file]; if (!node) { _this.logger.debug('No chunk for file', neighbor.file); return; } chunkRoute[node.file] = neighbor.route; var newTransition = { probability: neighbor.probability, chunks: __spread(new Set(__spread([node.file], node.deps))) }; newConfig[route].push(newTransition); }); }); this.logger.debug('Built the model', JSON.stringify(newConfig, null, 2)); this.logger.debug('File to chunk mapping', JSON.stringify(fileChunk, null, 2)); this.logger.debug('Chunk to route mapping is', JSON.stringify(chunkRoute, null, 2)); chunkRoute[mainName] = '/'; var tableOutput = [['Prefetcher', 'Target', 'Probability']]; var generateNeighbors = function (route, currentChunk, c) { if (!c.chunks || !c.chunks.length) { _this.logger.debug('Cannot find chunk name for', c, 'from route', route); return false; } tableOutput.push([currentChunk, c.chunks[0], c.probability]); return [ c.probability, "[" + parseFloat(c.probability.toFixed(2)) + "," + c.chunks .map(function (chunk) { return "'" + chunk + "'"; }) .join(',') + "]" ]; }; var chunksLeft = Object.keys(chunkRoute).length; var conf = this._config.prefetchConfig || utils_1.defaultPrefetchConfig; var minProbability = Math.min(conf['2g'], conf['3g'], conf['4g'], conf['slow-2g']); var handleAsset = function (asset) { var chunkName = asset.name; var route = chunkRoute[chunkName]; if (!route) { _this.logger.debug("Cannot find the route \"" + route + "\" for chunk \"" + chunkName + "\""); asset.callback(); return; } var neighbors = (newConfig[route] || []) .map(generateNeighbors.bind(null, route, chunkName)) .filter(Boolean) .sort(function (a, b) { return (a === false || b === false ? 0 : b[0] - a[0]); }) .filter(function (n) { return n === false ? false : n[0] >= minProbability; }) .map(function (n) { return (n === false ? null : n[1]); }); if (newConfig[route]) { _this.logger.debug('Adding', neighbors); } else { _this.logger.debug('Nothing to prefetch from', route); } var newCode = newConfig[route] ? "__GUESS__.p(" + neighbors.join(',') + ")" : ''; var isMainChunk = mainName === chunkName; if (isMainChunk) { _this.logger.debug('Adding prefetching logic in', mainName); var codeTemplate = 'aot.tpl'; var runtimeTemplate = fs_1.readFileSync(path_1.join(__dirname, codeTemplate)).toString(); var prefetchingLogic = template(runtimeTemplate)({ THRESHOLDS: JSON.stringify(Object.assign({}, utils_1.defaultPrefetchConfig, _this._config.prefetchConfig)), BASE_PATH: _this._config.base }); newCode = prefetchingLogic + ';' + newCode; _this.logger.debug('Altering the main chunk'); } alterChunk(compiler, chunkName, fs_1.readFileSync(path_1.join(compiler.outputPath, chunkName)).toString(), newCode, isMainChunk).finally(asset.callback); chunksLeft -= 1; if (!chunksLeft) { _this.logger.info(chalk_1.default.blue('\n\n\n🔮 Guess.js introduced the following prefetching instructions:')); _this.logger.info('\n\n' + table(tableOutput)); } }; assetObserver.onAsset(handleAsset); assetObserver.buffer.forEach(handleAsset); callback(); }; return PrefetchAotPlugin; }()); exports.PrefetchAotPlugin = PrefetchAotPlugin; /***/ }), /* 13 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__13__; /***/ }), /* 14 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__14__; /***/ }), /* 15 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var google_oauth2_node_1 = __webpack_require__(16); var guess_ga_1 = __webpack_require__(17); var clientId = '329457372673-hda3mp2vghisfobn213jpj8ck1uohi2d.apps.googleusercontent.com'; var clientSecret = '4camaoQPOz9edR-Oz19vg-lN'; var scope = 'https://www.googleapis.com/auth/analytics.readonly'; var year = 365 * 24 * 60 * 60 * 1000; var flatCache = __webpack_require__(18); var cache = flatCache.load('guess-plugin'); var id = function (r) { return r; }; var serializePeriod = function (period) { return period.startDate.getTime() + "-" + period.endDate.getTime(); }; exports.getReport = function (c) { var period = c.period || { startDate: new Date(Date.now() - year), endDate: new Date() }; var key = c.viewId + "-" + serializePeriod(period); var report = cache.getKey(key); if (report) { return Promise.resolve(JSON.parse(report)); } var google = __webpack_require__(19).google; var client; if (!c.jwt) { client = google_oauth2_node_1.auth({ clientId: clientId, clientSecret: clientSecret, scope: scope }).then(function (token) { var oauth2Client = new google.auth.OAuth2(); oauth2Client.setCredentials(token); return oauth2Client; }); } else { client = Promise.resolve(new google.auth.JWT(c.jwt.client_email, null, c.jwt.private_key, [scope], null)); } return client .then(function (auth) { return guess_ga_1.fetch({ viewId: c.viewId, auth: auth, period: period, routes: c.routes.map(function (r) { return r.path; }), formatter: c.formatter || id }); }) .then(function (g) { cache.setKey(key, JSON.stringify(g)); cache.save(); return g; }); }; /***/ }), /* 16 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__16__; /***/ }), /* 17 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__17__; /***/ }), /* 18 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__18__; /***/ }), /* 19 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__19__; /***/ }), /* 20 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var AssetObserver = /** @class */ (function () { function AssetObserver() { this.buffer = []; this._callbacks = []; } AssetObserver.prototype.onAsset = function (cb) { this._callbacks.push(cb); }; AssetObserver.prototype.addAsset = function (asset) { this._callbacks.forEach(function (cb) { return cb(asset); }); }; return AssetObserver; }()); exports.AssetObserver = AssetObserver; /***/ }) /******/ ]); });