Import Vanilla JavaScript library in Angular 6 - javascript

I am getting following error when try to import existing Vanilla JavaScript library to Angular 6 component.
Please suggest how to fix it.
Syntax to import the library, I have written
import * as ExistingLibrary from 'app/main/libs/ExistingLibrary.js';
ExistingLibrary.doJob is not a function
External JavaScript library - ExistingLibrary.js
var ExistingLibrary = new (function () {
this.doJob = doJob;
function doJob(template, options) {
function f1(template, options) {}
function f2(template, options) {}
});

var ExistingLibrary = new (function () {
this.doJob = doJob;
function doJob(template, options) {
function f1(template, options) {}
function f2(template, options) {}
});
instead of this you need to export the functions like this:
export function doJob(template, options) { }

The existing library should probably be a module of some short, so that you module bundler can add it to your module system.
The first thing to look up is if the existing library has a npm package?
In that case you probably should use the NPM version of the existing library, or consider upgrading the existing library to a version that comes with module system.
You probably need something like
export const ExistingLibrary = ...
or
module.exports = ExistingLibrary =
If modifying the existing library is not possible, you'll have to configure your module bundler or JS build pipeline to handle libraries that do not include modules and/or require global this. E.g. using something like https://www.npmjs.com/package/webpack-raw-bundler

Related

ES6 module import a function value [duplicate]

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

How to expose Webpack-built library as function?

I'm working on a JavaScript library which is essentially a Vue.js component bundled together with Vue itself. The project was started via the vue-cli and is packaged with Webpack.
When this library gets imported via a <script> tag, I'd like it to expose a single function like:
Mapboard({div: '#some-div')
The library itself is currently just:
export default (opts) => console.log('hello')
I tweaked my Webpack config to set a library name:
module.exports = {
output: {
library: 'Mapboard'
}
}
which successfully exposes a global called Mapboard, but it's object, not a function:
{
__esModule: true,
default: function (e) {...}
}
Is there any way to prevent Webpack from exporting this as an ES6 module? I'd like it to just be the function exported by the module, as shown above.
Take a look to this webpack 2 official article: https://webpack.js.org/guides/author-libraries/
That is for ES5 and ES6, if you are building your library using TypeScript, you probably need extra configuration for typings...
http://siawyoung.com/coding/javascript/exporting-es6-modules-as-single-scripts-with-webpack.html
This article helps a lot.The core point to solve this problem is:
The fix for this is simple: simply write a file that imports those ES6 modules the ES6 way, but exports them in nodeJS module.exports style. Webpack will then handle them correctly!
That's right!Just change your function into :
function foo(opts) {
console.log('hello');
}
module.exports = foo;
And everything should work as expected.
NOTE:Code write like this may not work:
module.exports = function foo(opts) {
console.log('hello');
}

is there any way to obtain a reference to (and use) an es6/2015 import in the same expression? [duplicate]

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

How does lazy module loading work in ES6

How can I lazily-load ES6 modules? By lazy, I mean I don't want to actually load modules that aren't needed. For example, here's something I can do with RequireJS:
function someEventHandler() {
var SomeModule = require('some-module'),
module = new SomeModule();
// ...
}
Something along the same lines doesn't appear to be possible using ES6 imports:
// Doesn't appear to be valid...
function someEventHandler() {
import SomeModule from 'some-module';
var module = new SomeModule();
// ...
}
Are there any viable techniques to only pull in dependencies when needed, using ES6 modules? Or is the only path to trace the full dependency graph and fetch everything up-front?
The import statement will only work in the very top of files, and it will load all of them. This is mainly to avoid potential issues with circular dependencies.
There will also be a way to do asynchronous loading; however the specification doesn't seem to be finalized yet. The ES6 module loader polyfill package uses a method called System.import(moduleName) that returns a promise and the final specification is likely to look similar:
function someEventHandler() {
System.import('some-module').then((SomeModule) => {
var module = new SomeModule();
// ...
})
}
Example for lazyloading jQuery in ES6 :
import('jquery').then((jquery) => {
// Because jquery is the module, here is the new syntax for using this
window.$ = jquery.default;
window.$('#id');
});

Is it possible to use nodejs style modules in typescript?

In node, I can define a module like this by setting the properties of exports object :
module.js
exports.fun = function (val) {
console.log(val);
};
and the ask for it using var module = require('module') in and the use the module.fun() function.
Is it possible to define the module in TypeScript like this:
module.ts
exports.fun = function (val :string) {
console.log(val);
};
and then import the module in some other file using node like syntax, say, import module = require('module.ts') so that it compiles to nodejs but, if now I use module.fun() in some .ts file, it should give me an error if the arguments don't match the type specified in module.ts file.
How can I do this in Typescript?
Yes it is possible to use the true js syntax. You are receiving the error since you are using the import keyword which expects the imported file to use the export keyword. If you want the js exports.foo syntax you should use var instead of import. The following will compile/work just fine:
var module = require('module.ts')
What you've described basically exactly how external modules in TypeScript work.
For example:
Animals.ts
export class Animal {
constructor(public name: string) { }
}
export function somethingElse() { /* etc */ }
Zoo.ts
import a = require('./Animals');
var lion = new a.Animal('Lion'); // Typechecked
console.log(lion.name);
Compile with --module commonjs and run zoo.js in node.

Categories

Resources