Skip to content

Commit

Permalink
improve cli onboarding (#89)
Browse files Browse the repository at this point in the history
* improve cli onboarding

* add changeset
  • Loading branch information
souporserious authored Apr 3, 2024
1 parent 6fcd390 commit 77c4c10
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/witty-mirrors-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-mdxts": patch
---

Improves CLI onboarding by prompting to copy the blog example if not run in a project.
12 changes: 2 additions & 10 deletions examples/blog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,8 @@ This example shows how to build a blog with MDXTS and Next.js.

## How to use

Use [`create-mdxts`](https://github.com/souporserious/mdxts/tree/main/packages/create-mdxts) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to copy this example to your machine:
Use the [`create-mdxts`](https://github.com/souporserious/mdxts/tree/main/packages/create-mdxts) CLI with [npx](https://docs.npmjs.com/cli/v10/commands/npx) to copy this example to your machine:

```bash
npm create-mdxts --example=blog
```

```bash
yarn create mdxts --example=blog
```

```bash
pnpm create mdxts --example=blog
npx create-mdxts --example blog
```
43 changes: 38 additions & 5 deletions packages/create-mdxts/src/fetch-example.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import path from 'node:path'
import { createWriteStream, mkdirSync } from 'node:fs'
import {
createWriteStream,
mkdirSync,
readFileSync,
writeFileSync,
} from 'node:fs'
import { Readable } from 'node:stream'
import { pipeline } from 'node:stream/promises'
import chalk from 'chalk'

import { getCurrentVersion } from './is-package-outdated'
import { Log, askQuestion } from './utils'

/** Fetches the contents of an MDXTS example from the GitHub repository and downloads them to the local file system. */
export async function fetchExample(exampleSlug: string) {
export async function fetchExample(
exampleSlug: string,
prependMessage?: string
) {
await fetchGitHubDirectory({
owner: 'souporserious',
repo: 'mdxts',
branch: 'main',
directoryPath: `examples/${exampleSlug}`,
prependMessage,
})
}

Expand All @@ -23,12 +33,14 @@ async function fetchGitHubDirectory({
branch,
directoryPath,
basePath = '.',
prependMessage,
}: {
owner: string
repo: string
branch: string
directoryPath: string
basePath?: string
prependMessage?: string
}) {
const isRoot = basePath === '.'
const apiUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${directoryPath}?ref=${branch}`
Expand All @@ -48,7 +60,7 @@ async function fetchGitHubDirectory({

if (isRoot) {
const userBasePath = await askQuestion(
`Download the ${directoryName} example to ${chalk.bold(
`${prependMessage}Download the ${directoryName} example to ${chalk.bold(
workingDirectory
)}? Press enter to proceed or specify a different directory: `
)
Expand Down Expand Up @@ -87,17 +99,19 @@ async function fetchGitHubDirectory({

if (isRoot) {
const { detectPackageManager } = await import('@antfu/install-pkg')
const packageManager = await detectPackageManager()
const packageManager = await detectPackageManager(process.cwd())
const introInstallInstructions =
basePath === '.'
? `Run`
: `Change to the ${chalk.bold(directoryName)} directory and run`

await reformatPackageJson(workingDirectory, basePath)

Log.success(
`Example ${chalk.bold(
directoryName
)} fetched and configured successfully! ${introInstallInstructions} ${chalk.bold(
`${packageManager} install`
`${packageManager ?? 'npm'} install`
)} to install the dependencies and get started.`
)
}
Expand Down Expand Up @@ -129,3 +143,22 @@ const downloadFile = async (url: string, filePath: string) => {

await pipeline(stream, fileStream)
}

/** Re-format package.json file to remove monorepo dependencies and use the latest MDXTS version. */
async function reformatPackageJson(workingDirectory: string, basePath: string) {
const packageJsonPath = path.join(workingDirectory, basePath, 'package.json')
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))

// Remove "@example/" prefix from package name
packageJson.name = packageJson.name.replace('@example/', '')

// Replace mdxts "workspace:*" with the latest version of the package
packageJson.dependencies['mdxts'] = await getCurrentVersion()

// Remove shiki and prettier dependencies since they are only required for the monorepo
delete packageJson.dependencies['prettier']
delete packageJson.dependencies['shiki']

// Write the updated package.json file
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf-8')
}
15 changes: 10 additions & 5 deletions packages/create-mdxts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Log, askQuestion, askYesNo, getFilePatternBaseName } from './utils'

const states = {
INITIAL_STATE: 'initialState',
CHECK_NEXT_INSTALLED: 'checkNextInstalled',
CHECK_TYPESCRIPT_INSTALLED: 'checkTypescriptInstalled',
CHECK_MDXTS_INSTALLED: 'checkMdxtsInstalled',
INSTALL_MDXTS: 'installMdxts',
Expand Down Expand Up @@ -55,6 +56,15 @@ export async function start() {
try {
switch (currentState) {
case states.INITIAL_STATE:
const packageJsonPath = join(process.cwd(), 'package.json')
if (existsSync(packageJsonPath)) {
currentState = states.CHECK_NEXT_INSTALLED
} else {
await fetchExample('blog', 'No project was found. ')
currentState = states.SUCCESS_STATE
}
break
case states.CHECK_NEXT_INSTALLED:
checkNextJsProject()
currentState = states.CHECK_TYPESCRIPT_INSTALLED
break
Expand Down Expand Up @@ -146,11 +156,6 @@ start()

export function checkNextJsProject() {
const packageJsonPath = join(process.cwd(), 'package.json')
if (!existsSync(packageJsonPath)) {
throw new Error(
'No package.json found. Please run this command in a Next.js project directory.'
)
}
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
if (!packageJson.devDependencies?.next && !packageJson.dependencies?.next) {
throw new Error(
Expand Down
2 changes: 1 addition & 1 deletion packages/create-mdxts/src/is-package-outdated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function shouldRefreshCache() {
return now - cacheContent.cachedAt > DAY_IN_MILLISECONDS
}

async function getCurrentVersion() {
export async function getCurrentVersion() {
if (shouldRefreshCache()) {
const version = await fetchPackageVersion()
saveVersionToCache(version)
Expand Down

0 comments on commit 77c4c10

Please sign in to comment.