In my tsconfig.json when I change the compilerOptions.module from 'commonjs' to 'es6' or 'esnext' I get the error "SyntaxError: Unexpected token import" for any of my instances of
import * as React from 'react'
Thanks for your help
As #Amy said, Import & Export keywords are very new in JavaScript, their introduction starts with the new ES6 standard and the implementation for each browser is non-existent or partially implemented.
As wrote in the TypeScript documentation, import & export are currently used with CommonJS/AMD.
The combination of this two situations throws sometimes a SyntaxError depending on your TSConfig and/or your browser.
What I suggest
You want to use new ES6 standard
You keep your browser up to date and you refer to the #Amy provided a link to know about Import & Export implementation for each browser.
You don't want to use new ES6 standard
You come back to AMD or CommonJS in your TSConfig file. With this solution you will need to use RequireJS to manage the Import & Export or to bundle your Typescripts file using Webpack Or Browserify.
My Opinion
If your code is only for learning or for fun, you can stay with the new ES6 standard.
If it is for production, I suggest to use Webpack, which is difficult to handle but very powerful.
Related
I'm working on a CLI tool. I used "commander", which is a CommonJS module, to parse command-line arguments. I also want to use "p-map" to manage concurrency. However, "p-map" is a ES6 module.
Also I'm using Typescript.
Now both code editor and Typescript compiler won't complain. However I cannot execute my CLI tool. If I compile with "module":"commonjs", node would not load p-map and complains "Must use import to load ES Module... node_modules/p-map/index.js...require() of ES modules is not supported.". If I compile with "module":"es2015", use "require" to import the CommonJS modules, and add "type":"module" in my package.json, node would complain "ReferenceError: require is not defined".
I love the flexibility of Typescript/Javascript, however, it's time like this makes me miss Java. Java might be too prissy, but I don't spend hours trying to figure out import / export......
So, is it possible to use both CommonJS and ES6 module in a Node.JS command-line program?
To enhance compatibility, the (moderately new) node esm loader can import cjs-modules (e.g. import identifier from 'cjs-module-name';).
The other way around doesn't work, you can't require an esm-module, but dynamic import should work, if really necessary.
A related read may be the statement from p-map's owner regarding the topic.
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
I am totally new to Typescript and Javascript as well, so this is undoubtedly a noobie question. I was looking at some Typescript 2.0 tutorials on writing modules. In the typescript documentation, the authors describe both the ES6 module import/export methods, and the CommonJS, AMD, and other import/export methods.
However, it seems that in my tsconfig.json I can specify which module handler I want to use when compiling: AMD, CommonJS, etc.
So my confusion is, can I write the import/exports using the standard ES6 statements with import {}..., and then those get converted to the appropriate CommonJS or RequireJS syntax on compilation? Or do I need to write the appropriate CommonJS/RequireJS, etc. syntax in typescript and then the compilation step will just use whatever I produce?
Yes, it affects the generated code, not how you should write your code.
As a learning exercise, I'd recommend looking at the output with each of the values: None, CommonJS, AMD, System, UMD, ES6, ES2015 and ESNext.
Note that some compiler options aren't available in some configurations:
outFile can only be used with AMD or System
However ES6 / ES2015 may be used when targeting ES5 or lower
can I write the import/exports using the standard ES6 statements with
import {}..., and then those get converted to the appropriate CommonJS
or RequireJS syntax on compilation?
Yes exactly, import and export are part of TypeScript language, and they are virtually identical to import and export in ES6.
TypeScript will compile them according to the combination of module and target settings in tsconfig.json - if target is es6 or above (or if module itself is es6), import and export will remain in generated javascript, otherwise they will get converted to AMD or commonJS syntax.
I understand that import and require both can work if I want to use a class/module from another file. But I don't really know why
if I use require ('./config.json') will work,
but use import config from './config.json' would not work.
Does this because import only accept class/module, can't work with JSON?
I also know import is working when compile, but require is working on run time.
But really confused.
These are two totally different module systems and thus don't work the same way.
import is part of what referred to as "ES modules" i.e the native javascript implementation of modules brought by ES6.
require, on the other hand, is the import keyword of the commonjs module system. It is still used widely today, because Node.js uses it (there was no native module system in the JavaScript spec at the time of its creation).
Have a look at both the import/export docs on the MDN and the require docs on the node.js website.
Newbie Node question here.
I'm trying to use the Google Cloud Node client with an existing application (not written by me) that bundles its code with rollup.
I've tried importing the library with require, as per its documentation, as follows:
import REGL from "regl/dist/regl";
import Camera from "./lib/camera";
...
var gcloud = require('google-cloud');
But my application complains (CLARIFICATION: it only starts producing this error when I add the require statement, otherwise the imports work fine):
'import' and 'export' may only appear at the top level
So maybe I need to use import gcloud instead of require, but how? I tried looking at the code in node_modules and doing this instead:
import gcloud from "google-cloud/src/index";
But now I get a bunch of other errors
🚨 Unexpected token
node_modules/google-cloud/node_modules/ent/reversed.json (2:7)
1: {
2: "9": "Tab;",
^
How can I use import instead of require, or alternatively, how can I make require play nicely with import?
import is ES6 syntax. You either must use an experimental flag with nodejs or use babel to compile your js to be ES6 compatible.
EDIT:
Since the problem is with require and not import, i'm updating my answer.
I'm not sure what you're setup is but it's because, i'm guessing, google-cloud isn't written in es6. So you'll have to see if there's an es6 version in the src. If there is you could try (I doubt this will work)
Try:
import * as gcloud from 'google-cloud'
if that doesn't work - try a shimming module like riveted. You'll need webpack to compile this. Since you're using rollup.js, which i'm unfamiliar with you'll need a es5 to es6 compiler for this.