Skip to content
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
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
"integrity": "sha256:0c55e65f2e3df736e478f26ee4d5ed41bae6b54dac1318c443e31444c8ed283c"
}
}
}
}
60 changes: 59 additions & 1 deletion packages/create-next-app/create-app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable import/no-extraneous-dependencies */

import retry from 'async-retry'
import { copyFileSync, existsSync, mkdirSync } from 'node:fs'
import { copyFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs'
import { basename, dirname, join, resolve } from 'node:path'
import { cyan, green, red } from 'picocolors'
import type { RepoInfo } from './helpers/examples'
Expand Down Expand Up @@ -35,6 +36,7 @@ export async function createApp({
biome,
app,
srcDir,
mongodb,
importAlias,
skipInstall,
empty,
Expand All @@ -53,6 +55,7 @@ export async function createApp({
biome: boolean
app: boolean
srcDir: boolean
mongodb?: boolean
importAlias: string
skipInstall: boolean
empty: boolean
Expand Down Expand Up @@ -254,7 +257,62 @@ export async function createApp({
reactCompiler,
})
}
// --- MongoDB Logic Start ---
// --- MongoDB Change Start ---
if (mongodb) {
const dbFolderPath = join(root, 'lib')
const dbFilePath = join(dbFolderPath, typescript ? 'db.ts' : 'db.js')

if (!existsSync(dbFolderPath)) {
mkdirSync(dbFolderPath, { recursive: true })
}

const dbCode = `import { MongoClient } from 'mongodb'

if (!process.env.MONGODB_URI) {
throw new Error('Invalid/Missing environment variable: "MONGODB_URI"')
}

const uri = process.env.MONGODB_URI
const options = {}

let client: MongoClient
let clientPromise: Promise<MongoClient>

if (process.env.NODE_ENV === 'development') {
let globalWithMongo = global as typeof globalThis & {
_mongoClientPromise?: Promise<MongoClient>
}
if (!globalWithMongo._mongoClientPromise) {
client = new MongoClient(uri, options)
globalWithMongo._mongoClientPromise = client.connect()
}
clientPromise = globalWithMongo._mongoClientPromise
} else {
client = new MongoClient(uri, options)
clientPromise = client.connect()
}

export default clientPromise`

writeFileSync(dbFilePath, dbCode)

// Safely append to .env.local with proper casting
const fs = require('node:fs') as typeof import('node:fs')
const envPath = join(root, '.env.local')
const envContent = `\nMONGODB_URI=mongodb+srv://<username>:<password>@cluster.mongodb.net/myDatabase?retryWrites=true&w=majority\n`

if (fs.existsSync(envPath)) {
fs.appendFileSync(envPath, envContent)
} else {
fs.writeFileSync(envPath, envContent)
}

console.log(
`${green('Added')} MongoDB connection utility in ${cyan('lib/db.' + (typescript ? 'ts' : 'js'))}`
)
}
// --- MongoDB Logic End ---
if (disableGit) {
console.log('Skipping git initialization.')
console.log()
Expand Down
39 changes: 31 additions & 8 deletions packages/create-next-app/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/usr/bin/env node
/* eslint-disable import/no-extraneous-dependencies */
import { existsSync } from 'node:fs'
import { isFolderEmpty } from './helpers/is-folder-empty'
import ciInfo from 'ci-info'
import { Command } from 'commander'
import Conf from 'conf'
import { existsSync } from 'node:fs'
import { basename, resolve } from 'node:path'
import { blue, bold, cyan, green, red, yellow } from 'picocolors'
import type { InitialReturnValue } from 'prompts'
Expand All @@ -12,7 +13,6 @@ import updateCheck from 'update-check'
import { createApp, DownloadError } from './create-app'
import type { PackageManager } from './helpers/get-pkg-manager'
import { getPkgManager } from './helpers/get-pkg-manager'
import { isFolderEmpty } from './helpers/is-folder-empty'
import { validateNpmName } from './helpers/validate-pkg'
import packageJson from './package.json'
import { Bundler } from './templates'
Expand Down Expand Up @@ -109,6 +109,7 @@ const program = new Command(packageJson.name)
`
)
.option('--disable-git', `Skip initializing a git repository.`)
.option('--mongodb', 'Initialize with MongoDB connection logic.')
.action((name) => {
// Commander does not implicitly support negated options. When they are used
// by the user they will be interpreted as the positional argument (name) in
Expand Down Expand Up @@ -188,9 +189,11 @@ async function run(): Promise<void> {
)
process.exit(1)
}

const appPath = resolve(projectPath)
const appName = basename(appPath)
if (existsSync(appPath) && !isFolderEmpty(appPath, appName)) {
process.exit(1)
}

const validation = validateNpmName(appName)
if (!validation.valid) {
Expand All @@ -212,10 +215,7 @@ async function run(): Promise<void> {
)
process.exit(1)
}

if (existsSync(appPath) && !isFolderEmpty(appPath, appName)) {
process.exit(1)
}
// Inside the !example block where displayConfig is defined

const example = typeof opts.example === 'string' && opts.example.trim()
const preferences = (conf.get('preferences') || {}) as Record<
Expand All @@ -234,6 +234,7 @@ async function run(): Promise<void> {
const defaults: typeof preferences = {
typescript: true,
eslint: false,
mongodb: false,
linter: 'eslint',
tailwind: true,
app: true,
Expand All @@ -260,6 +261,7 @@ async function run(): Promise<void> {
{ key: 'tailwind', values: { true: 'Tailwind CSS' } },
{ key: 'srcDir', values: { true: 'src/ dir' } },
{ key: 'app', values: { true: 'App Router', false: 'Pages Router' } },
{ key: 'mongodb', values: { true: 'MongoDB', false: '' } },
]

// Helper to format settings for display based on displayConfig
Expand Down Expand Up @@ -442,9 +444,28 @@ async function run(): Promise<void> {
getPrefOrDefault('linter') as keyof typeof linterIndexMap
],
})

// MongoDB Prompt
if (!opts.mongodb && !args.includes('--no-mongodb') && !opts.api) {
if (skipPrompt) {
opts.mongodb = getPrefOrDefault('mongodb')
} else {
const mongoLabel = blue('MongoDB')
const { mongodb } = await prompts({
onState: onPromptState,
type: 'toggle',
name: 'mongodb',
message: `Would you like to use ${mongoLabel} connection?`,
initial: getPrefOrDefault('mongodb'),
active: 'Yes',
inactive: 'No',
})
opts.mongodb = Boolean(mongodb)
preferences.mongodb = Boolean(mongodb)
}
}
opts.eslint = linter === 'eslint'
opts.biome = linter === 'biome'

preferences.linter = linter

// Keep backwards compatibility with old eslint preference
Expand Down Expand Up @@ -606,6 +627,7 @@ async function run(): Promise<void> {
examplePath: opts.examplePath,
typescript: opts.typescript,
tailwind: opts.tailwind,
mongodb: opts.mongodb,
eslint: opts.eslint,
biome: opts.biome,
app: opts.app,
Expand Down Expand Up @@ -642,6 +664,7 @@ async function run(): Promise<void> {
typescript: opts.typescript,
eslint: opts.eslint,
biome: opts.biome,
mongodb: opts.mongodb,
tailwind: opts.tailwind,
app: opts.app,
srcDir: opts.srcDir,
Expand Down
Loading