You Should be Using Folder Components

Give your components their own folder. They deserve it.

Izaak Schroeder
Dec 4, 2018 · 3 min read

There are some compelling reasons that every component you write should have the following structure:

src/ 
  component/
    category/
      ComponentName/
        index.js
        ComponentName.js

With the index.js file containing the following:

export {default} from './ComponentName.js';

Although it’s a little bit annoying to have to make an extra file for every component the tradeoff is worth it. You get consistency, free aliasing, fuzzy finder friendliness and the extra file will get optimized away by the compiler when you build for production anyway.

If you have components that require additional assets like images you don’t have some components in folders and some not:

src/
  component/
    category/
      ComponentA.js
      ComponentB/index.js
      ComponentB/ComponentB.js
      ComponentB/image.jpg

Since many tools sort by folder first and then alphabetically this also ensures your list of components is actually sorted correctly.

Atom sorts by folder and then alphabetically.

Because you have an index.js file that just exports the component you can redirect or rewrite that component elsewhere if you need to. For example, when doing A/B testing your index file can look like this:

import ComponentB from './ComponentB';
import NewComponentB from '...';import Experiment from '/component/util/Experiment';export default (props) => (
  <Experiment>
    {({useNewB}) => useNewB ? 
      <NewComponentB {...props} /> : <ComponentB {...props} />
    )}
  </Experiment>
);

You can also do things like use index.js for chunk splitting:

import Loadable from 'react-loadable';
import Loading from '...';

export default Loadable({
  loader: () => import('./ComponentB'),
  loading: Loading,
});

This pattern, in general, keeps the original component free of any “utility” side effects that otherwise don’t modify the component’s core behaviour.

Because your main component is in a file called Component/Component.js using a fuzzy finder for Component will bring up the correct result instead of trying to find the correct index.js file.

Fuzzy finder is happy.

As long as you have your babel preset set to modules: false and are using webpack@4 the duplicate export will be collapsed in production mode thanks to optimization.concatenateModules. You can read more about this here:

Roughly in development mode, for a component named ComponentName, you’ll see something like:

/***/ "./src/component/example/ComponentName/ComponentName.js":
/*!********************************!*\
  !*** ./src/component/example/ComponentName/ComponentName.js ***!
  \********************************/
/*! exports provided: default */// .../***/ "./src/component/example/ComponentName/index.js":
/*!******************************!*\
  !*** ./src/component/example/ComponentName/index.js ***!
  \******************************/
/*! exports provided: default */

And in production all of that will be gone and you’ll be left with a single variable declaration pointing to your component without any exports or imports or module wrappers.

Remember that friendly index.js file? It means that consumers of your component don’t have to write any more than necessary when importing.

import ComponentName from '/component/category/ComponentName';

They don’t have to append an extra ComponentName/ComponentName since the index.js file is used automatically for folders. If you’re using webpack you could probably write a custom webpack resolver to make webpack search for ComponentName.js instead of index.js in folders, but this breaks a lot of existing tools like flow which rely on the pre-existing index.js behaviour.

There’s no reason not to‡. Don’t be malignantly lazy. Give components a place they’ll be happy. Give them their own folder and a friendly index.js file for company. Use folder components on your next project. 🙏

‡ May be some reasons not to.

Bootstart

This will go.

1

1 clap
Izaak Schroeder

Written by

Things.

Bootstart

Bootstart

This will go.