index.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = exportApp;
  6. var _chalk = _interopRequireDefault(require("next/dist/compiled/chalk"));
  7. var _findUp = _interopRequireDefault(require("next/dist/compiled/find-up"));
  8. var _fs = require("fs");
  9. var _worker = require("../lib/worker");
  10. var _path = require("path");
  11. var _util = require("util");
  12. var _index = require("../build/output/index");
  13. var Log = _interopRequireWildcard(require("../build/output/log"));
  14. var _spinner = _interopRequireDefault(require("../build/spinner"));
  15. var _constants = require("../lib/constants");
  16. var _recursiveCopy = require("../lib/recursive-copy");
  17. var _recursiveDelete = require("../lib/recursive-delete");
  18. var _constants1 = require("../shared/lib/constants");
  19. var _config = _interopRequireDefault(require("../server/config"));
  20. var _utils = require("../server/utils");
  21. var _events = require("../telemetry/events");
  22. var _ciInfo = require("../telemetry/ci-info");
  23. var _storage = require("../telemetry/storage");
  24. var _normalizePagePath = require("../shared/lib/page-path/normalize-page-path");
  25. var _denormalizePagePath = require("../shared/lib/page-path/denormalize-page-path");
  26. var _env = require("@next/env");
  27. var _require = require("../server/require");
  28. async function exportApp(dir, options, span, configuration) {
  29. const nextExportSpan = span.traceChild("next-export");
  30. return nextExportSpan.traceAsyncFn(async ()=>{
  31. var ref, ref1, ref2, ref3;
  32. dir = (0, _path).resolve(dir);
  33. // attempt to load global env values so they are available in next.config.js
  34. nextExportSpan.traceChild("load-dotenv").traceFn(()=>(0, _env).loadEnvConfig(dir, false, Log));
  35. const nextConfig = configuration || await nextExportSpan.traceChild("load-next-config").traceAsyncFn(()=>(0, _config).default(_constants1.PHASE_EXPORT, dir));
  36. const threads = options.threads || nextConfig.experimental.cpus;
  37. const distDir = (0, _path).join(dir, nextConfig.distDir);
  38. const telemetry = options.buildExport ? null : new _storage.Telemetry({
  39. distDir
  40. });
  41. if (telemetry) {
  42. telemetry.record((0, _events).eventCliSession(distDir, nextConfig, {
  43. webpackVersion: null,
  44. cliCommand: "export",
  45. isSrcDir: null,
  46. hasNowJson: !!await (0, _findUp).default("now.json", {
  47. cwd: dir
  48. }),
  49. isCustomServer: null
  50. }));
  51. }
  52. const subFolders = nextConfig.trailingSlash && !options.buildExport;
  53. const isLikeServerless = nextConfig.target !== "server";
  54. if (!options.silent && !options.buildExport) {
  55. Log.info(`using build directory: ${distDir}`);
  56. }
  57. const buildIdFile = (0, _path).join(distDir, _constants1.BUILD_ID_FILE);
  58. if (!(0, _fs).existsSync(buildIdFile)) {
  59. throw new Error(`Could not find a production build in the '${distDir}' directory. Try building your app with 'next build' before starting the static export. https://nextjs.org/docs/messages/next-export-no-build-id`);
  60. }
  61. const customRoutesDetected = [
  62. "rewrites",
  63. "redirects",
  64. "headers"
  65. ].filter((config)=>typeof nextConfig[config] === "function");
  66. if (!_ciInfo.hasNextSupport && !options.buildExport && customRoutesDetected.length > 0) {
  67. Log.warn(`rewrites, redirects, and headers are not applied when exporting your application, detected (${customRoutesDetected.join(", ")}). See more info here: https://nextjs.org/docs/messages/export-no-custom-routes`);
  68. }
  69. const buildId = (0, _fs).readFileSync(buildIdFile, "utf8");
  70. const pagesManifest = !options.pages && require((0, _path).join(distDir, isLikeServerless ? _constants1.SERVERLESS_DIRECTORY : _constants1.SERVER_DIRECTORY, _constants1.PAGES_MANIFEST));
  71. let prerenderManifest = undefined;
  72. try {
  73. prerenderManifest = require((0, _path).join(distDir, _constants1.PRERENDER_MANIFEST));
  74. } catch (_) {}
  75. const excludedPrerenderRoutes = new Set();
  76. const pages = options.pages || Object.keys(pagesManifest);
  77. const defaultPathMap = {};
  78. let hasApiRoutes = false;
  79. for (const page1 of pages){
  80. // _document and _app are not real pages
  81. // _error is exported as 404.html later on
  82. // API Routes are Node.js functions
  83. if (page1.match(_constants.API_ROUTE)) {
  84. hasApiRoutes = true;
  85. continue;
  86. }
  87. if (page1 === "/_document" || page1 === "/_app" || page1 === "/_error") {
  88. continue;
  89. }
  90. // iSSG pages that are dynamic should not export templated version by
  91. // default. In most cases, this would never work. There is no server that
  92. // could run `getStaticProps`. If users make their page work lazily, they
  93. // can manually add it to the `exportPathMap`.
  94. if (prerenderManifest == null ? void 0 : prerenderManifest.dynamicRoutes[page1]) {
  95. excludedPrerenderRoutes.add(page1);
  96. continue;
  97. }
  98. defaultPathMap[page1] = {
  99. page: page1
  100. };
  101. }
  102. // Initialize the output directory
  103. const outDir = options.outdir;
  104. if (outDir === (0, _path).join(dir, "public")) {
  105. throw new Error(`The 'public' directory is reserved in Next.js and can not be used as the export out directory. https://nextjs.org/docs/messages/can-not-output-to-public`);
  106. }
  107. if (outDir === (0, _path).join(dir, "static")) {
  108. throw new Error(`The 'static' directory is reserved in Next.js and can not be used as the export out directory. https://nextjs.org/docs/messages/can-not-output-to-static`);
  109. }
  110. await (0, _recursiveDelete).recursiveDelete((0, _path).join(outDir));
  111. await _fs.promises.mkdir((0, _path).join(outDir, "_next", buildId), {
  112. recursive: true
  113. });
  114. (0, _fs).writeFileSync((0, _path).join(distDir, _constants1.EXPORT_DETAIL), JSON.stringify({
  115. version: 1,
  116. outDirectory: outDir,
  117. success: false
  118. }), "utf8");
  119. // Copy static directory
  120. if (!options.buildExport && (0, _fs).existsSync((0, _path).join(dir, "static"))) {
  121. if (!options.silent) {
  122. Log.info('Copying "static" directory');
  123. }
  124. await nextExportSpan.traceChild("copy-static-directory").traceAsyncFn(()=>(0, _recursiveCopy).recursiveCopy((0, _path).join(dir, "static"), (0, _path).join(outDir, "static")));
  125. }
  126. // Copy .next/static directory
  127. if (!options.buildExport && (0, _fs).existsSync((0, _path).join(distDir, _constants1.CLIENT_STATIC_FILES_PATH))) {
  128. if (!options.silent) {
  129. Log.info('Copying "static build" directory');
  130. }
  131. await nextExportSpan.traceChild("copy-next-static-directory").traceAsyncFn(()=>(0, _recursiveCopy).recursiveCopy((0, _path).join(distDir, _constants1.CLIENT_STATIC_FILES_PATH), (0, _path).join(outDir, "_next", _constants1.CLIENT_STATIC_FILES_PATH)));
  132. }
  133. // Get the exportPathMap from the config file
  134. if (typeof nextConfig.exportPathMap !== "function") {
  135. if (!options.silent) {
  136. Log.info(`No "exportPathMap" found in "${nextConfig.configFile}". Generating map from "./pages"`);
  137. }
  138. nextConfig.exportPathMap = async (defaultMap)=>{
  139. return defaultMap;
  140. };
  141. }
  142. const { i18n , images: { loader ="default" , unoptimized } , } = nextConfig;
  143. if (i18n && !options.buildExport) {
  144. throw new Error(`i18n support is not compatible with next export. See here for more info on deploying: https://nextjs.org/docs/deployment`);
  145. }
  146. if (!options.buildExport) {
  147. const { isNextImageImported } = await nextExportSpan.traceChild("is-next-image-imported").traceAsyncFn(()=>_fs.promises.readFile((0, _path).join(distDir, _constants1.EXPORT_MARKER), "utf8").then((text)=>JSON.parse(text)).catch(()=>({})));
  148. if (isNextImageImported && loader === "default" && !unoptimized && !_ciInfo.hasNextSupport) {
  149. throw new Error(`Image Optimization using Next.js' default loader is not compatible with \`next export\`.
  150. Possible solutions:
  151. - Use \`next start\` to run a server, which includes the Image Optimization API.
  152. - Configure \`images.unoptimized = true\` in \`next.config.js\` to disable the Image Optimization API.
  153. Read more: https://nextjs.org/docs/messages/export-image-api`);
  154. }
  155. }
  156. // Start the rendering process
  157. const renderOpts = {
  158. dir,
  159. buildId,
  160. nextExport: true,
  161. assetPrefix: nextConfig.assetPrefix.replace(/\/$/, ""),
  162. distDir,
  163. dev: false,
  164. hotReloader: null,
  165. basePath: nextConfig.basePath,
  166. canonicalBase: ((ref = nextConfig.amp) == null ? void 0 : ref.canonicalBase) || "",
  167. ampValidatorPath: ((ref1 = nextConfig.experimental.amp) == null ? void 0 : ref1.validator) || undefined,
  168. ampSkipValidation: ((ref2 = nextConfig.experimental.amp) == null ? void 0 : ref2.skipValidation) || false,
  169. ampOptimizerConfig: ((ref3 = nextConfig.experimental.amp) == null ? void 0 : ref3.optimizer) || undefined,
  170. locales: i18n == null ? void 0 : i18n.locales,
  171. locale: i18n == null ? void 0 : i18n.defaultLocale,
  172. defaultLocale: i18n == null ? void 0 : i18n.defaultLocale,
  173. domainLocales: i18n == null ? void 0 : i18n.domains,
  174. trailingSlash: nextConfig.trailingSlash,
  175. disableOptimizedLoading: nextConfig.experimental.disableOptimizedLoading,
  176. // Exported pages do not currently support dynamic HTML.
  177. supportsDynamicHTML: false,
  178. runtime: nextConfig.experimental.runtime,
  179. crossOrigin: nextConfig.crossOrigin,
  180. optimizeCss: nextConfig.experimental.optimizeCss,
  181. nextScriptWorkers: nextConfig.experimental.nextScriptWorkers,
  182. optimizeFonts: nextConfig.optimizeFonts,
  183. largePageDataBytes: nextConfig.experimental.largePageDataBytes,
  184. serverComponents: nextConfig.experimental.serverComponents
  185. };
  186. const { serverRuntimeConfig , publicRuntimeConfig } = nextConfig;
  187. if (Object.keys(publicRuntimeConfig).length > 0) {
  188. renderOpts.runtimeConfig = publicRuntimeConfig;
  189. }
  190. global.__NEXT_DATA__ = {
  191. nextExport: true
  192. };
  193. if (!options.silent && !options.buildExport) {
  194. Log.info(`Launching ${threads} workers`);
  195. }
  196. const exportPathMap = await nextExportSpan.traceChild("run-export-path-map").traceAsyncFn(async ()=>{
  197. const exportMap = await nextConfig.exportPathMap(defaultPathMap, {
  198. dev: false,
  199. dir,
  200. outDir,
  201. distDir,
  202. buildId
  203. });
  204. return exportMap;
  205. });
  206. if (options.buildExport && nextConfig.experimental.appDir) {
  207. // @ts-expect-error untyped
  208. renderOpts.serverComponentManifest = require((0, _path).join(distDir, _constants1.SERVER_DIRECTORY, `${_constants1.FLIGHT_MANIFEST}.json`));
  209. // @ts-expect-error untyped
  210. renderOpts.serverCSSManifest = require((0, _path).join(distDir, _constants1.SERVER_DIRECTORY, _constants1.FLIGHT_SERVER_CSS_MANIFEST + ".json"));
  211. }
  212. // only add missing 404 page when `buildExport` is false
  213. if (!options.buildExport) {
  214. // only add missing /404 if not specified in `exportPathMap`
  215. if (!exportPathMap["/404"]) {
  216. exportPathMap["/404"] = {
  217. page: "/_error"
  218. };
  219. }
  220. /**
  221. * exports 404.html for backwards compat
  222. * E.g. GitHub Pages, GitLab Pages, Cloudflare Pages, Netlify
  223. */ if (!exportPathMap["/404.html"]) {
  224. // alias /404.html to /404 to be compatible with custom 404 / _error page
  225. exportPathMap["/404.html"] = exportPathMap["/404"];
  226. }
  227. }
  228. // make sure to prevent duplicates
  229. const exportPaths = [
  230. ...new Set(Object.keys(exportPathMap).map((path)=>(0, _denormalizePagePath).denormalizePagePath((0, _normalizePagePath).normalizePagePath(path)))),
  231. ];
  232. const filteredPaths = exportPaths.filter(// Remove API routes
  233. (route)=>!exportPathMap[route].page.match(_constants.API_ROUTE));
  234. if (filteredPaths.length !== exportPaths.length) {
  235. hasApiRoutes = true;
  236. }
  237. if (filteredPaths.length === 0) {
  238. return;
  239. }
  240. if (prerenderManifest && !options.buildExport) {
  241. const fallbackEnabledPages = new Set();
  242. for (const path of Object.keys(exportPathMap)){
  243. const page = exportPathMap[path].page;
  244. const prerenderInfo = prerenderManifest.dynamicRoutes[page];
  245. if (prerenderInfo && prerenderInfo.fallback !== false) {
  246. fallbackEnabledPages.add(page);
  247. }
  248. }
  249. if (fallbackEnabledPages.size) {
  250. throw new Error(`Found pages with \`fallback\` enabled:\n${[
  251. ...fallbackEnabledPages,
  252. ].join("\n")}\n${_constants.SSG_FALLBACK_EXPORT_ERROR}\n`);
  253. }
  254. }
  255. // Warn if the user defines a path for an API page
  256. if (hasApiRoutes) {
  257. if (!options.silent) {
  258. Log.warn(_chalk.default.yellow(`Statically exporting a Next.js application via \`next export\` disables API routes.`) + `\n` + _chalk.default.yellow(`This command is meant for static-only hosts, and is` + " " + _chalk.default.bold(`not necessary to make your application static.`)) + `\n` + _chalk.default.yellow(`Pages in your application without server-side data dependencies will be automatically statically exported by \`next build\`, including pages powered by \`getStaticProps\`.`) + `\n` + _chalk.default.yellow(`Learn more: https://nextjs.org/docs/messages/api-routes-static-export`));
  259. }
  260. }
  261. const progress = !options.silent && createProgress(filteredPaths.length, `${Log.prefixes.info} ${options.statusMessage || "Exporting"}`);
  262. const pagesDataDir = options.buildExport ? outDir : (0, _path).join(outDir, "_next/data", buildId);
  263. const ampValidations = {};
  264. let hadValidationError = false;
  265. const publicDir = (0, _path).join(dir, _constants1.CLIENT_PUBLIC_FILES_PATH);
  266. // Copy public directory
  267. if (!options.buildExport && (0, _fs).existsSync(publicDir)) {
  268. if (!options.silent) {
  269. Log.info('Copying "public" directory');
  270. }
  271. await nextExportSpan.traceChild("copy-public-directory").traceAsyncFn(()=>(0, _recursiveCopy).recursiveCopy(publicDir, outDir, {
  272. filter (path) {
  273. // Exclude paths used by pages
  274. return !exportPathMap[path];
  275. }
  276. }));
  277. }
  278. const timeout = (configuration == null ? void 0 : configuration.staticPageGenerationTimeout) || 0;
  279. let infoPrinted = false;
  280. let exportPage;
  281. let endWorker;
  282. if (options.exportPageWorker) {
  283. exportPage = options.exportPageWorker;
  284. endWorker = options.endWorker || (()=>Promise.resolve());
  285. } else {
  286. const worker = new _worker.Worker(require.resolve("./worker"), {
  287. timeout: timeout * 1000,
  288. onRestart: (_method, [{ path }], attempts)=>{
  289. if (attempts >= 3) {
  290. throw new Error(`Static page generation for ${path} is still timing out after 3 attempts. See more info here https://nextjs.org/docs/messages/static-page-generation-timeout`);
  291. }
  292. Log.warn(`Restarted static page generation for ${path} because it took more than ${timeout} seconds`);
  293. if (!infoPrinted) {
  294. Log.warn("See more info here https://nextjs.org/docs/messages/static-page-generation-timeout");
  295. infoPrinted = true;
  296. }
  297. },
  298. maxRetries: 0,
  299. numWorkers: threads,
  300. enableWorkerThreads: nextConfig.experimental.workerThreads,
  301. exposedMethods: [
  302. "default"
  303. ]
  304. });
  305. exportPage = worker.default.bind(worker);
  306. endWorker = async ()=>{
  307. await worker.end();
  308. };
  309. }
  310. let renderError = false;
  311. const errorPaths = [];
  312. await Promise.all(filteredPaths.map(async (path)=>{
  313. const pageExportSpan = nextExportSpan.traceChild("export-page");
  314. pageExportSpan.setAttribute("path", path);
  315. return pageExportSpan.traceAsyncFn(async ()=>{
  316. const pathMap = exportPathMap[path];
  317. const result = await exportPage({
  318. path,
  319. pathMap,
  320. distDir,
  321. outDir,
  322. pagesDataDir,
  323. renderOpts,
  324. serverRuntimeConfig,
  325. subFolders,
  326. buildExport: options.buildExport,
  327. serverless: (0, _utils).isTargetLikeServerless(nextConfig.target),
  328. optimizeFonts: nextConfig.optimizeFonts,
  329. optimizeCss: nextConfig.experimental.optimizeCss,
  330. disableOptimizedLoading: nextConfig.experimental.disableOptimizedLoading,
  331. parentSpanId: pageExportSpan.id,
  332. httpAgentOptions: nextConfig.httpAgentOptions,
  333. serverComponents: nextConfig.experimental.serverComponents,
  334. appPaths: options.appPaths || []
  335. });
  336. for (const validation of result.ampValidations || []){
  337. const { page , result: ampValidationResult } = validation;
  338. ampValidations[page] = ampValidationResult;
  339. hadValidationError = hadValidationError || Array.isArray(ampValidationResult == null ? void 0 : ampValidationResult.errors) && ampValidationResult.errors.length > 0;
  340. }
  341. renderError = renderError || !!result.error;
  342. if (!!result.error) {
  343. const { page } = pathMap;
  344. errorPaths.push(page !== path ? `${page}: ${path}` : path);
  345. }
  346. if (options.buildExport && configuration) {
  347. if (typeof result.fromBuildExportRevalidate !== "undefined") {
  348. configuration.initialPageRevalidationMap[path] = result.fromBuildExportRevalidate;
  349. }
  350. if (result.ssgNotFound === true) {
  351. configuration.ssgNotFoundPaths.push(path);
  352. }
  353. const durations = configuration.pageDurationMap[pathMap.page] = configuration.pageDurationMap[pathMap.page] || {};
  354. durations[path] = result.duration;
  355. }
  356. if (progress) progress();
  357. });
  358. }));
  359. const endWorkerPromise = endWorker();
  360. // copy prerendered routes to outDir
  361. if (!options.buildExport && prerenderManifest) {
  362. await Promise.all(Object.keys(prerenderManifest.routes).map(async (route)=>{
  363. const { srcRoute } = prerenderManifest.routes[route];
  364. const pageName = srcRoute || route;
  365. // returning notFound: true from getStaticProps will not
  366. // output html/json files during the build
  367. if (prerenderManifest.notFoundRoutes.includes(route)) {
  368. return;
  369. }
  370. route = (0, _normalizePagePath).normalizePagePath(route);
  371. const pagePath = (0, _require).getPagePath(pageName, distDir, isLikeServerless);
  372. const distPagesDir = (0, _path).join(pagePath, // strip leading / and then recurse number of nested dirs
  373. // to place from base folder
  374. pageName.slice(1).split("/").map(()=>"..").join("/"));
  375. const orig = (0, _path).join(distPagesDir, route);
  376. const htmlDest = (0, _path).join(outDir, `${route}${subFolders && route !== "/index" ? `${_path.sep}index` : ""}.html`);
  377. const ampHtmlDest = (0, _path).join(outDir, `${route}.amp${subFolders ? `${_path.sep}index` : ""}.html`);
  378. const jsonDest = (0, _path).join(pagesDataDir, `${route}.json`);
  379. await _fs.promises.mkdir((0, _path).dirname(htmlDest), {
  380. recursive: true
  381. });
  382. await _fs.promises.mkdir((0, _path).dirname(jsonDest), {
  383. recursive: true
  384. });
  385. const htmlSrc = `${orig}.html`;
  386. const jsonSrc = `${orig}.json`;
  387. await _fs.promises.copyFile(htmlSrc, htmlDest);
  388. await _fs.promises.copyFile(jsonSrc, jsonDest);
  389. if (await exists(`${orig}.amp.html`)) {
  390. await _fs.promises.mkdir((0, _path).dirname(ampHtmlDest), {
  391. recursive: true
  392. });
  393. await _fs.promises.copyFile(`${orig}.amp.html`, ampHtmlDest);
  394. }
  395. }));
  396. }
  397. if (Object.keys(ampValidations).length) {
  398. console.log((0, _index).formatAmpMessages(ampValidations));
  399. }
  400. if (hadValidationError) {
  401. throw new Error(`AMP Validation caused the export to fail. https://nextjs.org/docs/messages/amp-export-validation`);
  402. }
  403. if (renderError) {
  404. throw new Error(`Export encountered errors on following paths:\n\t${errorPaths.sort().join("\n ")}`);
  405. }
  406. (0, _fs).writeFileSync((0, _path).join(distDir, _constants1.EXPORT_DETAIL), JSON.stringify({
  407. version: 1,
  408. outDirectory: outDir,
  409. success: true
  410. }), "utf8");
  411. if (telemetry) {
  412. await telemetry.flush();
  413. }
  414. await endWorkerPromise;
  415. });
  416. }
  417. function _interopRequireDefault(obj) {
  418. return obj && obj.__esModule ? obj : {
  419. default: obj
  420. };
  421. }
  422. function _getRequireWildcardCache() {
  423. if (typeof WeakMap !== "function") return null;
  424. var cache = new WeakMap();
  425. _getRequireWildcardCache = function() {
  426. return cache;
  427. };
  428. return cache;
  429. }
  430. function _interopRequireWildcard(obj) {
  431. if (obj && obj.__esModule) {
  432. return obj;
  433. }
  434. if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
  435. return {
  436. default: obj
  437. };
  438. }
  439. var cache = _getRequireWildcardCache();
  440. if (cache && cache.has(obj)) {
  441. return cache.get(obj);
  442. }
  443. var newObj = {};
  444. var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
  445. for(var key in obj){
  446. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  447. var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
  448. if (desc && (desc.get || desc.set)) {
  449. Object.defineProperty(newObj, key, desc);
  450. } else {
  451. newObj[key] = obj[key];
  452. }
  453. }
  454. }
  455. newObj.default = obj;
  456. if (cache) {
  457. cache.set(obj, newObj);
  458. }
  459. return newObj;
  460. }
  461. const exists = (0, _util).promisify(_fs.exists);
  462. function divideSegments(number, segments) {
  463. const result = [];
  464. while(number > 0 && segments > 0){
  465. const dividedNumber = number < segments ? number : Math.floor(number / segments);
  466. number -= dividedNumber;
  467. segments--;
  468. result.push(dividedNumber);
  469. }
  470. return result;
  471. }
  472. const createProgress = (total, label)=>{
  473. const segments = divideSegments(total, 4);
  474. if (total === 0) {
  475. throw new Error("invariant: progress total can not be zero");
  476. }
  477. let currentSegmentTotal = segments.shift();
  478. let currentSegmentCount = 0;
  479. let lastProgressOutput = Date.now();
  480. let curProgress = 0;
  481. let progressSpinner = (0, _spinner).default(`${label} (${curProgress}/${total})`, {
  482. spinner: {
  483. frames: [
  484. "[ ]",
  485. "[= ]",
  486. "[== ]",
  487. "[=== ]",
  488. "[ ===]",
  489. "[ ==]",
  490. "[ =]",
  491. "[ ]",
  492. "[ =]",
  493. "[ ==]",
  494. "[ ===]",
  495. "[====]",
  496. "[=== ]",
  497. "[== ]",
  498. "[= ]",
  499. ],
  500. interval: 500
  501. }
  502. });
  503. return ()=>{
  504. curProgress++;
  505. // Make sure we only log once
  506. // - per fully generated segment, or
  507. // - per minute
  508. // when not showing the spinner
  509. if (!progressSpinner) {
  510. currentSegmentCount++;
  511. if (currentSegmentCount === currentSegmentTotal) {
  512. currentSegmentTotal = segments.shift();
  513. currentSegmentCount = 0;
  514. } else if (lastProgressOutput + 60000 > Date.now()) {
  515. return;
  516. }
  517. lastProgressOutput = Date.now();
  518. }
  519. const newText = `${label} (${curProgress}/${total})`;
  520. if (progressSpinner) {
  521. progressSpinner.text = newText;
  522. } else {
  523. console.log(newText);
  524. }
  525. if (curProgress === total && progressSpinner) {
  526. progressSpinner.stop();
  527. console.log(newText);
  528. }
  529. };
  530. };
  531. //# sourceMappingURL=index.js.map