Giter Site home page Giter Site logo

create-create-app's Introduction

✨ Create Create App

Create your own `create-something` app.

screenshot

Why?

  • ⚖️ Built-in License selector No need to worry about license things.
  • 🎩 Template engine You can use template strings in text files, file names, and folder names.
  • 💄 Highly customizable Can change caveat text, add extra command-line options.

Table of contents

Quick Start

Let's create create-greet package in five steps.

1. Bootstrap your project

npx create-create-app greet  # simplest route
npm init create-app greet    # requires npm 6+
yarn create create-app greet # requires Yarn 0.25+

You will then be asked about your project.

screenshot

2. Add and edit template files

cd create-greet

Then you can see the templates/default folder where the actual template files go.

Note that .gitignore files should be named gitignore to avoid being ignored on publishing.

3. Build the app (TypeScript only)

Run npm run build or yarn build to transpile TypeScript code into JavaScript. If you chose the default template, this step is not necessary.

4. Publish package to npm

Run npm publish or yarn publish to publish your create-greet app to npm.

5. PROFIT

npx create-greet ohayo
npm init greet ohayo
yarn create greet ohayo

screenshot

Template

Edit files inside templates/default. Every file name, directory name, and a text file will be processed through Handlebars template engine to replace all template strings with the respective value.

Built-in variables are:

  • {{name}} package name (e.g. ohayo)
  • {{description}} package description
  • {{author}} author name (e.g. John Doe)
  • {{email}} author email (e.g. [email protected])
  • {{contact}} author name formatted with {{name}} <{{email}}>. If email is missing, simply {{name}}
  • {{license}} package license (e.g. MIT)
  • {{year}} current year (e.g. 2021)
  • {{template}} selected template name (e.g. typescript`)
  • {{packageManager}} package manager (e.g. yarn`)

Advanced: Multiple templates

Creates a new directory in the location defined by templateRoot. It can be accessed via --template flag (e.g. create-something <name> --template <template>). You might want to set promptForTemplate to true to explicitly ask the user to choose a template during the initialization phase. If promptForTemplate is false, which is the default behavior, default template will be used unless the user explicitly selects a template via --template cli flag.

Helper functions

In the following example, we assume that the variable name is create-react-app.

upper

Convert text to UPPERCASE.

{{upper name}} becomes CREATE-REACT-APP.

lower

Convert text to lowercase.

{{lower name}} becomes create-react-app.

capital

Convert text to CapitalCase.

  • {{capital name}} becomes CreateReactApp
  • {{capital name space=true}} becomes Create React App.

camel

Convert text to camelCase.

{{camel name}} becomes createReactApp.

snake

Convert text to snake_case.

{{snake name}} becomes create_react_app.

kebab

Convert text to kebab-case.

{{kebab name}} becomes create-react-app.

space

Replace all word separators with single space.

{{space name}} becomes create react app

uuid

Generates unique UUID string.

{{uuid}} // => a5df7100-da46-47a6-907e-afe861f48b39
{{upper (uuid)}} // => A5DF7100-DA46-47A6-907E-AFE861F48B39

Config

The app configuration can be found in src/cli.js (or src/cli.ts if you choose the typescript template).

import { resolve } from 'path';
import { create } from 'create-create-app';

create('create-greet', {
  templateRoot: resolve(__dirname, '..', 'templates'),
  extra: {
    language: {
      type: 'input',
      describe: 'greeting language',
      default: 'en',
      prompt: 'if-no-arg',
    },
  },
  modifyName: (name) => `package-prefix-${name}`,
  after: async ({ installNpmPackage }) => {
    console.log('Installing additional packages');
    await installNpmPackage('chalk');
  },
  caveat: `Your app has been created successfully!`,
});

templateRoot (required)

templateRoot is set to path.resolve(__dirname, '../templates'). You can change this to any location you like.

modifyName (default: undefined)

(name: string) => string | Promise<string>

Modify name property.

{
  modifyName: (name) => (name.startsWith('create-') ? name : `create-${name}`);
}

extra (default: undefined)

