2

Is there is a performance or behavioural difference between importing from an index file or importing individual modules?

For example, with an index file (@/modules/user) of...

import routes from './routes'
import controller from './controller'

const user = {
  routes,
  controller
}

export default user

If I import just the routes from that file...

import user from '@/modules/user'

const routes = Router()

routes.use('/user', user.routes)

Is this any different to just importing the routes individually from their own file (@/modules/user/routes)? Does the controller get imported as it's in the user object?

import userRoutes from '@/modules/user/routes'

const routes = Router()

routes.use('/user', userRoutes)
tribe
  • 321
  • 2
  • 9
  • Since there are no ES modules in Node and you obviously use a bunder to handle `@`, this totally depends on how you build the app. The question contains no information on that, so the answer is 'it depends'. Any way, there's not much difference for server side application. – Estus Flask Aug 25 '17 at 09:52
  • 1
    I suggest clarifying your question: Are you asking what the difference is in the **specified** behavior of modules (which is only slowly being adopted by engines, and not in Node yet), or the behavior of a particular bundler/transpiler? – T.J. Crowder Aug 25 '17 at 09:54
  • According to the spec, `./controller` would be evaluated and imported. – Felix Kling Aug 25 '17 at 15:20

2 Answers2

1

There are currently no native ES modules in Node.js. The actual difference depends on the toolchain. When the application is built with Webpack/Rollup (a minifier is potentially needed too) and configured to use ES modules internally, tree-shaking can be applied. This is best case scenario.

This would be a case for tree-shaking if there were a reexporting module:

import routes from './routes'
import controller from './controller'

export {
  routes,
  controller
}

And it was imported like

import { routes } from '@/modules/user'

However, the cases in the original post are different. In one case, once user constant is imported, it's impossible to remove unused controllers property from it with tree-shaking. In another case, @/modules/user/controller module remains unused and doesn't need tree-shaking. It will be ignored even if the application is configured to use CommonJS modules.

So yes, it's possible for ES modules to import only modules that are in use, and this heavily depends on actual code and project configuration.

Client-side applications primarily benefit from tree-shaking because it affects bundle size. This concern shouldn't be taken into account in server-side Node.js application - unless unused module imports massive amount of third-party modules that aren't used anywhere else.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • This is what I was looking for. It's a Node API on the server, so I guess I don't need to worry about these kind of performance issues. I'm aware of Webpack tree shaking on the client-side; I was just wondering how the server handles imports. – tribe Aug 25 '17 at 10:31
0

Currently you can only use the import syntax using transpilers(converters from one syntax to another) as it is not yet natively supported by engines. Lets take babel for example.

Babel converts the import to CommonJS style code that can work within Node.js. While the syntax is conformant to ES6, the implementation is not.

Babel converts the syntax into CommonJS, evaluating the imported code before determining what is being imported. With ES6, the imports and exports are determined before the code is evaluated.

With future support of es6 imports inside node, importing a specific function inside the code will only return that exported function, without evaluating the whole script in the targeted file.

Currently they work the same since transpilers convert them to traditional node require syntax.

However, you can use webpack Treeshaking to remove unused code from the output file, this way they are almost identical in behavior.

The @ syntax

The @ syntax depends on the module loader or module bundler. The module loader is not part of the ECMAScript spec. You most likely have something like babel-plugin-root-import in your webpack/babel config.

Basically it means from the root of the project.. it avoids having to write things like import Component from '../../../../components/component'. in this case, it has nothing to do with partial imports.

Bamieh
  • 10,358
  • 4
  • 31
  • 52
  • The question doesn't contain information whether Webpack or Rollup were used or not (considering that there is `@` in paths, they likely did), so there is guesswork involved in the answer. Babel doesn't necessarily convert ES6 modules to CommonJS, it's not known if it's possible to apply tree-shaking to the this case or not. *The @ syntax probably does the same thing as treeshaking* - no, it doesn't. See https://stackoverflow.com/questions/42749973/es6-import-using-at-sign-in-path-in-a-vue-js-project-using-webpack – Estus Flask Aug 25 '17 at 10:00
  • true, OP must clarify the question a little more, i updated the answer based on what i understood. – Bamieh Aug 25 '17 at 10:02