I am making use of react-router node module for routing in a react app. I am importing required modules as follows.
var React = require('react');
var Router = require('react-router');
var { Route, RouteHandler, Link } = Router;
// ... remaining code ...
But I am getting syntax error on line no. 3 i.e. var { Route, RouteHandler, Link } = Router;
Error:
Uncaught SyntaxError: Unexpected token {
Doing:
var {x,y} = {x:3,y:5};
Is called a destructuring assignment and is a new feature in JavaScript, it requires a new JavaScript runtime. This feature is not supported in NodeJS yet and not even in v8 yet (the JS engine JavaScript runs on). You can either assign it in 3 lines manually or use a tool like Traceur or Babel to compile your ES6 (new specification of EcmaScript) to ES5 (what node runs) code.
Related
Is it possible to pass options to ES6 imports?
How do you translate this:
var x = require('module')(someoptions);
to ES6?
There is no way to do this with a single import statement, it does not allow for invocations.
So you wouldn't call it directly, but you can basically do just the same what commonjs does with default exports:
// module.js
export default function(options) {
return {
// actual module
}
}
// main.js
import m from 'module';
var x = m(someoptions);
Alternatively, if you use a module loader that supports monadic promises, you might be able to do something like
System.import('module').ap(someoptions).then(function(x) {
…
});
With the new import operator it might become
const promise = import('module').then(m => m(someoptions));
or
const x = (await import('module'))(someoptions)
however you probably don't want a dynamic import but a static one.
Concept
Here's my solution using ES6
Very much inline with #Bergi's response, this is the "template" I use when creating imports that need parameters passed for class declarations. This is used on an isomorphic framework I'm writing, so will work with a transpiler in the browser and in node.js (I use Babel with Webpack):
./MyClass.js
export default (Param1, Param2) => class MyClass {
constructor(){
console.log( Param1 );
}
}
./main.js
import MyClassFactory from './MyClass.js';
let MyClass = MyClassFactory('foo', 'bar');
let myInstance = new MyClass();
The above will output foo in a console
EDIT
Real World Example
For a real world example, I'm using this to pass in a namespace for accessing other classes and instances within a framework. Because we're simply creating a function and passing the object in as an argument, we can use it with our class declaration likeso:
export default (UIFramework) => class MyView extends UIFramework.Type.View {
getModels() {
// ...
UIFramework.Models.getModelsForView( this._models );
// ...
}
}
The importation is a bit more complicated and automagical in my case given that it's an entire framework, but essentially this is what is happening:
// ...
getView( viewName ){
//...
const ViewFactory = require(viewFileLoc);
const View = ViewFactory(this);
return new View();
}
// ...
I hope this helps!
Building on #Bergi's answer to use the debug module using es6 would be the following
// original
var debug = require('debug')('http');
// ES6
import * as Debug from 'debug';
const debug = Debug('http');
// Use in your code as normal
debug('Hello World!');
I've landed on this thread looking up for somewhat similar and would like to propose a sort of solution, at least for some cases (but see Remark below).
Use case
I have a module, that is running some instantiation logic immediately upon loading. I do not like to call this init logic outside the module (which is the same as call new SomeClass(p1, p2) or new ((p1, p2) => class SomeClass { ... p1 ... p2 ... }) and alike).
I do like that this init logic will run once, kind of a singular instantiation flow, but once per some specific parametrized context.
Example
service.js has at its very basic scope:
let context = null; // meanwhile i'm just leaving this as is
console.log('initialized in context ' + (context ? context : 'root'));
Module A does:
import * as S from 'service.js'; // console has now "initialized in context root"
Module B does:
import * as S from 'service.js'; // console stays unchanged! module's script runs only once
So far so good: service is available for both modules but was initialized only once.
Problem
How to make it run as another instance and init itself once again in another context, say in Module C?
Solution?
This is what I'm thinking about: use query parameters. In the service we'd add the following:
let context = new URL(import.meta.url).searchParams.get('context');
Module C would do:
import * as S from 'service.js?context=special';
the module will be re-imported, it's basic init logic will run and we'll see in the console:
initialized in context special
Remark: I'd myself advise to NOT practice this approach much, but leave it as the last resort. Why? Module imported more than once is more of an exception than a rule, so it is somewhat unexpected behavior and as such may confuse a consumers or even break it's own 'singleton' paradigms, if any.
I believe you can use es6 module loaders.
http://babeljs.io/docs/learn-es6/
System.import("lib/math").then(function(m) {
m(youroptionshere);
});
You just need to add these 2 lines.
import xModule from 'module';
const x = xModule('someOptions');
Here's my take on this question using the debug module as an example;
On this module's npm page, you have this:
var debug = require('debug')('http')
In the line above, a string is passed to the module that is imported, to construct. Here's how you would do same in ES6
import { debug as Debug } from 'debug'
const debug = Debug('http');
Hope this helps someone out there.
I ran into an analogous syntax issue when trying to convert some CJS (require()) code to ESM (import) - here's what worked when I needed to import Redis:
CJS
const RedisStore = require('connect-redis')(session);
ESM Equivalent
import connectRedis from 'connect-redis';
const RedisStore = connectRedis(session);
You can pass parameters in the module specifier directly:
import * as Lib from "./lib?foo=bar";
cf: https://flaming.codes/en/posts/es6-import-with-parameters
Using a JS sdk of Icon a blockchain. Trying to using the SDK API calls and I'm having issues import or require
When I use Import an error is thrown SyntaxError: Cannot use import statement outside a module
When I use require an error is thrown ReferenceError: HttpProvider is not defined
Below is the link to Icon Icx Github
Icon GitHub
const IconService = require('icon-sdk-js');
//import IconService from 'icon-sdk-js';
const provider = new HttpProvider('https://bicon.net.solidwallet.io/api/v3');
const iconService = new IconService(provider);
const totalSupply = iconService.getTotalSupply().execute();
console.log(totalSupply);
In NodeJS you use require to "import" node modules and dependencies to your project
const IconService = require('icon-sdk-js');
Regarding this line const provider = new HttpProvider('https://bicon.net.solidwallet.io/api/v3');
Where are you importing HttpProvider from? HttpProvider is not built in Javascript library.
If it is a node module, you have to do something similar
const HttpProvider = require('HttpProvider'); (in your question you don't specify what HttpProvider is)
I think you might use IconService.HttpProvider('the url'); to use the constructor
Building on related issue: Load "Vanilla" Javascript Libraries into Node.js
I'm trying to load a 'Vanilla' Javascript library 'rsa.js' into NodeJS, using the method described by Chris W. in the question above. In essence I've created a custom node_modules directory like this:
./node_modules/rsa/rsa-lib/rsa.js
./node_modules/rsa/rsa-lib/README
./node_modules/rsa/index.js
Only problem is, compiling the module fails on the last line of rsa.js:
undefined:836
export default rsa;
SyntaxError: Unexpected token export
rsa.js
var rsa = {};
(function(rsa) {
...
})(rsa);
console.log("rsa",rsa);
export default rsa;
index.js
var fs = require('fs');
// Read and eval library
filedata = fs.readFileSync('./node_modules/rsa/rsa-lib/rsa.js','utf8');
eval(filedata);
/* The rsa.js file defines a class 'rsa' which is all we want to export */
exports.rsa = rsa
Any suggestions how to fix this problem?
The error 'Unexpected token export' is caused because the library is using
export default thingToExport;
instead of
module.exports = thingToExport
This is an ES6 feature not supported by Node (yet), so when Node tries to run the code, it throws an error.
How to solve: try modifying the last line of the library so it says module.exports = rsa;.
I should add, though, that eval is not a good way to load a library into your own code. That is what require is for. If you have installed this library with npm i and it is in your node_modules, you should be able to load it into your code with var rsa = require('rsa');.
Again though, if you're not transpiling the code, it may have problems with export default, so you will probably want to change that to module.exports either way.
Is it possible to pass options to ES6 imports?
How do you translate this:
var x = require('module')(someoptions);
to ES6?
There is no way to do this with a single import statement, it does not allow for invocations.
So you wouldn't call it directly, but you can basically do just the same what commonjs does with default exports:
// module.js
export default function(options) {
return {
// actual module
}
}
// main.js
import m from 'module';
var x = m(someoptions);
Alternatively, if you use a module loader that supports monadic promises, you might be able to do something like
System.import('module').ap(someoptions).then(function(x) {
…
});
With the new import operator it might become
const promise = import('module').then(m => m(someoptions));
or
const x = (await import('module'))(someoptions)
however you probably don't want a dynamic import but a static one.
Concept
Here's my solution using ES6
Very much inline with #Bergi's response, this is the "template" I use when creating imports that need parameters passed for class declarations. This is used on an isomorphic framework I'm writing, so will work with a transpiler in the browser and in node.js (I use Babel with Webpack):
./MyClass.js
export default (Param1, Param2) => class MyClass {
constructor(){
console.log( Param1 );
}
}
./main.js
import MyClassFactory from './MyClass.js';
let MyClass = MyClassFactory('foo', 'bar');
let myInstance = new MyClass();
The above will output foo in a console
EDIT
Real World Example
For a real world example, I'm using this to pass in a namespace for accessing other classes and instances within a framework. Because we're simply creating a function and passing the object in as an argument, we can use it with our class declaration likeso:
export default (UIFramework) => class MyView extends UIFramework.Type.View {
getModels() {
// ...
UIFramework.Models.getModelsForView( this._models );
// ...
}
}
The importation is a bit more complicated and automagical in my case given that it's an entire framework, but essentially this is what is happening:
// ...
getView( viewName ){
//...
const ViewFactory = require(viewFileLoc);
const View = ViewFactory(this);
return new View();
}
// ...
I hope this helps!
Building on #Bergi's answer to use the debug module using es6 would be the following
// original
var debug = require('debug')('http');
// ES6
import * as Debug from 'debug';
const debug = Debug('http');
// Use in your code as normal
debug('Hello World!');
I've landed on this thread looking up for somewhat similar and would like to propose a sort of solution, at least for some cases (but see Remark below).
Use case
I have a module, that is running some instantiation logic immediately upon loading. I do not like to call this init logic outside the module (which is the same as call new SomeClass(p1, p2) or new ((p1, p2) => class SomeClass { ... p1 ... p2 ... }) and alike).
I do like that this init logic will run once, kind of a singular instantiation flow, but once per some specific parametrized context.
Example
service.js has at its very basic scope:
let context = null; // meanwhile i'm just leaving this as is
console.log('initialized in context ' + (context ? context : 'root'));
Module A does:
import * as S from 'service.js'; // console has now "initialized in context root"
Module B does:
import * as S from 'service.js'; // console stays unchanged! module's script runs only once
So far so good: service is available for both modules but was initialized only once.
Problem
How to make it run as another instance and init itself once again in another context, say in Module C?
Solution?
This is what I'm thinking about: use query parameters. In the service we'd add the following:
let context = new URL(import.meta.url).searchParams.get('context');
Module C would do:
import * as S from 'service.js?context=special';
the module will be re-imported, it's basic init logic will run and we'll see in the console:
initialized in context special
Remark: I'd myself advise to NOT practice this approach much, but leave it as the last resort. Why? Module imported more than once is more of an exception than a rule, so it is somewhat unexpected behavior and as such may confuse a consumers or even break it's own 'singleton' paradigms, if any.
I believe you can use es6 module loaders.
http://babeljs.io/docs/learn-es6/
System.import("lib/math").then(function(m) {
m(youroptionshere);
});
You just need to add these 2 lines.
import xModule from 'module';
const x = xModule('someOptions');
Here's my take on this question using the debug module as an example;
On this module's npm page, you have this:
var debug = require('debug')('http')
In the line above, a string is passed to the module that is imported, to construct. Here's how you would do same in ES6
import { debug as Debug } from 'debug'
const debug = Debug('http');
Hope this helps someone out there.
I ran into an analogous syntax issue when trying to convert some CJS (require()) code to ESM (import) - here's what worked when I needed to import Redis:
CJS
const RedisStore = require('connect-redis')(session);
ESM Equivalent
import connectRedis from 'connect-redis';
const RedisStore = connectRedis(session);
You can pass parameters in the module specifier directly:
import * as Lib from "./lib?foo=bar";
cf: https://flaming.codes/en/posts/es6-import-with-parameters
Edit - Answer: encapsulating the imports work as required:
# index.js
var myLibrary {
ProfileApp: require('./components/ProfileApp.react'),
ProfileStore: require('./stores/ProfileStore'),
}
module.exports = myLibrary;
I can now do
var lib = require('myLibrary');
var ProfileApp = lib.ProfileApp;
End of edit
I have developped a react/flux libray which I need to package using webpack. I do this for the first time and my exports seem wrong... (the library itself works well).
My (simplified) index.js file is
# index.js
module.exports = require('./components/ProfileApp.react');
module.exports = require('./stores/ProfileStore');
...
The code is correctly compiled and installed in node_modules, but does not work when imported.
# whatever.file.doing.imports
var myLibrary = require('myLibrary'); # works well
var ProfileApp = myLibrary.ProfileApp; # works only if I call it --> myLibrary.ProfileApp()
var ProfileStore = myLibrary.ProfileStore; # does not work and myLibrary.ProfileStore() raises "is not a function error"
I think my exports in index.js should use another syntax. For instance, React Router (https://github.com/rackt/react-router/blob/master/modules/index.js) uses
export Router from './Router';
# which can be simply instantiated writing
var Router = ReactRouter.Router;
This syntax raises an error when used in my library. Do you know if I have to use plugin to be able to use this syntax, or if I can write it differently?
Thank you very much!
The special export syntax that React Router uses is from ES6 and is "transpiled" by the Babel loader that you see in use in the webpack config on line 23. Also note that that line only applies to files that have a ".js" extension. Since you have files with ".react" extensions, you may need to change that line.
Unfortunately that does not explain your issue with having to call ProfileApp as a function. Maybe if you posted the code for the ProfileApp and ProfileStore, that would help.