object | undefined

Additional questions can be defined. These options will be available as CLI flags, interactive questions, and template strings. In the example above, --language flag and the {{language}} template string will be enabled in the app.

All possible options can be found in the yargs-interactive documentation.

defaultDescription (default: description)

Default value for a package description.

defaultAuthor (default: user.name in ~/.gitconfig otherwise Your name)

Default value for a package author.

defaultEmail (default: user.email in ~/.gitconfig otherwise Your email)

Default value for a package author email.

defaultTemplate (default: default)

Default value for a template.

defaultLicense (default: MIT)

Default value for license.

defaultPackageManager (default: undefined)

Default value for package manager. npm, yarn and pnpm are available. undefined to auto detect package manager.

promptForDescription (default: true)

Interactively asks users for a package description.

promptForAuthor (default: true)

Interactively asks users for a package author.

promptForEmail (default: true)

Interactively asks users for a package author email.

promptForTemplate (default: false)

Interactively asks users to select a template. If there are no multiple templates in the templates directory, it won't display a prompt anyways.

Even if promptForTemplate is set to false, users can still specify a template via a command line flag --template <template>.

create-something <name> --template <template>

promptForLicense (default: true)

Interactively asks users for a package license.

promptForPackageManager (default: false)

Interactively asks users for a package manager to use for installing packages from npm.

skipGitInit (default: false)

Skip initializing a git repository at a creation time.

skipNpmInstall (default: false)

Skip installing package dependencies at a creation time.

after (default: undefined)

(options: AfterHookOptions) => void

Define after-hook script to be executed right after the initialization process.

caveat (default: undefined)

string | ((options: AfterHookOptions) => string | void) | undefined

The caveat message will be shown after the entire process is completed.

create('create-greet', {
  caveat: 'Happy coding!',
});
create('create-greet', {
  caveat: ({ answers }) => `Run -> cd ${answers.name} && make`,
});
create('create-greet', {
  extra: {
    plugin: {
      type: 'input',
      describe: 'plugin to be used in your project',
      default: 'some-plugin',
      prompt: 'if-no-arg',
    },
  },
  after: async ({ installNpmPackage, answers }) => {
    const plugin = answers.plugin;
    console.log(`Installing additional package: ${plugin}`);
    await installNpmPackage(plugin);
  },
  caveat: ({ packageDir }) => {
    console.log('Next step:');
    console.log(`cd ${packageDir} && npm start`);
  },
});

AfterHookOptions

{
  // variables
  name: string; // e.g. "create-greet"
  template: string; // e.g. "default"
  packageDir: string; // e.g. "/path/to/ohayo"
  templateDir: string; // e.g. "/path/to/create-greet/templates/default"
  year: number; // e.g. 2020
  answers: {
    name: string; // package name passed through `modifyName`
    description: string; // description
    author: string; // e.g. "John Doe"
    email: string; // e.g. "[email protected]"
    contact: string; // e.g. "John Doe <[email protected]>"
    license: string; // e.g. "MIT"
    [key: string]: string | number | boolean | any[]; // any values defined in the `extra` field.
  };

  // helper functions
  run: (command: string, options?: CommonOptions<string>) => ExecaChildProcess<string>; // execute shell commands in the package dir
  installNpmPackage: (packageName: string | [string], isDev?: boolean) => Promise<void>; // install npm package. uses package manager specified by --node-pm CLI param (default: auto-detect)
}

Showcase

List of amazing projects built with create-create-app.

Missing your project? Send a PR :)

Contribution

PRs are always welcomed.

Contributors ✨

Thanks goes to these wonderful people (emoji key):


uetchy

💻 📖

Shinyu Murakami

💻

Masayoshi Takahashi

💻

Alexander Liu

💻

Vilja

💻

Lucas Colombo

💻

This project follows the all-contributors specification. Contributions of any kind welcome!

create-create-app's People

Contributors

alexanderl19 avatar allcontributors[bot] avatar classicoldsong avatar ivilja avatar lucas-labs avatar murakamishinyu avatar takahashim avatar uetchy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

