Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(create-gatsby): Improve install #28318

Merged
merged 6 commits into from
Nov 30, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions packages/create-gatsby/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Enquirer from "enquirer"
import cmses from "./cmses.json"
import styles from "./styles.json"
import features from "./features.json"
import { initStarter, getPackageManager } from "./init-starter"
import { initStarter, getPackageManager, gitSetup } from "./init-starter"
import { installPlugins } from "./install-plugins"
import c from "ansi-colors"
import path from "path"
Expand All @@ -13,6 +13,7 @@ import { center, rule, wrap } from "./components/utils"
import { stripIndent } from "common-tags"
import { trackCli } from "./tracking"
import crypto from "crypto"
import { reporter } from "./reporter"

const sha256 = (str: string): string =>
crypto.createHash(`sha256`).update(str).digest(`hex`)
Expand Down Expand Up @@ -50,6 +51,7 @@ const makeChoices = (
export const validateProjectName = async (
value: string
): Promise<string | boolean> => {
value = value.trim()
if (INVALID_FILENAMES.test(value)) {
return `The destination "${value}" is not a valid filename. Please try again, avoiding special characters.`
}
Expand Down Expand Up @@ -167,6 +169,7 @@ ${center(c.blueBright.bold.underline(`Welcome to Gatsby!`))}
enquirer.use(plugin)

const data = await enquirer.prompt(questions)
data.project = data.project.trim()

trackCli(`CREATE_GATSBY_SELECT_OPTION`, {
name: `project_name`,
Expand Down Expand Up @@ -297,24 +300,22 @@ ${c.bold(`Thanks! Here's what we'll now do:`)}

await initStarter(DEFAULT_STARTER, data.project, packages.map(removeKey))

console.log(
c.green(c.symbols.check) + ` Created site in ` + c.green(data.project)
)
reporter.success(`Created site in ` + c.green(data.project))

if (plugins.length) {
console.log(c.bold(`${w(`🔌 `)}Installing plugins...`))
console.log(`${w(`🔌 `)}Setting-up plugins...`)
wardpeet marked this conversation as resolved.
Show resolved Hide resolved
await installPlugins(plugins, pluginConfig, path.resolve(data.project), [])
}

const pm = await getPackageManager()
await gitSetup(data.project)

const runCommand = pm === `npm` ? `npm run` : `yarn`
const pm = await getPackageManager()

console.log(
stripIndent`
${w(`🎉 `)}Your new Gatsby site ${c.bold(
data.project
)} has been successfully bootstrapped
)} has been successfully created
at ${c.bold(path.resolve(data.project))}.
`
)
Expand All @@ -323,7 +324,7 @@ ${c.bold(`Thanks! Here's what we'll now do:`)}
`)

console.log(`Start the local development server with\n
${c.magenta(`${runCommand} develop`)}
${c.magenta(`${pm} start`)}
wardpeet marked this conversation as resolved.
Show resolved Hide resolved
`)

console.log(`See all commands at\n
Expand Down
88 changes: 63 additions & 25 deletions packages/create-gatsby/src/init-starter.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
import { execSync } from "child_process"
import execa from "execa"
import execa, { Options } from "execa"
import fs from "fs-extra"
import path from "path"
import { reporter } from "./reporter"
import { spin } from "tiny-spin"
import { getConfigStore } from "./get-config-store"
type PackageManager = "yarn" | "npm"
import c from "ansi-colors"

const packageMangerConfigKey = `cli.packageManager`
const packageManagerConfigKey = `cli.packageManager`

const kebabify = (str: string): string =>
str
.replace(/([a-z])([A-Z])/g, `$1-$2`)
.replace(/[^a-zA-Z]+/g, `-`)
.toLowerCase()

export const getPackageManager = (): PackageManager =>
getConfigStore().get(packageMangerConfigKey)
getConfigStore().get(packageManagerConfigKey)

export const setPackageManager = (packageManager: PackageManager): void => {
getConfigStore().set(packageMangerConfigKey, packageManager)
getConfigStore().set(packageManagerConfigKey, packageManager)
}

export const clearLine = (count = 1): Promise<boolean> =>
new Promise(resolve => {
process.stderr.moveCursor(0, -count, () => {
process.stderr.write(`\u001b[2K`)
resolve()
})
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you copied this from somewhere, could you paste the link here? Does this work on windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, all my own work. I'm assuming it works on Windows, because the other ansi sequences do, but it will need checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added comments and a link to a list of escape codes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested and confirmed working on Windows. (Try npm init gatsby@create-gatsby)

// Checks the existence of yarn package
// We use yarnpkg instead of yarn to avoid conflict with Hadoop yarn
// Refer to https://github.com/yarnpkg/yarn/issues/673
Expand All @@ -31,19 +45,15 @@ const checkForYarn = (): boolean => {
// Initialize newly cloned directory as a git repo
const gitInit = async (
rootPath: string
): Promise<execa.ExecaReturnBase<string>> => {
reporter.info(`Initialising git in ${rootPath}`)

return await execa(`git`, [`init`], { cwd: rootPath })
}
): Promise<execa.ExecaReturnBase<string>> =>
await execa(`git`, [`init`], { cwd: rootPath })

// Create a .gitignore file if it is missing in the new directory
const maybeCreateGitIgnore = async (rootPath: string): Promise<void> => {
if (fs.existsSync(path.join(rootPath, `.gitignore`))) {
return
}

reporter.info(`Creating minimal .gitignore in ${rootPath}`)
await fs.writeFile(
path.join(rootPath, `.gitignore`),
`.cache\nnode_modules\npublic\n`
Expand All @@ -52,8 +62,6 @@ const maybeCreateGitIgnore = async (rootPath: string): Promise<void> => {

// Create an initial git commit in the new directory
const createInitialGitCommit = async (rootPath: string): Promise<void> => {
reporter.info(`Create initial git commit in ${rootPath}`)

await execa(`git`, [`add`, `-A`], { cwd: rootPath })
// use execSync instead of spawn to handle git clients using
// pgp signatures (with password)
Expand All @@ -68,21 +76,41 @@ const createInitialGitCommit = async (rootPath: string): Promise<void> => {
}
}

const setNameInPackage = async (
sitePath: string,
name: string
): Promise<void> => {
const packageJsonPath = path.join(sitePath, `package.json`)
const packageJson = await fs.readJSON(packageJsonPath)
packageJson.name = kebabify(name)
packageJson.description = `My Gatsby site`
try {
const result = await execa(`git`, [`config`, `user.name`])
if (result.failed) {
delete packageJson.author
} else {
packageJson.author = result.stdout
}
} catch (e) {
delete packageJson.author
}

await fs.writeJSON(packageJsonPath, packageJson)
wardpeet marked this conversation as resolved.
Show resolved Hide resolved
}

// Executes `npm install` or `yarn install` in rootPath.
const install = async (
rootPath: string,
packages: Array<string>
): Promise<void> => {
const prevDir = process.cwd()

let stop = spin(`Installing packages...`)
reporter.info(`${c.blueBright(c.symbols.pointer)} Installing Gatsby...`)

process.chdir(rootPath)

const npmConfigUserAgent = process.env.npm_config_user_agent

const silent = `--silent`

try {
if (!getPackageManager()) {
if (npmConfigUserAgent?.includes(`yarn`)) {
Expand All @@ -93,23 +121,32 @@ const install = async (
}
if (getPackageManager() === `yarn` && checkForYarn()) {
await fs.remove(`package-lock.json`)
const args = packages.length ? [`add`, silent, ...packages] : [silent]
const args = packages.length
? [`add`, `--silent`, ...packages]
: [`--silent`]
await execa(`yarnpkg`, args)
} else {
await fs.remove(`yarn.lock`)
const options: Options = {
stderr: `inherit`,
}

await execa(`npm`, [`install`, silent])
stop()
stop = spin(`Installing plugins...`)
await execa(`npm`, [`install`, silent, ...packages])
stop()
await execa(`npm`, [`install`, `--loglevel`, `error`], options)
await clearLine()
reporter.success(`Installed Gatsby`)
reporter.info(`${c.blueBright(c.symbols.pointer)} Installing plugins...`)
await execa(
`npm`,
[`install`, `--loglevel`, `error`, ...packages],
options
)
await clearLine()
reporter.success(`Installed plugins`)
}
} catch (e) {
reporter.panic(e.message)
} finally {
process.chdir(prevDir)
stop()
reporter.success(`Installed packages`)
}
}

Expand Down Expand Up @@ -143,7 +180,7 @@ const clone = async (
await fs.remove(path.join(rootPath, `.git`))
}

async function gitSetup(rootPath: string): Promise<void> {
export async function gitSetup(rootPath: string): Promise<void> {
await gitInit(rootPath)
await maybeCreateGitIgnore(rootPath)
await createInitialGitCommit(rootPath)
Expand All @@ -161,8 +198,9 @@ export async function initStarter(

await clone(starter, sitePath)

await setNameInPackage(sitePath, rootPath)

await install(rootPath, packages)

await gitSetup(rootPath)
// trackCli(`NEW_PROJECT_END`);
}