Skip to content

Add support for various styling solutions #4

Open
@joshwcomeau

Description

@joshwcomeau

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 :)

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions