Giter VIP home page Giter VIP logo

new-component's Introduction

new-component logo
npm

new-component

Simple, customizable utility for adding new React components to your project.

This project is a CLI tool that allows you to quickly scaffold new components. All of the necessary boilerplate will be generated automatically.

This project uses an opinionated file structure discussed in this blog post: Delightful React File/Directory Structure.

NOTE: This project is not actively maintained. I continue to use it in my own projects, but I don't have the bandwidth to review PRs or triage issues. Feel free to fork this project and tweak it however you wish. ❤️


Features

  • Simple CLI interface for adding React components.
  • Uses Prettier to stylistically match the existing project.
  • Offers global config, which can be overridden on a project-by-project basis.
  • Colourful terminal output!

Version 5: The new version adds support for TypeScript, and removes support for passing a custom file extension;

Quickstart

Install via NPM:

# Using Yarn:
$ yarn global add new-component

# or, using NPM
$ npm i -g new-component

cd into your project's directory, and try creating a new component:

$ new-component MyNewComponent

Your project will now have a new directory at src/components/MyNewComponent. This directory has two files:

// `MyNewComponent/index.js`
export { default } from './MyNewComponent';
// `MyNewComponent/MyNewComponent.js`
import React from 'react';

function MyNewComponent() {
  return <div></div>;
}

export default MyNewComponent;

These files will be formatted according to your Prettier configuration.


Configuration

Configuration can be done through 3 different ways:

  • Creating a global .new-component-config.json in your home directory (~/.new-component-config.json).
  • Creating a local .new-component-config.json in your project's root directory.
  • Command-line arguments.

The resulting values are merged, with command-line values overwriting local values, and local values overwriting global ones.


API Reference

Language

Controls which language, JavaScript or TypeScript, should be used.

  • js — creates a .js file (default).
  • ts — creates a .tsx file.

Note that all components created will be functional components. Class components are not supported.

Usage:

Command line: --lang <value> or -l <value>

JSON config: { "lang": <value> }

Directory

Controls the desired directory for the created component. Defaults to src/components

Usage:

Command line: --dir <value> or -d <value>

JSON config: { "dir": <value> }

Platform Support

This has only been tested in macOS. I think it'd work fine in linux, but I haven't tested it. Windows is a big question mark.

Development

To get started with development:

  • Fork and clone the Git repo
  • cd into the directory and install dependencies (yarn install or npm install)
  • Set up a symlink by running npm link, while in the new-component directory. This will ensure that the new-component command uses this locally-cloned project, rather than the global NPM installation.
  • Spin up a test React project.
  • In that test project, use the new-component command to create components and test that your changes are working.

new-component's People

Contributors

joeldbirch avatar joshwcomeau avatar lb- avatar morajabi 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

new-component's Issues

Shorter type names

Now that I've used this for a while, I find it surprisingly taxing to type out -t functional, or -t pure-class.

Maybe we could shorten them to -t func and -t pure.... or maybe even just -t f and -t p? All of the above?

Open for discussion! cc @morajabi

Creating a component with hyphens generates an error

At the moment if we give a name with hyphens the CLI returns an error.
For example, at the moment this :

new-component a-component-with-hyphens

will return this kind of error:

SyntaxError: Unexpected token, expected "(" (3:12)
  1 | import React from 'react';
  2 |
> 3 | function a-component-with-hyphens() {
    |            ^
  4 |   return <div></div>;
  5 | }
  6 |
etc..

At the same time this commands will work, but will create the folder, the file and the function with the name provided:

new-component a_component_with_underscores
new-component aCamelCaseComponent
new-component "a component with spaces" # this will actually give you an error

I think this is a problem that could be easily solved
I'm already working on a fix to try to standardize any of this examples to a PascalCase convention.
Will send you a Pull Request as soon as I finish testing it.

Add support for various styling solutions

It'd be awesome if new-component could include base styling.

There are two issues here: Coming up with the individual templates for each style solution, as well as the underlying architecture changes to make this possible.

Templates by style solution

styled-components

For styled-components, I spoke with Max on twitter and we think the best solution would be to update the template to be something like this:

// Whatever.js
import React, { Component } from 'react';
import styled from 'styled-components';

class Whatever extends Component {
  render() {
    return <Wrapper />;
  }
}

const Wrapper = styled.div`

`;

export default Whatever;

A near-identical template could be used for emotion (literally just swapping out styled-components for emotion/react, in the import line.

CSS modules

For CSS modules, the JS template would need to be updated to something like this:

// Whatever.js
import React, { Component } from 'react';

import styles from './Whatever.css';

class Whatever extends Component {
  render() {
    return <div className={styles.wrapper} />;
  }
}

export default Whatever;

We'd also need the CSS file, but it can be super minimal:

// Whatever.css
.wrapper {

}

Aphrodite

Finally, given that I work at KA, I'd like to add Aphrodite support! it would look like something of a mix of these earlier two solutions (all defined in the JS file, but using className and a styles object)


Architecture Changes

It actually seems like a pretty hard problem, figuring out how to add these new templates in a sustainable way. Because we support 3 different kinds of components (class, pure, functional), ideally I don't want to have to create 3 * 4 templates, for each possible permutation.

Thinking off the top of my head... One idea is to split the template into "quadrants", little mix-and-match pieces. You'd assemble the final template by picking the pieces you need, based on the type of component and style solution.

I imagine the different "areas" are:

  • React imports
  • Style imports
  • component definition
  • component render contents
  • below-component footer (for stuff like const Wrapper = styled.div)
  • exports (export default Whatever)

Here's a very rough first pass (this could be all wrong, just going with an idea :) )

// templates/react-imports.js
export default {
  functional: "import React from 'react';"
  class: "import React, { Component } from 'react';"
};

// templates/style-imports.js
export default {
  'styled-components': "import styled from 'styled-components';",
};

// templates/render-contents.js
export default {
  'styled-components': "<Wrapper />",
};

// templates/component-definition.js
// NOTE: This one is a bit tricky, since the `render-contents` are within it.
// Maybe something like this?

export default {
  // NOTE: ignore the spaces between ` ` `. Just not sure how to escape in markdown.
  functional = (ComponentName, renderContents) => ` ` `
    const ${ComponentName} = (
      return ${renderContents}
    );
  ` ` `
}

And then you'd just combine them to create the actual template:

import reactImportTemplates from './templates/react-imports';
import styleImportTemplates from './templates/style-imports';
import renderContentTemplates from './templates/render-contents';
import componentDefinitionTemplates from './templates/component-definition';

// Pretend these vars are defined from program input args
const componentName = 'Whatever';
const componentType = 'class';
const style = 'styled-components';

const renderContents = renderContentTemplates[style];

return ` ` `
${reactImportTemplates[componentType]}
${styleImportTemplates[style]}

${componentDefinitionTemplate[componentType](componentName, renderContents)}
` ` `;

This is of course a very rough draft, haven't thought through all the implications. Happy to discuss!

Going forward, I don't anticipate having that much time to spend on this (currently deeply involved in another side project, + my day job), so if anyone wanted to take this on, that'd be awesome. I want this to be a community project! Otherwise, I'll do my best to get to this in the next month or two :)

Handle sub directories in component names

You might want to use a more complex tree to handle creating components.

example:

src/ 
  components/
    admin/

You get the following error if trying to provide a path in your component name and the path does not (yet) exist.

ryan@tbp dev/proj (master) » new-component subdir/TestComponent


✨  Creating the subdir/TestComponent component ✨


Directory:  src/components/subdir/TestComponent
Type:       class  functional  pure-class
=========================================


{ Error: ENOENT: no such file or directory, mkdir 'src/components/subdir/TestComponent'
  errno: -2,
  code: 'ENOENT',
  syscall: 'mkdir',
  path: 'src/components/subdir/TestComponent' }
ryan@tbp dev/proj (master) »

... and the following error if path already exists.

ryan@tbp dev/proj (master) » mkdir src/components/admin
ryan@tbp dev/proj (master) » new-component admin/TestComponent


✨  Creating the admin/TestComponent component ✨


Directory:  src/components/admin/TestComponent
Type:       class  functional  pure-class
=========================================


✓ Directory created.
{ SyntaxError: Unexpected token, expected { (4:12)
  2 |
  3 |
> 4 | class admin/TestComponent extends Component {
    |            ^
  5 |   render() {
  6 |     return <div />;
  7 |   }
    at createError$1 (/Users/ryan/.nvm/versions/node/v8.2.1/lib/node_modules/new-component/node_modules/prettier/parser-babylon.js:1:112)
    at parse (/Users/ryan/.nvm/versions/node/v8.2.1/lib/node_modules/new-component/node_modules/prettier/parser-babylon.js:1:681)
    at Object.parse (/Users/ryan/.nvm/versions/node/v8.2.1/lib/node_modules/new-component/node_modules/prettier/index.js:3491:12)
    at formatWithCursor (/Users/ryan/.nvm/versions/node/v8.2.1/lib/node_modules/new-component/node_modules/prettier/index.js:13697:22)
    at format (/Users/ryan/.nvm/versions/node/v8.2.1/lib/node_modules/new-component/node_modules/prettier/index.js:13737:10)
    at Object.format (/Users/ryan/.nvm/versions/node/v8.2.1/lib/node_modules/new-component/node_modules/prettier/index.js:13945:12)
    at text (/Users/ryan/.nvm/versions/node/v8.2.1/lib/node_modules/new-component/src/helpers.js:65:12)
    at mkDirPromise.then.then.then.then.template (/Users/ryan/.nvm/versions/node/v8.2.1/lib/node_modules/new-component/src/index.js:100:32)
    at <anonymous>
  loc: { start: { line: 4, column: 12 } },
  codeFrame: '\u001b[0m \u001b[90m 2 | \u001b[39m\n \u001b[90m 3 | \u001b[39m\n\u001b[31m\u001b[1m>\u001b[22m\u001b[39m\u001b[90m 4 | \u001b[39m\u001b[36mclass\u001b[39m admin\u001b[33m/\u001b[39m\u001b[33mTestComponent\u001b[39m \u001b[36mextends\u001b[39m \u001b[33mComponent\u001b[39m {\n \u001b[90m   | \u001b[39m           \u001b[31m\u001b[1m^\u001b[22m\u001b[39m\n \u001b[90m 5 | \u001b[39m  render() {\n \u001b[90m 6 | \u001b[39m    \u001b[36mreturn\u001b[39m \u001b[33m<\u001b[39m\u001b[33mdiv\u001b[39m \u001b[33m/\u001b[39m\u001b[33m>\u001b[39m\u001b[33m;\u001b[39m\n \u001b[90m 7 | \u001b[39m  }\u001b[0m' }
ryan@tbp dev/proj (master) »

Add "Undo" functionality

Often, I'll realize right after creating a component that I did it wrong.

Maybe I meant to make a functional component, but forgot the flag. Maybe I realized it has the wrong name (or I typo'ed the name).

Right now the solution is rm -rf src/components/ThingYouJustCreated, which is a little burdensome, and I worry I might make a mistake with that and delete the wrong thing.

I think it'd be neat if you could do:

$ new-component-undo

This will delete the component 'ThingYouJustCreated`. 
Press enter to continue, or any other key to cancel.

Calling new-component with no arguments creates 'undefined' component

When running the command with no arguments, it creates a component named undefined.

ryan@tbp dev/proj (master) » new-component


✨  Creating the undefined component ✨


Directory:  src/components/undefined
Type:       class  functional  pure-class
=========================================


✓ Directory created.
✓ Component built and saved to disk.
✓ Index file built and saved to disk.


Component created! 🚀
Thanks for using new-component.


ryan@tbp dev/proj (master %) » git status
On branch master
Your branch is up-to-date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	src/components/undefined/

nothing added to commit but untracked files present (use "git add" to track)
ryan@tbp dev/proj (master %) »

Prettier

Now that we have outside contributors (thanks @morajabi!), I think it'd be good to add a code-formatting tool like Prettier. That way there's no need for style-based nits in code reviews.

I think Prettier is the clear head-of-the-pack, and it should be really easy to implement. If anyone has thoughts about alternatives, though, don't be shy!

More file types (Typescript) and potential for scaffolding more files

Hey, first of all, thanks for open sourcing this!

I got curious about it, but the first "blocker" is that I typically work in .tsx-files and it would be great to scaffold those from scratch. Would you be interested in a PR that adds a flag for Typescript, or would I be better off forking than bloating a JS-centered tool? (1)

Further, most of my work happens in a redux context, so it would be cool to be able to optionally spin up a componentname.reducer.fileending as well as a (we are nearing very opinionated territory here) componentname.container.fileending. (2)

Finally, I typically work in a SCSS modules context, so the ability to scaffold a (.module.).(s)css-file would be nice as well! But again, this might be beyond the scope of this repo and its better off as a fork. (3)

Happy to look into implementing any of the above based on my availability and your preferences.

yarn add global doesn't add the new-component command

When I try and do yarn global add new-component and run the new-component command, it results in the following error:

new-component : The term 'new-component' is not
recognized as the name of a cmdlet, function,
script file, or operable program. Check the
spelling of the name, or if a path was
included, verify that the path is correct and
try again.
At line:1 char:1

  • new-component Title
  •   + CategoryInfo          : ObjectNotFound: (  
     new-component:String) [], CommandNotFoundEx   
    ception
      + FullyQualifiedErrorId : CommandNotFoundEx  
     ception
    
    

Using windows 10 platform for this.

Breaks Prettier formatting

I could be wrong but I think new-component is using an outdated version of Prettier. When I installed it, auto-formatting stopped working.

Choose js vs jsx

I'm working with Vite and it seems to not allow jsx in js files. I'd be happy to add, maybe an '-x' flag to create files as jsx.
I see an earlier version had something similar to this. Wondering if your open to putting something similar to what was (but more focused) back in.

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.