This Blog is about the (too) many possibilities that ES6 gives us for exporting and importing fields, functions and classes.
I just read some articles about how we should export and import, and now I'm puzzled and confused. The technical backgrounds about why some export/import pattern is good or bad stay in the dark. Or what would you suppose to be behind a sentence like "You lose some ES6 module benefits such as tree-shaking and faster access to imports" - ? All I can give by now is a quick overview.
General
Both ES6 exports and imports are possible just on ground-level, they can not be inside some function or code-block.
Imports moreover are "hoisted", that means they get resolved before the source-code is executed where they occur.
Export
Exports are some kind of access modifiers. They state which field, function or class are publicly available for importers.
Named Inline Exports
Simply put the export
keyword before the field, function or class to make it public.
Advantages:
- You clearly state which parts of the module are are public
- Short, simple, concise, the exported names are not duplicated in a separate export clause
Disadvantages:
- On the import side you need { curly braces }, even when importing just one expression
Separate Export Clause
The export
keyword is used as the opener for a list of names that should be exported.
The according import is the same as with named inline exports.
Disadvantages:
- Duplication of possibly lots of names. This seems to be a compatibility-pattern for the now obsolete revealing module pattern.
Export Renaming
Disadvantages:
- Can create confusion, and is not needed at all. Renaming on the import side is what we will need (in case two imported functions have the same name)
One Default Export per Module
You add default
after the export
keyword.
You can combine the default-export with any number of named inline exports.
Advantages:
- The import doesn't need the enclosing { curly braces }
Disadvantages:
- You can have just one default-export per module.
- Big modules: no default export, just named inline exports.
Although we should avoid big modules, it's inevitable sometimes, e.g. you want to make a constant for each keyboard key. - Small modules: make it even smaller until one default export is sufficient.
Import
Other than export
, which plays the role of an
access modifier,
import
is a
dependency statement.
The ES6 interpreter searches for imports before executing the source code in a module it loads.
When it can't resolve all dependencies, or one has a syntax-error, it doesn't execute the loading module either.
ES6 seems to give three options for resolving imported files:
- path relative to the location of the importer, always starting with
"./"
, that's what I used in all examples of this article - absolute path (I wouldn't use that unless you want to bind your library-structure to the file-system of your computer)
- module names, has to be configured, not specified how, maybe the best way but not yet ready
Named Import
Here I refer to the exports of output.js
module presented at the beginning of this article.
Advantages:
- You clearly state what you depend on, not more or less, it is a precise dependency statement, and it is easy to understand
Disadvantages:
- The import needs the enclosing { curly braces }
Wildcard Import onto Module-Object
The star (asterisk, *) is called "wildcard". It denotes all exports.
This import-statement creates a new object output
that contains all exports of the imported module.
You can use them by dereferencing the module object, e.g. output.SUCCESS
.
The "as modulename
" clause is required!
You could say modulename
is a "namespace".
Advantages:
- No duplication of names in the import statement
-
Easy to find out from which module some name comes from, because it is always
module.name
-
Ambiguities that must be fixed via "
as xxx
" (aliasing) will not occur
Disadvantages:
- You possibly import things that are not needed, your dependency statement is not precise enough and may handycap refactoring
-
Necessity to always use "
modulename.
" as prefix for imported things
Import Renaming
To resolve ambiguity when importing the same name from different modules,
import
provides renaming via the "as" keyword.
You wouldn't need that when importing by wildcard, then each of the functions would be bound to the imported module-object.
Advantages:
- This is needed to fix ambiguities of named imports
Disadvantages:
- Naming magic, possibly confusion about what the real name of the function is
- Try to be as explicit as possible.
Avoid wildcard imports unless it is needed, like e.g. for importing constants for all keyboard keys. - Avoid renaming functions and classes whenever possible, especially avoid abbreviations.
You just create confusing source code.
Resume
This article is not complete. For example I did not discuss anonymous default exports, or re-exporting, because I consider them to be dispensable features.
The question rises whether it makes sense to provide so many different export/import ways in a programming language that claims to become a standard, running in millions of web-browsers. Standards live from being understood by a maximum number of people, thus they need to be unambiguous and simple, a base for communication.
Nevertheless this is a big step forward.
Finally JavaScript got dependency management, built into browsers!
Please refer to the many
web-pages
about ES6 modules for deeper information about how to export and import.
Keine Kommentare:
Kommentar veröffentlichen