feat(create): new --package-manager option; interactive package manager selection (#6750)

This commit is contained in:
Joshua Chen 2022-02-24 18:50:37 +08:00 committed by GitHub
parent 89560226f0
commit a70514205d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 32 deletions

View file

@ -12,13 +12,10 @@ NEW_VERSION="$(node -p "require('./packages/docusaurus/package.json').version").
CONTAINER_NAME="verdaccio"
EXTRA_OPTS=""
usage() { echo "Usage: $0 [-n] [-s]" 1>&2; exit 1; }
usage() { echo "Usage: $0 [-s]" 1>&2; exit 1; }
while getopts ":ns" o; do
case "${o}" in
n)
EXTRA_OPTS="${EXTRA_OPTS} --use-npm"
;;
s)
EXTRA_OPTS="${EXTRA_OPTS} --skip-install"
;;

View file

@ -36,14 +36,17 @@ program.version(packageJson.version);
program
.arguments('[siteName] [template] [rootDir]')
.option('--use-npm', 'Use NPM as package manage even with Yarn installed')
.option(
'--skip-install',
'-p, --package-manager <manager>',
'The package manager used to install dependencies. One of yarn, npm, and pnpm.',
)
.option(
'-s, --skip-install',
'Do not run package manager immediately after scaffolding',
)
.option('--typescript', 'Use the TypeScript template variant')
.option('-t, --typescript', 'Use the TypeScript template variant')
.option(
'--git-strategy <strategy>',
'-g, --git-strategy <strategy>',
`Only used if the template is a git repository.
\`deep\`: preserve full history
\`shallow\`: clone with --depth=1
@ -56,10 +59,10 @@ program
siteName,
template,
rootDir = '.',
{useNpm, skipInstall, typescript, gitStrategy} = {},
{packageManager, skipInstall, typescript, gitStrategy} = {},
) => {
wrapCommand(init)(path.resolve(rootDir), siteName, template, {
useNpm,
packageManager,
skipInstall,
typescript,
gitStrategy,

View file

@ -17,6 +17,8 @@ import {fileURLToPath} from 'url';
const RecommendedTemplate = 'classic';
const TypeScriptTemplateSuffix = '-typescript';
// Only used in the rare, rare case of running globally installed create +
// using --skip-install. We need a default name to show the tip text
const DefaultPackageManager = 'npm';
const SupportedPackageManagers = {
@ -54,18 +56,48 @@ function findPackageManagerFromUserAgent():
);
}
async function getPackageManager(
forceUseNpm?: boolean,
): Promise<SupportedPackageManager> {
// TODO replace --use-npm by --package-manager option
if (forceUseNpm) {
async function askForPackageManagerChoice(): Promise<SupportedPackageManager> {
const hasYarn = shell.exec('yarn --version', {silent: true}).code === 0;
const hasPNPM = shell.exec('pnpm --version', {silent: true}).code === 0;
if (!hasYarn && !hasPNPM) {
return 'npm';
}
const choices = ['npm', hasYarn && 'yarn', hasPNPM && 'pnpm']
.filter((p): p is string => Boolean(p))
.map((p) => ({title: p, value: p}));
return (
await prompts({
type: 'select',
name: 'packageManager',
message: 'Select a package manager...',
choices,
})
).packageManager;
}
async function getPackageManager(
packageManagerChoice: SupportedPackageManager | undefined,
skipInstall: boolean = false,
): Promise<SupportedPackageManager> {
if (
packageManagerChoice &&
!PackageManagersList.includes(packageManagerChoice)
) {
throw new Error(
`Invalid package manager choice ${packageManagerChoice}. Must be one of ${PackageManagersList.join(
', ',
)}`,
);
}
return (
packageManagerChoice ??
(await findPackageManagerFromLockFile()) ??
findPackageManagerFromUserAgent() ??
DefaultPackageManager
// This only happens if the user has a global installation in PATH
(skipInstall ? DefaultPackageManager : askForPackageManagerChoice())
);
}
@ -169,13 +201,12 @@ export default async function init(
siteName?: string,
reqTemplate?: string,
cliOptions: Partial<{
useNpm: boolean;
packageManager: SupportedPackageManager;
skipInstall: boolean;
typescript: boolean;
gitStrategy: typeof gitStrategies[number];
}> = {},
): Promise<void> {
const pkgManager = await getPackageManager(cliOptions.useNpm);
const templatesDir = fileURLToPath(new URL('../templates', import.meta.url));
const templates = await readTemplates(templatesDir);
const hasTS = (templateName: string) =>
@ -358,6 +389,10 @@ export default async function init(
// Display the most elegant way to cd.
const cdpath = path.relative('.', dest);
const pkgManager = await getPackageManager(
cliOptions.packageManager,
cliOptions.skipInstall,
);
if (!cliOptions.skipInstall) {
shell.cd(dest);
logger.info`Installing dependencies with name=${pkgManager}...`;

View file

@ -37,10 +37,18 @@ Example:
npx create-docusaurus@latest website classic
```
If you do not specify `name` or `template`, it will prompt you for them. We recommend the `classic` template so that you can get started quickly, and it contains features found in Docusaurus 1. The `classic` template contains `@docusaurus/preset-classic` which includes standard documentation, a blog, custom pages, and a CSS framework (with dark mode support). You can get up and running extremely quickly with the classic template and customize things later on when you have gained more familiarity with Docusaurus.
If you do not specify `name` or `template`, it will prompt you for them.
We recommend the `classic` template so that you can get started quickly, and it contains features found in Docusaurus 1. The `classic` template contains `@docusaurus/preset-classic` which includes standard documentation, a blog, custom pages, and a CSS framework (with dark mode support). You can get up and running extremely quickly with the classic template and customize things later on when you have gained more familiarity with Docusaurus.
The `template` also accepts a git repo URL or a local file path, with the latter evaluated relative to the current working directory. The repo/folder content will be copied to the site directory. If it's a git repository, you can also specify a cloning strategy. Run `npx create-docusaurus@latest --help` for more information.
You can also use the template's TypeScript variant by passing the `--typescript` flag.
```bash
npx create-docusaurus@latest my-website classic --typescript
```
:::info FB-Only
If you are setting up a new Docusaurus website for a Facebook open source project, use the `facebook` template instead, which comes with some useful Facebook-specific defaults:
@ -51,20 +59,8 @@ npx create-docusaurus@latest my-website facebook
:::
If you want to skip installing dependencies, use the `--skip-install` option, like the following:
```bash
npx create-docusaurus@latest my-website classic --skip-install
```
You can also use the template's TypeScript variant by passing the `--typescript` flag.
```bash
npx create-docusaurus@latest my-website classic --typescript
```
<details>
<summary>Alternative installation methods</summary>
<summary>Alternative installation commands</summary>
You can also initialize a new project using your preferred project manager:
@ -96,6 +92,19 @@ pnpm create docusaurus website classic
</details>
Docusaurus makes best efforts to select a package manager to install dependencies for you, based on the command you are using and the project you are in. You can override this behavior by using `--package-manager [npm/yarn/pnpm]`.
```bash
# Use Yarn to install dependencies even when the command is npx
npx create-docusaurus@latest my-website classic --package-manager yarn
```
If you want to skip installing dependencies, use the `--skip-install` option.
```bash
npx create-docusaurus@latest my-website classic --skip-install
```
## 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/`: