UNPKG

@docusaurus/core

Version:

Easy to Maintain Open Source Documentation Websites

176 lines (156 loc) 5.55 kB
/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ // @ts-check import fs from 'fs-extra'; import path from 'path'; import {createRequire} from 'module'; import execa from 'execa'; import {logger} from '@docusaurus/logger'; import semver from 'semver'; import updateNotifier from 'update-notifier'; import boxen from 'boxen'; import {DOCUSAURUS_VERSION} from '@docusaurus/utils'; const packageJson = /** @type {import("../package.json")} */ ( createRequire(import.meta.url)('../package.json') ); /** @type {Record<string, any>} */ let sitePkg; try { sitePkg = createRequire(path.resolve('package.json'))('./package.json'); } catch { logger.warn`path=${'package.json'} file not found at CWD: path=${process.cwd()}.`; logger.info`This is non-critical, but could lead to undesired behavior downstream. Docusaurus assumes that path=${'package.json'} exists at CWD, because it's where the package manager looks up the script at. A common reason is because you have changed directory in the script. Instead of writing code=${'"start": "cd website && docusaurus start"'}, consider using the code=${'[siteDir]'} argument: code=${'"start": "docusaurus start website"'}.`; sitePkg = {}; } const { name, engines: {node: requiredVersion}, } = packageJson; /** * Notify user if `@docusaurus` packages are outdated * * Note: this is a 2-step process to avoid delaying cli usage by awaiting a * response: * - 1st run: trigger background job to check releases + store result * - 2nd run: display potential update to users * * cache data is stored in `~/.config/configstore/update-notifier-@docusaurus` */ export default async function beforeCli() { const notifier = updateNotifier({ pkg: { name, version: DOCUSAURUS_VERSION, }, // Check is in background so it's fine to use a small value like 1h // Use 0 for debugging updateCheckInterval: 1000 * 60 * 60, }); // Hacky way to ensure we check for updates on first run // Note: the notification will only happen in the 2nd run // See https://github.com/yeoman/update-notifier/issues/209 try { if ( notifier.config && // @ts-expect-error: this is an internal API !notifier.disabled && Date.now() - notifier.config.get('lastUpdateCheck') < 50 ) { notifier.config.set('lastUpdateCheck', 0); notifier.check(); } } catch (err) { // Do not stop cli if this fails, see https://github.com/facebook/docusaurus/issues/5400 logger.error(err); } /** * We don't want to display update message for canary releases. * See https://github.com/facebook/docusaurus/issues/5378 * @param {import('update-notifier').UpdateInfo} update */ function ignoreUpdate(update) { const isCanaryRelease = update?.current?.startsWith('0.0.0'); return isCanaryRelease; } if ( notifier.config && notifier.update && semver.lt(notifier.update.current, notifier.update.latest) ) { // Because notifier clears cached data after reading it, leading to notifier // not consistently displaying the update. // See https://github.com/yeoman/update-notifier/issues/209 notifier.config.set('update', notifier.update); if (ignoreUpdate(notifier.update)) { return; } const siteDocusaurusPackagesForUpdate = Object.keys({ ...sitePkg.dependencies, ...sitePkg.devDependencies, }) .filter((p) => p.startsWith('@docusaurus')) .map((p) => p.concat('@latest')) .join(' '); const getYarnVersion = async () => { if (!(await fs.pathExists(path.resolve('yarn.lock')))) { return undefined; } const yarnVersionResult = await execa.command('yarn --version'); if (yarnVersionResult.exitCode === 0) { const majorVersion = parseInt( yarnVersionResult.stdout?.trim().split('.')[0] ?? '', 10, ); if (!Number.isNaN(majorVersion)) { return majorVersion; } } return undefined; }; const getUpgradeCommand = async () => { const yarnVersion = await getYarnVersion(); if (!yarnVersion) { return `npm i ${siteDocusaurusPackagesForUpdate}`; } return yarnVersion >= 2 ? `yarn up ${siteDocusaurusPackagesForUpdate}` : `yarn upgrade ${siteDocusaurusPackagesForUpdate}`; }; /** @type {import('boxen').Options} */ const boxenOptions = { padding: 1, margin: 1, align: 'center', borderColor: 'yellow', borderStyle: { topLeft: ' ', topRight: ' ', bottomLeft: ' ', bottomRight: ' ', top: '-', bottom: '-', left: ' ', right: ' ', }, }; const docusaurusUpdateMessage = boxen( `Update available ${logger.dim( `${notifier.update.current}`, )}${logger.green(`${notifier.update.latest}`)} To upgrade Docusaurus packages with the latest version, run the following command: ${logger.code(await getUpgradeCommand())}`, boxenOptions, ); console.log(docusaurusUpdateMessage); } // Notify user if node version needs to be updated if (!semver.satisfies(process.version, requiredVersion)) { logger.error('Minimum Node.js version not met :('); logger.info`You are using Node.js number=${process.version}, Requirement: Node.js number=${requiredVersion}.`; process.exit(1); } }