create-create-app's Issues

github action file `hashFiles()`

Error

Parse error on line 46:
...{{ runner.os }}-${{ hashFiles('**/packag
-----------------------^
Expecting 'ID', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'INVALID'

hashFiles() is github action function

https://docs.github.com/en/actions/learn-github-actions/expressions#hashfiles

How to reproducing

add .github/workflows/unit-test.yml in template/default

write this in any github action template.

      - name: Restore cache
        uses: actions/cache@v3
        with:
          path: |
            node_modules
          key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
          restore-keys: |
            ${{ runner.os }}-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-

I think ignore glob pattern is needed.

Expose package manager variable in AfterHookOptions

Quality of life feature for displaying commands in caveat text.
Would support use cases such as https://github.com/vercel/next.js/blob/0cb2037a41c27d4ced57b5479e27edf96f748083/packages/create-next-app/create-app.ts#L308-L326.

packageManager variable in AfterHookOptions:

{
  // variables
  packageManager: string,
  ...
}

or with a helper function

{
  ...
  // helper functions
  npmCommand: (command: string) => string; // returns npm command text. uses package manager specified by --node-pm CLI param (default: npm)
}

Find alternative for unmaintained `gitconfig` dependency

I'm getting this warning

warning create-kolmafia-script > create-create-app > gitconfig > argx > iftype > babel-runtime > [email protected]: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.

gitconfig seems to be unmaintained, so will probably not be fixing that issue any time soon. I know this isn't really an issue but it's causing confusion for my users.

Expose package manager to AfterHookOptions

I'd like to give some aftercare for running create, for example

Go to the directory and run `npm run build` to finish!

However, I can't tell from that after hook what the user has used for their package manager.

Not working

Creating a new package in /home/z/disk/repos/packages/npm/create-npm-card/hehe.

Parse error on line 937:
...ediately following "\{{" ([@dmarcotte](h
-----------------------^
Expecting 'CLOSE_RAW_BLOCK', 'CLOSE', 'CLOSE_UNESCAPED', 'OPEN_SEXPR', 'CLOSE_SEXPR', 'ID', 'OPEN_BLOCK_PARAMS', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'INVALID'


Error: Parse error on line 937:
...ediately following "\{{" ([@dmarcotte](h
-----------------------^
Expecting 'CLOSE_RAW_BLOCK', 'CLOSE', 'CLOSE_UNESCAPED', 'OPEN_SEXPR', 'CLOSE_SEXPR', 'ID', 'OPEN_BLOCK_PARAMS', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'INVALID'
    at Parser.parseError (/home/z/disk/repos/packages/npm/create-npm-card/node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:267:19)
    at Parser.parse (/home/z/disk/repos/packages/npm/create-npm-card/node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:336:30)
    at parseWithoutProcessing (/home/z/disk/repos/packages/npm/create-npm-card/node_modules/handlebars/dist/cjs/handlebars/compiler/base.js:46:33)
    at HandlebarsEnvironment.parse (/home/z/disk/repos/packages/npm/create-npm-card/node_modules/handlebars/dist/cjs/handlebars/compiler/base.js:52:13)
    at compileInput (/home/z/disk/repos/packages/npm/create-npm-card/node_modules/handlebars/dist/cjs/handlebars/compiler/compiler.js:508:19)
    at ret (/home/z/disk/repos/packages/npm/create-npm-card/node_modules/handlebars/dist/cjs/handlebars/compiler/compiler.js:517:18)
    at T (/home/z/disk/repos/packages/npm/create-npm-card/node_modules/create-create-app/lib/chunk.PN6R6NCW.js:1:2328)
    at L (/home/z/disk/repos/packages/npm/create-npm-card/node_modules/create-create-app/lib/chunk.PN6R6NCW.js:1:2836)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Ie (/home/z/disk/repos/packages/npm/create-npm-card/node_modules/create-create-app/lib/chunk.PN6R6NCW.js:3:4)


# Environment
- create-create-app: 7.1.0
- System > OS: Linux 5.16 Arch Linux
- Binaries > Node: 17.7.2 - /bin/node

Steps to reproduce

  1. Clone https://github.com/UltiRequiem/create-npm-card
  2. npm run build
  3. node dist/cli.js

Issues with clean

When I've run a dry publish with a generated initializer, the clean command was broken. I've proposed a fix for it : #45

Cannot read property 'filename' of undefined

Hi, I'm using v7.3.0, and encountering an error "Cannot read property 'filename' of undefined" - it looks like it's related to the epicfail check for 'require.main!.filename' in the create function. The Node docs say that when the entry point is not a CommonJS module, require.main is undefined -- and the entry point of my app is a module, not cjs.

Is there any way around this issue?

I went back to v7.1.0 and everything works. But there's been some nice additions since then, and I'd love to use the latest version.

Thanks!

Test

Add test for continuous integration.

Prefer `pnpm` if available

Could you add pnpm if available? or can choose like pkgManager: ['pnpm','yarn','npm'] in config

It could be in the settings. or ask the user depending on what options you have installed on your system

Dissolve templateRoot into options

create('create-app', resolve(__dirname, '../templates'), {
  caveat: '',
  extra: {}
});

into this:

create('create-app', {
  templateRoot: resolve(__dirname, '../templates'),
  caveat: '',
  extra: {}
});

Readable error message

while running my create-app with a new template I created I get this error

Parse error on line 50:
...d. For example, `{{a}` will match `['{',
-----------------------^
Expecting 'CLOSE_RAW_BLOCK', 'CLOSE', 'CLOSE_UNESCAPED', 'OPEN_SEXPR', 'CLOSE_SEXPR', 'ID', 'OPEN_BLOCK_PARAMS', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', 'SEP', got 'INVALID'

Error: Parse error on line 50:
...d. For example, `{{a}` will match `['{',
-----------------------^
Expecting 'CLOSE_RAW_BLOCK', 'CLOSE', 'CLOSE_UNESCAPED', 'OPEN_SEXPR', 'CLOSE_SEXPR', 'ID', 'OPEN_BLOCK_PARAMS', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', 'SEP', got 'INVALID'
    at Parser.parseError (C:\dev\create-create-app\node_modules\handlebars\dist\cjs\handlebars\compiler\parser.js:267:19)
    at Parser.parse (C:\dev\create-create-app\node_modules\handlebars\dist\cjs\handlebars\compiler\parser.js:336:30)
    at parseWithoutProcessing (C:\dev\create-create-app\node_modules\handlebars\dist\cjs\handlebars\compiler\base.js:46:33)
    at HandlebarsEnvironment.parse (C:\dev\create-create-app\node_modules\handlebars\dist\cjs\handlebars\compiler\base.js:52:13)
    at compileInput (C:\dev\create-create-app\node_modules\handlebars\dist\cjs\handlebars\compiler\compiler.js:508:19)
    at ret (C:\dev\create-create-app\node_modules\handlebars\dist\cjs\handlebars\compiler\compiler.js:517:18)
    at Q (C:\dev\create-create-app\lib\index.js:1:3869)
    at ie (C:\dev\create-create-app\lib\index.js:1:4383)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Be (C:\dev\create-create-app\lib\index.js:2:52)
I guess I have a problem in one of the template files, but which one ?
I wanted to catch this error and issue a clearer message bout couldn't manage to launch create(-create)-app with a debugger...
Is there a launch.json configuration for VSCode that would work ?

`.gitignore` does not get copied from template

npm init create-app won't copy the .gitignore files from the templates into the generated packages.

It is caused by the fact that when you publish a NPM package, .gitignore files are ignored. (npm/npm#3763)

One workaround is to use a file like gitignore and copy it to .gitignore when doing generation.

npm publish doesn't change npm create templates

I updated the templates/ with create-book using create-create-app and then npm pulish, but the one generated by running npm create book is still the old templates.

Is there anything else need to do to update the image run by npm create other than npm publish?

README.md explains that npm publish is running.

3. Publish package to npm

Run npm publish or yarn publish to publish your create-greet app to npm.

When I installed the published one with npm i create-book, npm was up to date.

Question for you

Hey!

Question for ya.
Think you could Answer this for me Real Quick?
If you don't mind.

First off sorry to create an issue but I'm not sure how else to connect and communicate about the project and goals of creating something more.

I really could use your help.

If you would take me under your wing to help me run this and put it in an emulator to further understand this and visually see what a bunch of code can become.

I've been stuck for days trying to figure out how to do this

Thanks

~EASTinphectiON

allow to use UNLICENSED for license

I would like to create private apps using this tool, especially with vivliostyle/create-book.

In documents of npm, we can use { "license": "UNLICENSED" } for private packages. So I think it would be a good idea to support this specification in create-create-app as well.

Consideration:

  • Should we support this feature in default, or using extra arguments in create()?
  • When choosing UNLICENSED, should we also add {"private": true} in package.json?

Fails on Windows when Yarn is not installed

Testing on Windows, without Yarn installed,

C:\Users\Shinyu>npm create create-app testapp
? description description
? author name MurakamiShinyu
? author email [email protected]
? template default
? license AGPL-3.0

Creating a new package in C:\Users\Shinyu\create-testapp.

Installing dependencies.
npm ERR! code ENOLOCAL
npm ERR! Could not install from "" as it does not contain a package.json file.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Shinyu\AppData\Roaming\npm-cache\_logs\2020-08-10T04_11_07_268Z-debug.log
installDeps failed: 1

I found that this problem happens when the npm install command is called with a --prefix option,

command = 'npm';
args = ['install', '--prefix', rootDir];

and npm has the following bug:

  • npm/cli#1290 [BUG] Npm install with --prefix does not work on Windows

Also in Stackoverflow: NPM prefix flag does not work as expected on windows

Add `welcome` option to complement `caveat`

It would be good to add some introductory messaging if possible. I know this can be done just by console.logging separately, but it would be useful to have access to any answers that have already been provided via a CLI arg (a la AfterHookOptions) too.

feat: Access `answers` in `extras` for conditional prompts

Hi, thanks for creating and maintaining this project, it's really neat!

There is one thing blocking me from using this project - I would like to be able to reference the answers object inside of subsequent questions, so that I can determine which prompts to ask based on the previous answers.

If there is a way to do this with the current API please let me know. If it would be possible to make prompt a function that returns the current answers, then the value of prompt can be determined programatically.

Example:

create('create-example-app', {
  templateRoot,
  extra: {
    firstPrompt: {
      type: 'list',
      describe: 'choose your answer',
      choices: ['One', 'Two'],
      prompt: 'if-no-arg',
    },
    conditionalPrompt: {
      type: 'list',
      describe: 'Choose the next answer if the first answer was One',
      choices: ['Three', 'Four'],
      prompt:  (answer) => {
        if (answer === 'One') {
          return 'if-no-arg'
        } else {
          return 'never'
        }
    },
  },
  after: ({ answers }) => console.log(`Ok you chose ${answers}.`),
  caveat,
});

Please let me know if this is something worth implementing, I would like to help implement it if possible. Thanks!

Accessing selected package manager in caveat

Hello,
I'm using a function for caveat to list all possible commands, exactly like create-create-app does itself.
I can easily access the template and name in there through AfterHookOptions, but I cannot get what package manager was selected.
This means I have to either show only npm run dev or options for all package managers. Instead, I'd like to show e.g. yarn dev if the user selected yarn as the package manager.

Skip install? template variables in file names?

Hi! Thanks for sharing this great library.

I would like to ask two questions:

  1. Is it possible to skip npm install at the end of the creation? If the template has a package.json, at the end of the creation process, it will automatically install packages. Is there any way to avoid package install?

  2. Is it possible to use variables for file names? I'm trying to do this but something weird happens:

This is my template folder with a variable on one filename.
image

This results in the following output. Notice that test is appended at the start of the filename, and also, the file is not even inside the created folder, but one directory behind.

image

Thanks!!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.