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

feat: Onboarding Setup #956

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
82 changes: 64 additions & 18 deletions bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,63 @@

## To learn more, visit https://stacksjs.org/docs/guide/bootstrap

if [ -n "$1" ]; then
# Check if the directory exists
if [ -d "storage/framework/core" ]; then # determines whether we are in a Stacks context
:
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}

# Check for required commands
for cmd in git mkfifo; do
if ! command_exists "$cmd"; then
echo "Error: '$cmd' is required but not installed. Please install $cmd and try again."
exit 1
fi
done

# Check if the directory exists
if [ -d "storage/framework/core" ]; then
:
else
if [ -z "$1" ]; then
project="stacks"
else
if [ -d "$1" ]; then
echo "Project $1 exists locally. Please use a different name & run again."
exit 1
else
git clone https://github.com/stacksjs/stacks.git $1
cd "$1" || exit 1
project="$1"
fi

# Run the pkgx-install script (in case it’s already installed, it will be updated to the latest version)
"./storage/framework/scripts/pkgx-install"
if [ "$project" = "stacks" ] && [ -d "storage/framework/core" ]; then
:
elif [ -d "$project" ]; then
echo "Project $project exists locally. Please use a different name & run again."
exit 1
else
git clone https://github.com/stacksjs/stacks.git "$project"
cd "$project" || exit 1

echo "Project $1 has been created. Please open a new terminal, run 'bun run dev' to start the server."
# Save current project directory path
projectDir=$(pwd)

if ! command_exists "./storage/framework/scripts/pkgx-install"; then
echo "Error: pkgx-install script not found in './storage/framework/scripts/pkgx-install'. Please check your installation and try again."
exit 1
fi
"./storage/framework/scripts/pkgx-install"

echo "Installing project dependencies via bun..."
pkgx bun install

echo "Building project core packages..."
cd "./storage/framework/core" && pkgx bun run build

echo "Project $project has been created in ${projectDir}. Run 'bun run dev' to start the server."

exit 1
fi
fi

# Get the directory of the current script and go up 3 directories
PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
CLI_PATH="$PROJECT_ROOT/storage/framework/core/buddy/src/cli.ts"
CORE_PATH="$PROJECT_ROOT/storage/framework/core"
CLI_PATH="$CORE_PATH/buddy/src/cli.ts"
SCRIPT_PATH="$PROJECT_ROOT/storage/framework/scripts/pkgx-install"
LOG_PATH="$PROJECT_ROOT/storage/logs/console.log"

Expand All @@ -44,23 +76,37 @@ cd "$PROJECT_ROOT" || exit 1
# Run the pkgx-install script
case "$*" in
*--verbose*)
if [ ! -f "$SCRIPT_PATH" ]; then
echo "Error: Script path $SCRIPT_PATH does not exist."
exit 1
fi
"$SCRIPT_PATH"
# bun --bun ./storage/framework/core/buddy/src/cli.ts setup --verbose
;;
*)
if [ ! -f "$SCRIPT_PATH" ]; then
echo "Error: Script path $SCRIPT_PATH does not exist."
exit 1
fi
"$SCRIPT_PATH" > /dev/null 2>&1
# bun --bun ./storage/framework/core/buddy/src/cli.ts setup
;;
esac

# Create a named pipe
mkfifo /tmp/pipe

# Bun is assumed to be installed after it's initial set up
# Run the command, send output to both the console and the pipe
bun --bun "$CLI_PATH" setup | tee /tmp/pipe &
if ! command_exists bun; then
# We'll use pgkx with bun to get
pkgx bun --bun "$CLI_PATH" setup | tee /tmp/pipe &
exit 1
else
bun --bun "$CLI_PATH" setup | tee /tmp/pipe &
fi


# Read from the pipe, add timestamps, and append to the file
while IFS= read -r line; do echo "$(date '+[%Y-%m-%d %H:%M:%S]') $line"; done < /tmp/pipe >> "$LOG_PATH"

