How to use ES6 import with hyphen - javascript

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.

Related

Implications of doing `import * as React from 'react'` vs `import React, { useEffect } from 'react'` [duplicate]

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

ES6 twitter-text import

I'm trying to import the twitter-text package into a React/ES6 environment, and I'm not able to figure out what exactly is exported and keep getting ...is not exported from 'twitter-text'. compile errors.
Doc states that the twttr.txt namespace is exported, but all the examples I can find are for node and use require(). It installed fine via npm install twitter-text and it's finding refs, for example import { parseTweet } from 'twitter-text'; is grabbing actual function and class refs from the package, but still the no export error when it compiles.
I also tried to get the global twttr.txt using just import 'twitter-text'; but I'm getting the same error.
The library is default-exporting an object unfortunately, which means that you need to use
import twttr from 'twitter-text'
twttr.parseTweet(…)
Named exports do not seem to be available.

Babel.js using Import and Export not working

I'm trying to use import and export to create modules and it's not working.
I added https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js to the index.html header and tried to import a js file and get an error message saying SyntaxError: import declarations may only appear at top level of a module. What can I possibly be doing wrong?
I know I can use require.js but rather use import and export.
HTML
script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js"></script
JS File
import Mymodule from './modules/mymodule';
Babel cannot perform client-side transpiling of modules, or rather it is not universally supported by browsers. In fact, unless you use a plugin, Babel will transform import into require().
If I run the following code:
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.js"></script>
<script defer type="text/babel" data-presets="es2015">
import Mymod from './modules/module';
Mymod();
</script>
</head>
I get the following error:
Uncaught ReferenceError: require is not defined
From Babel Docs:
Compiling in the browser has a fairly limited use case, so if you are working on a production site you should be precompiling your scripts server-side. See setup build systems for more information.
Most people choose a pre-compiled module bundler like Webpack or Rollup.
If you really want to perform this client-side, use RequireJS with Babel run via a plugin, though you may need to use AMD syntax.
Native browser support for ES6 modules is still in early stages. But to my knowledge there isn't a preset/plugin available yet for Babel to tell it not to transform import/export statements.
The scripts that babel-standalone translates execute by default in global scope, so any symbols defined by them are automatically available to every other module. From that perspective, you don't need import/export statements in your modules.
However, you might be trying to maintain source files that can be used both by babel-standalone (e.g. for quick test environments, feature demonstrations, etc) and via bundlers such as webpack. In that case, you need to keep the import and export statements there for compatibility.
One way to make it work is to add extra symbols into the global scope that cause the import and export code that babel generates to have no effect (rather than causing an error as usually occurs). For example, export statements are compiled into code that looks like this:
Object.defineProperty (exports, "__esModule", {
value: true
});
exports.default = MyDefaultExportedClass;
This fails if there is no existing object called "exports". So give it one: I just give it a copy of the window object so anything interesting that gets defined is still accessible:
<script>
// this must run before any babel-compiled modules, so should probably
// be the first script in your page
window.exports = window;
import statements are translated to calls to require(). The result (or properties extracted from it) is assigned to the variable used as the identifier in the import statement. There's a little bit of complication around default imports, which are different depending on whether or not the result of require() contains the property __esModule. If it doesn't, things are easier (but then you can't support having both default and named exports in the same module ... if you need to do this, look at the code babel produces and figure out how to make it work).
So, we need a working version of require(). We can provide one by giving a static translation of module name to exported symbol/symbols. For example, in a demo page for a React component, I have the following implementation:
function require (module) {
if (module === "react") return React;
if (module === "react-dom") return ReactDOM;
}
For a module returning multiple symbols, you'd just return an object containing the symbols as properties.
This way, a statement like
`import React from "react";`
translates to code that is effectively:
`React = React;`
which is roughly what we want.

What does import Module from 'module' import when no default export is defined and why is it different from import * as Module?

I am pretty new to JavaScript and have been struggling with imports recently. There has been one thing I cannot wrap my head around.
In older node modules (mostly those which came to see the light prior to ES6), which may be installed using the npm, such as express, usually no default export is defined.
My IDE (WebStorm) marks the following line with the Default export is not declared in the imported module notification.
import express from 'express';
This message may be circumvented by trying to import the whole module as an alias using
import * as express from 'express';
implicitly telling my IDE to just import everything and name it express, however doing so then leads to an express is not a function error when trying to instantiate the application on the following line.
const app = express();
Peculiarly the original import (without the alias) works.
What exactly is imported using the import statement without the alias, when no default export is defined? I would think it is the whole module, but it does not seems so.
What does import Module from 'module' import when no default export is defined?
Nothing. In fact, instantiating the module will throw a SyntaxError when something is imported that is not exported or exported multiple times from the imported module.
Why is it different from import * as Module?
Because import * just imports a module namespace object that has the exports as properties. If you don't export anything, it'll be an empty object.
In older, pre-ES6 node modules usually no default export is defined.
Which means that you cannot import them as an ES6 module. Your IDE seems to expect that though and puts up the warning.
So what happens if you refer to them in an import declaration? Your module loader might do anything with it, and HostResolveImportedModule will return a module record that is not an source text "ES6 module" record - i.e. it might do anything implementation-dependent with CommonJS modules.

Can't find module 'hbs' with ES6 style import

I'm doing this in TypeScript, but tried it in vanilla JS as well with the same error. I've pulled down two modules: express and hbs. I'm trying to use the ES6 import syntax like this:
import * as http from 'http';
import * as express from 'express';
import hbs from 'hbs';
The last line gives me an error saying it can't find module hbs. I'm looking right at it... I can see it just fine. However when I replace the line with the older CommonJS syntax:
var hbs = require('hbs');
It works fine... what gives? Still on the learning curve with ES6...
Observation 1... as you have in your other exports, you should either import the whole module with an alias:
import * as hbs from 'hbs';
Or you can choose to import specific exports:
import {thing} from 'hbs';
Observation 2... is hbs a TypeScript module, or a JavaScript one? If it is a JavaScript one (as I believe it may be) you will need to pair it with a definition file, for example hbs.d.ts that describes the JavaScript file. TypeScript won't recognise a plain JavaScript module without the definition.
I was experiecing a similar problem. The syntax is correct ES6 indeed.
Good news is that the problem seems to have been fixed already in the development version of the typescript compiler 0.8: try 'npm install typescript#next -g' and then running the compiler again.
you should use default as the imported module name .
import {default as hbs} from "hbs";
this works same as
var hbs = require('hbs');
because require("hbs") imports default module exported by hbs.

Categories