Most examples I see of importing modules use lowercase; e.g.
import * as tools from './tools';
The rule I usually see is, if it's a constructor function then use PascalCase; otherwise use camelCase.
However I always see import * as React from 'react' even though React is not a constructor function (can't do new React()). Why is it always capitalized, and when from a JavaScript style standpoint would I choose to capitalize a library or module like './tools'?
Most of my background is in C# and C++ so I'm inclined to capitalize libraries (import DateFns from 'date-fns', import * as Tools from './Tools').
Because it is a namespace and I guess because it is a framework brand. Brands that are frameworks tend to get capitalized more often (Vue, Backbone, Ember, etc).
When using Typescript as your javascript super-set it makes a whole lot of sense to capitalize your namespaces, since it has a C# like flavor to it.
But even with new ECMAScript versions there is a benefit to capitalize namespaces. I think it keeps things more readable.
I just stumbled on this older question.
The primary reason why the 'react' module needs to be imported as React (exact spelling and capitalization) is so that JSX works properly.
From the JSX In Depth doc:
Fundamentally, JSX just provides syntactic sugar for the React.createElement(component, props, ...children) function.
...and later:
React Must Be in Scope
Since JSX compiles into calls to React.createElement, the React library must also always be in scope from your JSX code.
Example
This component in JSX:
const SimpleComponent = () => (<div>simple component</div>);
...gets compiled into this:
var SimpleComponent = function SimpleComponent() {
return React.createElement("div", null, "simple component");
};
...so React must exist in the scope or the compiled code will throw this error when it runs:
ReferenceError: React is not defined
Related
QUESTION
There are a number of posts about this topic, but I'm still unsure as to the best practice for JS imports.
STYLE GUIDES CONFLICT
Google Style Guide Google Import Style Guide suggest the following approach is "good"
import * as goog from '../closure/goog/goog.js';
AirBNB Style Guide AirBNB Style Guide clearly states not use wildcards.
Observation
As I look through some respected JS developers I see them use wildcards. Originally I suspected it was for namespace or aliasing purposes, but I've seen this type of example more often than not.
import * as debounce from 'lodash/debounce.js'
The only reason I can imagine is maintainability i.e. debounce will remain debounce independent of export, and in this cases debounce will debounce as long as a debounce.js file exists.
The difference between
OPTION 1:
import debounce from "lodash/debounce.js";
OR
OPTION 2:
import * as debounce from 'lodash/debounce.js'
Is that option 1 seems to generate (example only)
var _debounce = require('./lodash/debounce.js');
and option 2 adds a bit of iteration code.
var _debounce = require('./lodash/debounce.js');
var Debounce = _interopRequireWildcard(_debounce);
function _interopRequireWildcard(obj) {
if (obj && obj.__esModule) {
return obj;
} else {
var newObj = {};
if (obj != null) {
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key))
newObj[key] = obj[key];
}
}
newObj.default = obj;
return newObj;
}
}
Best Practice?
Is there a best practice for the average JS developer?
import * as debounce from 'lodash/debounce.js' // wildcard import
import debounce from 'lodash/debounce.js' // submodule import
import {debounce} from 'lodash' // deconstruction import
import _ , { debounce, throttle } from 'lodash'; // everything but the sink
import debounce from 'lodash.debounce' // method import
Method vs Submodule
As a side note there is also conflict about submodule vs. method imports i.e.
Submodule Import
import debounce from 'lodash/debounce'
Method Import
import debounce from 'lodash.debounce'
but I read that method imports don't share code and as such the memory footprint will be slightly larger, whereas submodules do, which would be important in larger libraries.
My gut feel is wildcard imports are a code smell (like infinity in science), but I feel I might misunderstand the nuances in the style guides.
Is the takeaway here that both are right, but only use wildcards
for maintainability / longevity when importing 3rd party code
smaller libraries or utilities a more efficient approach
namespacing?
or ...
...but I've seen this type of example more often than not.
import * as debounce from 'lodash/debounce.js'
The only reason I can imagine is maintainability i.e. debounce will remain debounce independent of export, and in this cases debounce will debounce as long as a debounce.js file exists.
While that's true, it's not particularly useful, because debounce in that example is just an object (specifically, it's called a module namespace object). It's just a container. It has properties for all the named exports in debounce.js and if there's also a default export, a property called default. Those (other than default of course) will still change if the exports in debounce.js change.
The difference between
OPTION 1:
import debounce from "lodash/debounce.js";
OR
OPTION 2:
import * as debounce from 'lodash/debounce.js'
The difference is in what they do, not (just) the output that (say) Webpack creates for them. They do different things.
import debounce from 'lodash/debounce.js' imports the default export from debounce.js and binds it to a local binding (loosely, variable) called debounce.
import * as debounce from 'lodash/debounce.js' imports ALL of the exports from debounce.js wrapped up in a module namespace object and binds that object to a local binding called debounce.
In the first example, assuming the default export of lodash/debounce.js is a function, you'd use it as:
const newFunction = debounce(someFunction, someDelay);
In the second example, you'd have to use a property on the module namespace object; assuming it's the default export, that would be:
const newFunction = debounce.default(someFunction, someDelay);
Those are fundamentally different.
So the best practice is to do the thing you actually want to do. Sometimes, you want the module namespace object, though (opinion!) I suspect that's fairly rare. Generally, you probably want to import specific exports, either the default one (import x from ...) or a named one (import { x } from ...).
I am new to react and its transpiled way of generating javascript.
In react side, I have a class Utility that uses a data object UserData organized as below -
UserDataObj.js
class UserData{
this.someobj = {};
//some function here
something(){
}
}
const UserDataObj = new UserData();
export {UserDataObj};
Utility.js
import {UserDataObj} from './data/UserDataObj';
class Utility {
doSomething(){
//UserDataObj.something();
}
}
const utility = new Utility();
export {utility};
I have another ReactApp UserApp.js, that also uses UserDataObj and Utility (although not good design wise) -
import {UserDataObj} from './data/UserDataObj';
import {utility} from './Utility';
class UserApp extends React.Component{
//does something with UserDataObj
// also does somethign with utility
}
My question is, how many utility and UserDataObj instances will be created in memory, when UserApp is rendered. My guess is, it should be only 1 instance for both. But I want to confirm if importing n times creates a new instance every time.
Any good read on this topic is greatly appreciated.
Thanks
This depends on the bundling tool, and not React. I imagine that the new browser ES Module resolution scheme works in the same way.
Most bundlers that I know of, and other import schemes such as Node.js' require module resolution will cache the import between files and always return the same exported objetcs. This is a requirement for prototype inheritance, for example, otherwise, it would mess up the instanceof operator.
That exported new Utility() instance will be the same for any module that imports it. In order to generate new instances, you would have to have a function.
I am attempting to import everything from a library as a hash, modify it, and re-export the modified hash, without knowing all of the named exports in a library. For example:
import * as reactBootstrap from 'react-bootstrap';
wrappedReactBootstrap = doFunnyThingsTo(reactBootstrap);
export {
...wrappedReactBootstrap
};
// or
export wrappedReactBootstrap;
My understanding of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export is that the following is not allowed by the spec. Could someone confirm?
Obviously, looping is out of the question, since export and import statements must be top level.
Object rest spread is stage 3 proposal and not a part of any spec (will probably be included in ES2018).
More importantly, export has syntax that mimics existing JS syntax but doesn't interpret { ... } as an expression. export syntax was strictly defined because ES2015 modules are supposed to be statically analyzed. This is one of their benefits, but it requires the developer to specify exports and imports explicitly.
Since { ...wrappedReactBootstrap } introduces dynamic export (it was used here exactly for this purpose), it isn't supported by ES2015 module export and it is very unlikely that it will be.
If it is necessary to provide dynamic behaviour for the export, it can be exported and imported as named or default object.
import * as reactBootstrap from 'react-bootstrap';
export default doFunnyThingsTo(reactBootstrap);
And used like
import wrappedReactBootstrap from '...';
const { funny, thing } = wrappedReactBootstrap;
Obviously, wrappedReactBootstrap object won't get the benefits of ES2015 modules this way, e.g. tree-shaking.
What happens when you write an import statement in the following form:
import React, { Component } from 'react';
Is destructuring of the import module occurring as in destructuring an object to achieve Component instead of needing React.Component? Or is it importing with a named export with completely differing syntax, though it does resemble destructuring?
An important corollary question: does import React, { Component } ... needlessly load up the Component object from the React module twice as compared to simply import React ... (given that Component is a constituent of the larger React library)?
To answer your first question:
No, it's not object destructuring. The syntax may have been set up that way to relate but there's no confirmation that they were intentionally made to be related. Per the ECMAScript 2015 Language Specification:
Section 15.2.2 Imports
Syntax
[...]
ImportClause :
[...]
ImportedDefaultBinding , NamedImports
[...]
NamedImports :
{ }
{ ImportsList }
{ ImportsList , }
It's completely separate syntax.
To answer your second question:
Yes, it imports it twice, once React for access as React.Component by the default export, and once as Component as a named export. Per the specification:
Section 12.2.2 Static Semantics: BoundNames
[...]
ImportClause : ImportedDefaultBinding , NamedImports
Let names be the BoundNames of ImportedDefaultBinding.
Append to names the elements of the BoundNames of NamedImports.
Return names.
As you can see, the names you import with import React, { Component } are bound twice, meaning you get React as the default export and thus React.Component, and then the bound name Component is also appended to your imported names. You essentially get it twice under two different bindings or names.
It should be noted that only the bound names are different. React.Component and Component refer the same object, just with different bindings because you imported using named exports. Once you import React, React.Component has already been imported. All { Component } does is create a new binding to the already imported object.
There is no destructuring happening in the import syntax. Even though it looks somewhat similar - it's a separated syntax.
The imported identifiers are bindings to the objects created during module initialisation. So practically you get 2 bindings to the same object, which costs you 1 extra reference, nothing more.
No matter how many times in your source code tree you import a module it would only be initialised once, with all the values created just once. And all the import statements would essentially "bind" to the values in memory without creating duplicates.
I am experiencing a really weird behavior and can't even say which package to blame for it.
My setup: RequireJS project with the JSXTransformer and the jsx! plugin
I have an es6 class like this:
define([
'react'
], function(
React
) {
class MyComponent extends React.Component {
myMethod() {
otherObject.someMethod()._privateProp; // Yes, we need this accessing and have no influence on it
}
}
return MyComponent;
});
The transpiled output in the resulting bundle after running r.js is:
define('jsx!project/components/InputOutput',[
'react'
], function(
React
) {
var ____Class8=React.Component;for(var ____Class8____Key in ____Class8){if(____Class8.hasOwnProperty(____Class8____Key)){MyComponent[____Class8____Key]=____Class8[____Class8____Key];}}var ____SuperProtoOf____Class8=____Class8===null?null:____Class8.prototype;MyComponent.prototype=Object.create(____SuperProtoOf____Class8);MyComponent.prototype.constructor=MyComponent;MyComponent.__superConstructor__=____Class8;function MyComponent(){"use strict";if(____Class8!==null){____Class8.apply(this,arguments);}}
MyComponent.prototype.myMethod=function() {"use strict";
otherObject.someMethod().$MyComponent_privateProp;
};
return MyComponent;
});
Note how otherObject.someMethod().$MyComponent_privateProp; is written there. This obviously breaks because it is not a property on instances of MyComponent.
Add /** #preventMunge */ to the top of the file. See this GitHub issue:
Yes, sorry this is a non-standard fb-ism. For now you can work around this and toggle this feature off by putting /** #preventMunge */ at the top of your file -- but that's also a pretty big fb-ism. We should (a) turn this into a transform option (rather than a direct docblock directive) and (b) make it opt-in rather than opt-out (since it's non-standard).
For context: We munge all under-prefixed object properties on a per-module basis partly because our under-prefix convention applies to both objects and classes. Additionally, even if we wanted to lax the objects vs classes distinction, it's impossible to tell (in the general case) if a property is a reference to this since alias variables can occur (i.e. var self = this; self._stuff;).