# Remove the named pipe
rm /tmp/pipe
rm /tmp/pipe
1 change: 1 addition & 0 deletions storage/framework/core/buddy/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ async function main() {
cmd.version(buddy)
cmd.prepublish(buddy)
cmd.upgrade(buddy)
cmd.create(buddy)

// dynamic imports
await dynamicImports(buddy)
Expand Down
3 changes: 1 addition & 2 deletions storage/framework/core/buddy/src/commands/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@ export function create(buddy: CLI) {
.option('-p, --project', descriptions.project, { default: false })
.option('--verbose', descriptions.verbose, { default: false })
// .option('--auth', 'Scaffold an authentication?', { default: true })
.action(async (options: CreateOptions) => {
.action(async (name: string, options: CreateOptions) => {
log.debug('Running `buddy new <name>` ...', options)

const startTime = await intro('stacks new')
const name = options.name
const path = resolve(process.cwd(), name)

isFolderCheck(path)
Expand Down
37 changes: 36 additions & 1 deletion storage/framework/core/buddy/src/commands/setup.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import process from 'node:process'
import { path as p } from '@stacksjs/path'
import { fs } from '@stacksjs/storage'
import { Action } from '@stacksjs/enums'
import { runAction } from '@stacksjs/actions'
import { handleError } from '@stacksjs/error-handling'
Expand Down Expand Up @@ -121,7 +122,41 @@ async function initializeProject(options: CliOptions): Promise<void> {
}

export async function optimizePkgxDeps(): Promise<void> {
return new Promise(resolve => setTimeout(resolve, 300))
return new Promise((resolve) => {
// Mapping of config files to their respective packages
// Now supports multiple files per package
const configToPackageMap: Readonly<{ [packageName: string]: string[] }> = {
redis: ['cache.ts', 'session.ts'], // Example: both cache.ts and session.ts need redis

// sqlite: ['sample.ts'], // Example: sqlite will be removed when this is uncommented since sample.ts does not exist

// You can add other mappings here
}
Comment on lines +128 to +134
Copy link
Member

Choose a reason for hiding this comment

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

Need to finish this


// Function to check if at least one file exists
const atLeastOneFileExists = (fileNames: string[]) => fileNames.some(fileName => fs.existsSync(`./config/${fileName}`))

log.info('[INFO] Checking config files...')

// Check each package and install if any associated config file exists
Object.entries(configToPackageMap).forEach(([packageName, configFiles]) => {
if (atLeastOneFileExists(configFiles)) {
log.info(`[INFO] Required '${packageName}' for '${configFiles.join(', ')}' config files...`)
}
else {
log.info(`[INFO] No config files for '${packageName}' exist. Removing from dependencies in pkgx.yaml...`)

const pkgxPath = './pkgx.yaml' // TODO: Might need to properly reference this in a config so when the path changes, this will be properly located
const pkgxContent = fs.readFileSync(pkgxPath, 'utf8')
const lines = pkgxContent.split('\n')
const newLines = lines.filter(line => !line.includes(`${packageName}.`))
fs.writeFileSync(pkgxPath, newLines.join('\n'))
log.success(`[SUCCESS] Removed '${packageName}'...`)
}
})

resolve()
})
}

export async function ensureEnvIsSet(options: CliOptions): Promise<void> {
Expand Down
79 changes: 79 additions & 0 deletions storage/framework/onboarding/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { setTimeout } from 'node:timers/promises'
import * as p from '@clack/prompts'
import color from 'picocolors'
import { runCommand } from '@stacksjs/cli'
import { path } from '@stacksjs/path'

async function main() {
console.clear()

await setTimeout(1000)

p.intro(`Stacks ${color.bgCyan(color.black(' create-app '))}`)

const defaultFolderPath = './stacks'

const project = await p.group(
{
path: () =>
p.text({
message: 'Where should we create your project?',
initialValue: defaultFolderPath,
placeholder: defaultFolderPath,
validate: (value) => {
if (!value)
return 'Please enter a path.'
if (value[0] !== '.')
return 'Please enter a relative path.'
},
}),
type: ({ results }) =>
p.select({
message: `Pick your flavor ("${results.path}")`,
initialValue: 'default',
maxItems: 3,
options: [
{ value: 'default', label: 'Default (UI with API)' },
{ value: 'ui', label: 'UI' },
{ value: 'api', label: 'API' },
],
}),
modules: () =>
p.multiselect({
message: 'Select additional modules.',
initialValues: ['prettier', 'eslint'],
Copy link
Member

Choose a reason for hiding this comment

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

Unsure why prettier is here. We don't use it, and actively suggest people not to use it in combination with Stacks formatting 👍

options: [
{ value: 'database', label: 'Database', hint: 'recommended' },
{ value: 'search', label: 'Search', hint: 'recommended' },
{
value: 'notifications',
label: 'Notifications (email, sms, chat)',
},
{ value: 'cache', label: 'Cache' },
],
}),
},
{
onCancel: () => {
p.cancel('Operation cancelled.')
process.exit(0)
},
},
)

const s = p.spinner()

s.start('Creating new project')
await runCommand(`${path.projectPath('buddy')} new ${project.path}`)
s.stop('Created new project')

const nextSteps = `cd ${project.path} \nbun run dev`

p.note(nextSteps, 'Next steps.')

p.outro(
`Problems? ${color.underline(color.cyan('https://github.com/stacksjs/stacks/issues'))}`,
)
}

main().catch(console.error)
17 changes: 17 additions & 0 deletions storage/framework/onboarding/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "stacks-onboarding",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@clack/core": "^0.3.4",
"@clack/prompts": "^0.7.0",
"picocolors": "^1.0.0"
}
}
Comment on lines +1 to +17
Copy link
Member

Choose a reason for hiding this comment

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

This shouldn't be here and extracted to core packages, placed where appropriate, like the cli package.

We may already may require these deps elsewhere too

13 changes: 13 additions & 0 deletions storage/framework/onboarding/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"noEmit": true,
"module": "ESNext",
"target": "ESNext",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true
},
"include": ["packages"]
}
Comment on lines +1 to +13
Copy link
Member

Choose a reason for hiding this comment

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

This also isn't needed then

5 changes: 1 addition & 4 deletions storage/framework/scripts/pkgx-install
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,4 @@ fi
eval "$(pkgx integrate)"

# install the project deps
eval "$(dev)"

# install the project node_modules
eval "$(bun install)"
eval "$(dev)"
Loading