mui / mui/material-ui

[RFC] Avoid or "prefer not to use" default exports

Open
#21,862 34 comments 37 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

discussion RFC scope: all components v6.x
Dominant language
JavaScript
Stars
99.1k
Forks
32.5k
Avg merge
2d 17h
Merged PRs (30d)
106

Description

Introduction

This discussion was initiated during the migration of eslint configs of material-ui/pickers and convention and code style consolidation. (https://github.com/mui-org/material-ui-pickers/pull/2004)

The problem

The core repository is using export default everywhere as a primary way to export React components. This RFC is about why it is not the best approach – the main problem of the default exports is implicit renames. And this unexpected renames leads to the following problems:

Consistent naming between all files

When export default is used it allows anonymous renames on the importing side:

export default function Modal() {
... 
}

// importing file
import Dialog from '../..'

Here it appeared that the component that has displayName="Modal" and actually is a Modal in the code reads like Dialog which is weird because it has its own defined name. This can also lead to the discrepancy between the component name in the component and display name in the dev tools.

Problems with refactoring

If we have an allowed implicit rename it could be tricky to find all the places when the component is used. And automated refactoring will also do nothing because rename is totally allowed

Make sure that for named exports there is a strong AST link for the rename import { Modal as Dialog } which is simplifying refactoring and make any rename explicit

Poor importing experience

Discoverability is very poor for default exports. You cannot explore a module with IntelliSense to see if it has a default export or not. With export default, you get nothing here (maybe it does export default / maybe it doesn't (¯_(ツ)_/¯). And also it doesn't autocomplete by the component name, while for named exports – it does.

import /* here */ from 'something';

Without export default you get a nice intellisense here:

import { /* here */ } from 'something';
More solid imports section

When there are no default exports through the codebase

import * as React from 'react'; 
import Typography from './somewhere' 
import { util } from './somewhereElse'
import Default, { andSomething } from '../'

Without

import * as React from 'react'; 
import { Typography }  from './somewhere' 
import { util } from './somewhereElse'
import { Default, andSomething } from '../'

And as huge bonus for typescript users: Props importing experience will be much clearer

import { Typography, TypographyProps } from '@material-ui/core'

For now, the only way to import props is:

import Typography { TypographyProps } from '@material-ui/core'

Normal flow of things

Originally the goal of export default (I am 99% sure) was intended to export something when we don't really know what we exporting. The best case of default export power is dynamic examples – when we don't really know which component we need to import and render. Or for example next.js's page loader – when it also doesn't know which pages it needs to process exactly.

When we have a specific object that we need to export – we should name it and use this name consistently through the codebase.

Potential problems

Default exports were loved by react community because of HOC. It was really useful to do

export default withStyles(Component)

It is not possible with named exports, but we could have a convention about naming private components in the file

function _Component() { 

}

export const Component = withStyles(_Component)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with this RFC and the linked material-ui/pickers migration PR (#2004), then inspect how React components and their imports are exported across the repository. No target files or tests are named, so the scope and acceptance criteria would need to be settled first; done would mean an agreed export convention and a consistent migration, if that is the outcome.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react, typescript
Domain
developer-experience, frontend
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.