ES2015 module re-exports

Today’s episode of TIL (“Today I Learned”) is:

Did you know you can re-export modules in ES2015 (aka: ES6, aka: new JavaScript)? That is, you can import a module and export it again all in one line of code. Why would you want to do this?

Well, first you need to know about the way importing directories works. If you write import foo from './foo', the JavaScript engine will look for either a file named ./foo.js or a directory named ./foo. If the latter is found, it will assume the directory is a node (npm) module and look inside for a package.json to determine what file to include. If there is no package.json, it will default to loading ./foo/index.js.

Sometimes I have a file I’ve been importing, like user.js, containing a default model and a validation function:

export default { firstName: 'Big', lastName: McLargeHuge' }
export function validateUser( user ) {
  if ( user.firstName && user.lastName ) {
    return true
  }
  return false
}

In the rest of my code, I load it like this:

import user from './user'
import { validateUser } from './user'

Then later I decide I actually want to split up the code inside user.js into multiple files, all related to users. Let’s say I want to add a new file for validation of user data. In that case, I can move user.js to ./user/index.js and add the file ./user/validation.js.

Here’s ./user/index.js:

export default { firstName: 'Big', lastName: McLargeHuge' }

And here’s ./user/validation.js

export function validateUser( user ) {
  if ( user.firstName && user.lastName ) {
    return true
  }
  return false
}

That works well! Now in the rest of my code I can load things like so:

import user from './user'
import { validateUser } from './user/validation'

But wouldn’t it be nice to be able to get the validateUser function from the user module without needing to know the internal structure of that module? Here’s where we can use re-exports.

By adding this line to my ./user/index.js, I can import and export my validation code in one shot: export { validateUser } from './validation' (or even easier, export * from './validation').

Let’s take this one step further. I don’t want to have that re-export dirtying up my user model file. Let’s move my default user module into its own file, ./user/main.js:

export default { firstName: 'Big', lastName: McLargeHuge' }

We’ll just re-export that too. (We just need to do one tricky thing in order to re-export a default, we have to write export {default as default}). So now the ./user/index.js looks like this:

export { default as default } from './main'
export * from './validation'

Magic! Now in the rest of my code, I can just write:

import user from `./user`
import { validateUser } from './user'

And yet the code for both of those is in entirely separate files!

Author: Payton Swick

Vegan. Digital craftsman. Tea explorer. Avid learner of things. Writes code @automattic.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s