2024February

Next.js Codebase Analysis <> create-next-app <> index.ts explained — Part 1.18

Finally, I am past the prompts you see when you enter npx create-next-app. In this article, I will talk about the createApp

try {
    await createApp({
      appPath: resolvedProjectPath,
      packageManager,
      example: example && example !== 'default' ? example : undefined,
      examplePath: program.examplePath,
      typescript: program.typescript,
      tailwind: program.tailwind,
      eslint: program.eslint,
      appRouter: program.app,
      srcDir: program.srcDir,
      importAlias: program.importAlias,
    })
  }

My first thought is that program variable has been updated with the responses you provide and is further used in createApp function as an argument.

I like the fact that it is a JSON object as an argument, a good thumb rule from clean code book is that your function can at most have 3 arguments, if you need more than 3 arguments, you might want to break down your function further or use an object like in this case.

createApp function:

createApp is an async function export from create-app.ts

export async function createApp({
  appPath,
  packageManager,
  example,
  examplePath,
  typescript,
  tailwind,
  eslint,
  appRouter,
  srcDir,
  importAlias,
}: { 
  // this can be defined as type in the same file at the top 
  // But that's fine assuming this is only the place it is used.
  appPath: string
  packageManager: PackageManager
  example?: string
  examplePath?: string
  typescript: boolean
  tailwind: boolean
  eslint: boolean
  appRouter: boolean
  srcDir: boolean
  importAlias: string
}): Promise<void> {
  let repoInfo: RepoInfo | undefined
  // there is mode derived from typescript flag
  const mode: TemplateMode = typescript ? 'ts' : 'js'
  // nested ternary? nice.
  // so there is two kinds of templates,
  // one with router and the other without
  const template: TemplateType = appRouter
    ? tailwind
      ? 'app-tw'
      : 'app'
    : tailwind
    ? 'default-tw'
    : 'default'

Conclusion:

I see that the argument type is defined next to argument without any explicit declaration of type somewhere at the top of the file, I would be okay with this assuming this type is not required else where in the codebase, otherwise I would write a type for this argument at the top of file and export it for reusability purposes.

Nested ternary, I don’t use that style much, but I can use it if the need be. I completely forgot we could do such a nested ternary, quite the reminder.

Get free courses inspired by the best practices used in open source.

About me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

I am open to work on interesting projects. Send me an email at ramu.narasinga@gmail.com

My Github —  https://github.com/ramu-narasinga

My website —  https://ramunarasinga.com

My Youtube channel —  https://www.youtube.com/@ramu-narasinga

Learning platform —  https://thinkthroo.com

Codebase Architecture —  https://app.thinkthroo.com/architecture

Best practices —  https://app.thinkthroo.com/best-practices

Production-grade projects —  https://app.thinkthroo.com/production-grade-projects

We use cookies
We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.

By clicking "Accept", you agree to our use of cookies.

Learn more