There's something I'm not sure to understand with ES6 modules, especially when it comes to import with side effects.
For example, in an Angular project, I'm using Rxjs library to use observables. I need to import functions and objects from this library with ES6 import.
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
//later in the code I'm using these imports like this in a method
return Obserable.of(....);
My problem is with imports :
import { Observable } from 'rxjs/Observable'; seems understandable: I'm importing Observable object from 'rxjs/Obserable' located in node_modules.
My problem is with import 'rxjs/add/observable/of';
Why not something like import { of } from 'rxjs/....';
I've read import '...' doesn't export any object or function. What does it do exactly ? If you are not exporting 'of' operator, how can you use it ?
When to use import */import {} from or directly import '...';
Thanks
That's actually old way to import operators.
import 'rxjs/add/observable/of'; is actually prototyping method of to Observable. When you import that, every Observable object has of method available. That's why you should put those import lines in a root file like app.module. However, as I told you at the beginning, it is the old way.
With RxJs 5.5, pipeable operators came into play. You can and should import operators/observables as follows
import { of } from 'rxjs/observable/of';
const myObs = of('some value');
With this way, operators and observables became tree-shakable. Webpack will not put unused operators into your output bundle.
Update
Let's say you are using bunch of operators and you added static imports in a global file. After a while, you refactored your code and you are no longer using Observable.of. But let's say you forgot you already imported that in a global file. Even though you are not using of anymore, you are still going to get the code of of observable in your output bundle. Prototyping makes it impossible to tree shake your code. I suggest you watch this. Ben Lesh explains pipeable operators and RxJs6.
Related
I've noticed that React can be imported like this:
import * as React from 'react';
...or like this:
import React from 'react';
The first imports everything in the react module (see: Import an entire module's contents)
The second imports only the default module export (see: Importing defaults)
It seems like the two approaches are different and fundamentally incompatible.
Why do they both work?
Please reference the source code and explain the mechanism...I'm interested in understanding how this works.
Update
This is not a duplicate of What is the difference between import * as react from 'react' vs import react from 'react'
That question was answered with general ES6 module information.
I am asking about the mechanism that makes the react module work like this. It seems to be related to "hacky" export mechanism in the source here but it's not clear how that enables both importing the entire module and just the default export into React and having both of those approaches work with transpiling JSX, etc.
TL;DR
Indeed ES import statements import default and import * are not the same thing, the fact that they behave the same in this case is a combination of how React authors chose to publish the library and compatibility layers in TypeScript (using esModuleInterop) or Babel and your bundler to make them "just work". It probably shouldn't work according to ES6 spec, but today we are still working in an era where JS modules are a mess, so tools like Babel, TypeScript, Webpack, etc try to normalize behavior.
More details:
React is not an ES6 library. If you look at the source code you see this in index.js:
const React = require('./src/React');
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = React.default || React;
(Note the comment, even in React source code they struggle with ES6 default export compatibility.)
The module.exports = syntax is CommonJS (NodeJS). A browser would not understand this. This is why we use bundlers like Webpack, Rollup, or Parcel. They understand all kinds of module syntax and produce bundles that should work in the browser.
But even though React is not an ES library, both TypeScript and Babel let you import it as if it is (using import syntax, rather than require(), etc), but there are differences between CJS and ES that have to be resolved. One of them is the fact that export = can give you things that ES has no spec-compliant way to import, like a function or a class as the module. To work around these incompatibilities Babel has for awhile allowed you to import CJS modules as if they were exporting something by default, or import as a namespace. TypeScript for awhile didn't do this, but more recently added that as an option under esModuleInterop. So now both Babel and TypeScript can pretty consistently allow a CJS module to be imported using default or namespace ES imports.
With TypeScript it also depends on how the type-definitions for the library are actually defined. I won't get into that, but you can imagine situations where thanks to transpilers and bundlers a particular import works at runtime, but TypeScript doesn't compile without errors.
Another thing worth mentioning is that if you look at the built code for React there is a UMD module version as well as the CJS version. The UMD version includes some gnarly runtime code to try to make it work in any module environment, including the browser. It's mainly for use if you want to just include React at runtime (ie you don't use a bundler). Example.
Confusing? Yeah, I think so. :)
You most likely have "allowSyntheticDefaultImports": true, set in your tsconfig.json, which essentially shuts the compiler up about default imports it thinks are invalid. Typescript added esModuleInterop which does essentially what babel does for module loading.
This allows you to use ES6 default imports even when the source code you're importing doesn't export anything as default
Typescript is strict (follows the rules) when it comes to this, which is why they require you to import * as React from 'react'. Or requires you to tell it to allow synthetic default imports in its base config.
More On That Here
This question already has answers here:
When should I use curly braces for ES6 import?
(11 answers)
Closed 1 year ago.
I am learning Vue JS and find that sometimes we import {} sometimes we import without {}. What is the difference, please?
import Home from '#/views/Home.vue'
import { createRouter, createWebHistory } from 'vue-router'
Thank you
The import with {} is called named import and without {} is called default import.
When you export a component as export Component_Name you import it as import {Component_Name } from 'path_to_component';
When you export a component as export default Component_Name you import it as import Component_Name from 'path_to_component';
It's nothing vue specific, it's just a feature of ES6 version of Javascript.
If you want all or more function(component) of the package you can use import Home from '#/views/Home.vue',
If you want a specific function(component) from the package you can use import { createRouter, createWebHistory } from 'vue-router'
To my mind, the way Javascript does imports is confusing, and is a common source of programming errors.
The problem is that there are no rules about default exports vs named exports, and there are no errors that come from importing the wrong thing.
For example,
import moment from 'moment' // The _right_ way to import it
const now = moment()
Compare that with this code, which looks remarkably similar, only the braces on the import are different:
import { moment } from 'moment' // The _wrong_ way to import it,
// but it doesn't throw an error (until you try and use it)
const now = moment() // Will throw an error, because moment is undefined
There is a good article here on the subject: https://humanwhocodes.com/blog/2019/01/stop-using-default-exports-javascript-module/
Conclusion
I’ve had several productivity problems importing default
exports in my projects. While none of the problems are necessarily
impossible to overcome, using named imports and exports seems to
better fit my preferences when coding. Making things explicit and
leaning heavily on tooling makes me a productive coder, and insofar as
named exports help me do that, I will likely favor them for the
foreseeable future. Of course, I have no control over how third-party
modules I use export their functionality, but I definitely have a
choice over how my own modules export things and will choose named
exports.
So my goal is to create a library in Typescript. My intention is to split up core parts of the library into submodules like RxJS or Angular Material.
RxJS and Angular both support imports like so:
// RxJS
import { map, filter } from 'rxjs/operators';
// Angular
import { MatButtonModule } from '#angular/material/button';
However, I am unable to replicate this myself.
My goal is to do something similar and allow you to import a class with import { foo } from 'package/bar;
I have looked at RxJS's source on Github and have tried replicating what they've done but it's not working.
The library compiles fine but when I go about importing it I always get a Cannot resolve dependency 'package/foo' error.
Meanwhile doing import { test } from package (without the submodule part) works completely fine.
I've tried using paths in tsconfig to no avail. If that is the answer then I'm doing it wrong.
How do I go about doing this?
In order to achieve that, you can create your "sub-modules" in different directories (although they are technically part of the same module), and create an index.ts on each of those directories exporting there whatever you want to publish.
For example, I have done this in my NodeJs package Flowed, and you can for example do this:
import { FlowManager } from 'flowed/dist/engine';
Where the corresponding index.ts file is this one if you want to check.
Although in my case I put also available all the stuff from the root, so the previous line would be equivalent to:
import { FlowManager } from 'flowed';
Im developing a small app with angular2 and I installed Rxjs 5.
In every tutorial there is a diffrent way to import the Rxjs libary.
The code to import in angular2 web is not working; I mean that Websotrm doesn't recognize Observable or any of its functions (from,subscribe,...).
What do I need to do to fix that?
If I import everything from Rxjs, does the load of the website will be slower? (I won't have more then 2- classes)
(Webstorm question) How to I make webstorm to autocomplete the name of the functions with out pressing alt+space
The latest RXJS distributions offer broken up modules to mitigate the gigantic filesize, à la Lodash. Importing rxjs/Rx (as another answer suggests) will get you the entirety of the library and isn't suggested.
Instead, import methods and operators individually:
for core classes, import the class from its scoped module: import { Observable } from 'rxjs/Observable'
for instance methods, use the instance scope in the "add" scope: import 'rxjs/add/observable/fromEvent' (note there is no destructured object to import – the method is added automatically by the import)
for operators, import from the add/operator scope: import 'rxjs/add/operator/switchMap'
Importing an operator once makes it available to all instances, so it's recommended to gather all the parts you use in a single file and import that file wherever needed, I.E. by re-exporting the instances you use.
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/flatMap';
import 'rxjs/add/operator/switchMap';
export { Observable, BehaviorSubject };
This works in my projects: import {Observable, Subject} from "rxjs/Rx";
You only need to add Rx.umd.min.js from rxjs/bundles. It's about 170KB.
Try upgrading to WebStorm 2016.2. I am using that version and it works fine (provided you have the correct imports) Has better support for Angular 2 in general. See change notes.
I virtually never use Ctrl+Space. Tip: Set the Autopopup code completion value (Settings, Editor, Code Completion) to a very low delay.
I really don't know how to do this and not sure how to google either.
Right now I have this
let source = require('vinyl-source-stream');
I would like to change to be import but this doesn't work
import {'vinyl-source-stream' as source} from 'vinyl-source-stream';
If that module even supports the ES6 import/export system, then what you want is this:
import source from 'vinyl-source-stream';
Your version is attempting to import an exported value named vinyl-source-stream from the module; instead, you just want the module itself to be imported (into an object named source in this case).
If you want everything in the module imported, instead of just the default exports, use this instead:
import * as source from 'vinyl-source-stream';
But neither of those will work if the module isn't actually written to use the new system.
This library doesn't use the ES2015 module system. It doesn't export at all, so you can't import it or from it.
This library uses the CommonJS module pattern (as can be seen in the source) and is meant to be requireed.
You could import the library with:
import form 'vinyl-source-stream';
which will cause the code to be executed, but that will be useless in this case since nothing (useful) will happen - in fact, you'll probably get a runtime exception due to undefined module.