From 26d223dbeb73a772740e49a170d6cd04bb324cac Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Wed, 23 Feb 2022 18:22:40 +0300 Subject: [PATCH] feat(create): better detection of package manager preference (#6679) Co-authored-by: sebastienlorber --- packages/create-docusaurus/src/index.ts | 80 +++++++++++++++++++------ website/docs/installation.md | 39 +++++++++++- 2 files changed, 101 insertions(+), 18 deletions(-) diff --git a/packages/create-docusaurus/src/index.ts b/packages/create-docusaurus/src/index.ts index 6a7398a2a6..9f2f37965a 100755 --- a/packages/create-docusaurus/src/index.ts +++ b/packages/create-docusaurus/src/index.ts @@ -17,12 +17,56 @@ import {fileURLToPath} from 'url'; const RecommendedTemplate = 'classic'; const TypeScriptTemplateSuffix = '-typescript'; -function hasYarn() { - try { - return shell.exec('yarnpkg --version', {silent: true}).code === 0; - } catch (e) { - return false; +const DefaultPackageManager = 'npm'; + +const SupportedPackageManagers = { + npm: 'package-lock.json', + yarn: 'yarn.lock', + pnpm: 'pnpm-lock.yaml', +}; + +type SupportedPackageManager = keyof typeof SupportedPackageManagers; + +const PackageManagersList = Object.keys( + SupportedPackageManagers, +) as SupportedPackageManager[]; + +async function findPackageManagerFromLockFile(): Promise< + SupportedPackageManager | undefined +> { + for (const packageManager of PackageManagersList) { + const lockFilePath = path.resolve( + process.cwd(), + SupportedPackageManagers[packageManager], + ); + if (await fs.pathExists(lockFilePath)) { + return packageManager; + } } + return undefined; +} + +function findPackageManagerFromUserAgent(): + | SupportedPackageManager + | undefined { + return PackageManagersList.find((packageManager) => + process.env.npm_config_user_agent?.startsWith(packageManager), + ); +} + +async function getPackageManager( + forceUseNpm?: boolean, +): Promise { + // TODO replace --use-npm by --package-manager option + if (forceUseNpm) { + return 'npm'; + } + + return ( + (await findPackageManagerFromLockFile()) ?? + findPackageManagerFromUserAgent() ?? + DefaultPackageManager + ); } function isValidGitRepoUrl(gitRepoUrl: string) { @@ -131,14 +175,13 @@ export default async function init( gitStrategy: typeof gitStrategies[number]; }> = {}, ): Promise { - const useYarn = cliOptions.useNpm ? false : hasYarn(); + const pkgManager = await getPackageManager(cliOptions.useNpm); const templatesDir = fileURLToPath(new URL('../templates', import.meta.url)); const templates = await readTemplates(templatesDir); const hasTS = (templateName: string) => fs.pathExists( path.resolve(templatesDir, `${templateName}${TypeScriptTemplateSuffix}`), ); - let name = siteName; // Prompt if siteName is not passed from CLI. @@ -313,21 +356,23 @@ export default async function init( await fs.remove(path.join(dest, 'gitignore')); } - const pkgManager = useYarn ? 'yarn' : 'npm'; // Display the most elegant way to cd. const cdpath = path.relative('.', dest); if (!cliOptions.skipInstall) { shell.cd(dest); logger.info`Installing dependencies with name=${pkgManager}...`; if ( - shell.exec(useYarn ? 'yarn' : 'npm install --color always', { - env: { - ...process.env, - // Force coloring the output, since the command is invoked by shelljs, - // which is not the interactive shell - ...(supportsColor.stdout ? {FORCE_COLOR: '1'} : {}), + shell.exec( + pkgManager === 'yarn' ? 'yarn' : `${pkgManager} install --color always`, + { + env: { + ...process.env, + // Force coloring the output, since the command is invoked, + // by shelljs which is not the interactive shell + ...(supportsColor.stdout ? {FORCE_COLOR: '1'} : {}), + }, }, - }).code !== 0 + ).code !== 0 ) { logger.error('Dependency installation failed.'); logger.info`The site directory has already been created, and you can retry by typing: @@ -338,16 +383,17 @@ export default async function init( } } + const useNpm = pkgManager === 'npm'; logger.success`Created path=${cdpath}.`; logger.info`Inside that directory, you can run several commands: code=${`${pkgManager} start`} Starts the development server. - code=${`${pkgManager} ${useYarn ? '' : 'run '}build`} + code=${`${pkgManager} ${useNpm ? 'run ' : ''}build`} Bundles your website into static files for production. - code=${`${pkgManager} ${useYarn ? '' : 'run '}serve`} + code=${`${pkgManager} ${useNpm ? 'run ' : ''}serve`} Serves the built website locally. code=${`${pkgManager} deploy`} diff --git a/website/docs/installation.md b/website/docs/installation.md index 4bd97f1427..ba81f9cc4f 100644 --- a/website/docs/installation.md +++ b/website/docs/installation.md @@ -3,6 +3,11 @@ id: installation title: Installation --- +```mdx-code-block +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +``` + Docusaurus is essentially a set of npm [packages](https://github.com/facebook/docusaurus/tree/main/packages). :::tip @@ -17,7 +22,6 @@ Use **[docusaurus.new](https://docusaurus.new)** to test Docusaurus immediately - [Node.js](https://nodejs.org/en/download/) version >= 14 or above (which can be checked by running `node -v`). You can use [nvm](https://github.com/nvm-sh/nvm) for managing multiple Node versions on a single machine installed. - When installing Node.js, you are recommended to check all checkboxes related to dependencies. -- [Yarn](https://yarnpkg.com/en/) version >= 1.5 (which can be checked by running `yarn --version`). Yarn is a performant package manager for JavaScript and replaces the `npm` client. It is not strictly necessary but highly encouraged. ## Scaffold project website {#scaffold-project-website} @@ -59,6 +63,39 @@ You can also use the template's TypeScript variant by passing the `--typescript` npx create-docusaurus@latest my-website classic --typescript ``` +
+ Alternative installation methods + +You can also initialize a new project using your preferred project manager: + +````mdx-code-block + + + +```bash +npm init docusaurus website classic +``` + + + + +```bash +yarn create docusaurus website classic +``` + + + + +```bash +pnpm create docusaurus website classic +``` + + + +```` + +
+ ## Project structure {#project-structure} Assuming you chose the classic template and named your site `my-website`, you will see the following files generated under a new directory `my-website/`: