-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #143 from framesjs/feat/cli-tool
feat: basic create-frames cli tool
- Loading branch information
Showing
141 changed files
with
8,269 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"create-frames": minor | ||
--- | ||
|
||
feat: introduce cli tool to bootstrap projects from templates |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"type": "module" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/** | ||
* This script is used to prepare create-frames package for publishing. | ||
* | ||
* It copies the templates directory to the root of the package so that it can be used by the create-frames package. | ||
*/ | ||
|
||
import { dirname, resolve } from "node:path"; | ||
import { fileURLToPath } from "node:url"; | ||
import glob from "fast-glob"; | ||
import { cpSync, renameSync, rmSync } from 'node:fs'; | ||
|
||
const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
|
||
|
||
rmSync(resolve(__dirname, "../packages/create-frames/templates"), { force: true, recursive: true }); | ||
|
||
cpSync( | ||
resolve(__dirname, "../templates"), | ||
resolve(__dirname, "../packages/create-frames/templates"), | ||
{ | ||
recursive: true, | ||
filter: (src) => !/(node_modules|\.turbo|\.next|next-env\.d\.ts)/.test(src), | ||
} | ||
); | ||
|
||
const dotfiles = await glob( | ||
resolve(__dirname, "../packages/create-frames/templates/**/.*") | ||
); | ||
|
||
// rename dotfiles to use underscore instead of dot so we can publish them to npm as is | ||
for (const doftile of dotfiles) { | ||
renameSync(doftile, doftile.replace("/.", "/_")); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
templates |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
!templates |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Create Frames.js app | ||
|
||
Create a new Frames.js app with a single command using predefined templates. | ||
|
||
## Creating a project | ||
|
||
### Using npm | ||
|
||
```sh | ||
npm init frames | ||
``` | ||
|
||
### Using yarn | ||
|
||
```sh | ||
yarn create frames | ||
``` | ||
|
||
### Using pnpm | ||
|
||
```sh | ||
pnpm create frames | ||
``` | ||
|
||
## Installing globally (optional) and running from terminal | ||
|
||
You can also install this package globally and run it from your terminal. | ||
|
||
### Using npm | ||
|
||
```sh | ||
npm install -g create-frames | ||
create-frames | ||
``` | ||
|
||
### Using yarn | ||
|
||
```sh | ||
yarn global add create-frames | ||
create-frames | ||
``` | ||
|
||
### Using pnpm | ||
|
||
```sh | ||
pnpm add -g create-frames | ||
create-frames | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#!/usr/bin/env node | ||
import yargs from "yargs"; | ||
import { hideBin } from "yargs/helpers"; | ||
import { getTemplates } from "./utils/getTemplates.js"; | ||
import { create } from "./create.js"; | ||
|
||
// use only default command | ||
yargs(hideBin(process.argv)) | ||
.scriptName("create-frames") | ||
.usage("Usage: $0 [options]") | ||
.command( | ||
"$0", | ||
"Create a new project", | ||
{ | ||
name: { | ||
alias: "n", | ||
describe: "Name of the project", | ||
type: "string", | ||
}, | ||
template: { | ||
alias: "t", | ||
describe: "Choose a template for the project", | ||
choices: getTemplates(), | ||
}, | ||
}, | ||
(args) => { | ||
create(args); | ||
} | ||
) | ||
.parse(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { intro, log, outro, select, confirm, text } from "@clack/prompts"; | ||
import { getTemplates } from "./utils/getTemplates.js"; | ||
import { dirname, relative, resolve } from "node:path"; | ||
import { fileURLToPath } from "node:url"; | ||
import { spawnSync } from "node:child_process"; | ||
import ignore from "ignore"; | ||
import pc from "picocolors"; | ||
import { detect as detectPackageManager } from "detect-package-manager"; | ||
import { | ||
cpSync, | ||
readFileSync, | ||
readdirSync, | ||
renameSync, | ||
writeFileSync, | ||
} from "node:fs"; | ||
import { packageManagerRunCommand } from "./utils/packageManagerRunCommand.js"; | ||
|
||
const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
|
||
/** | ||
* | ||
* @param {import('yargs').ArgumentsCamelCase<{ t?: string, n?: string }>} params | ||
*/ | ||
export async function create(params) { | ||
if (params.$0 !== "create-frames") { | ||
throw new Error("Invalid command"); | ||
} | ||
|
||
intro("Welcome to frames.js"); | ||
|
||
// if there is no -n argument (name, ask for the name of new project) | ||
let projectName = | ||
params.n || | ||
(await text({ | ||
message: "Enter the name of your project", | ||
placeholder: "my-frames-app", | ||
validate(input) { | ||
if (!input) { | ||
return "Project name is required"; | ||
} | ||
|
||
return; | ||
}, | ||
})); | ||
|
||
const destDir = resolve(process.cwd(), projectName); | ||
|
||
const template = | ||
params.t || | ||
(await select({ | ||
message: "Choose a template for the project", | ||
options: getTemplates().map((template) => ({ | ||
name: template, | ||
value: template, | ||
})), | ||
defaultValue: "next", | ||
validate(input) { | ||
if (!input) { | ||
return "Template is required"; | ||
} | ||
|
||
return; | ||
}, | ||
})); | ||
|
||
const templateDir = resolve(__dirname, "./templates", template); | ||
const ignoredPatterns = readFileSync( | ||
resolve(templateDir, "_gitignore"), | ||
"utf-8" | ||
); | ||
const ignored = ignore().add(ignoredPatterns); | ||
|
||
cpSync(templateDir, destDir, { | ||
force: true, | ||
recursive: true, | ||
filter(src) { | ||
const path = relative(templateDir, src); | ||
|
||
return !path || !ignored.ignores(path); | ||
}, | ||
}); | ||
|
||
for (const file of readdirSync(destDir)) { | ||
if (!file.startsWith("_")) continue; | ||
|
||
renameSync( | ||
resolve(destDir, file), | ||
resolve(destDir, file.replace("_", ".")) | ||
); | ||
} | ||
|
||
const pkgJsonPath = resolve(destDir, "package.json"); | ||
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8")); | ||
pkgJson.name = projectName; | ||
writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2)); | ||
|
||
log.success(`Project successfully scaffolded in ${pc.blue(destDir)}!`); | ||
|
||
const pkgManager = await detectPackageManager(); | ||
|
||
const wantsToInstallDependencies = await confirm({ | ||
message: `Do you want to install the dependencies using ${pkgManager}?`, | ||
initialValue: true, | ||
}); | ||
|
||
if (wantsToInstallDependencies) { | ||
log.message(`Installing the dependencies...`); | ||
const result = spawnSync(pkgManager, ["install"], { | ||
cwd: destDir, | ||
stdio: "ignore", | ||
}); | ||
|
||
if (result.status !== 0) { | ||
log.error( | ||
`Failed to install the dependencies, please install them manually.` | ||
); | ||
process.exit(1); | ||
} | ||
|
||
log.success(`Dependencies installed!`); | ||
} | ||
|
||
log.message("Next steps:"); | ||
log.step( | ||
`1. Go to the project directory by running: ${pc.blue(`cd ./${projectName}`)}` | ||
); | ||
log.step( | ||
`2. Start the development server and run the app in debugger by running: ${pc.blue(await packageManagerRunCommand("dev"))}` | ||
); | ||
log.step( | ||
`3. Open your browser and go to ${pc.blue(`http://localhost:3010`)} to see your app running in the debugger` | ||
); | ||
|
||
outro("Done! Your project has been set up! 🎉"); | ||
} |
Oops, something went wrong.