How to Eval with imported Module in ES6 and Webpack - javascript

I use Webpack as a package manager and ES6. Looks like an imported module is not correctly evaluated with eval.
How to eval a string using the imported Module ?
Code:
In a global scope:
<script type="text/javascript">
var tableDefinition = '{ value: "myvalue", myfunction: (v) => { return DateFormat.format(v) }}';
</script>
In my module:
import DateFormat from "~modules/DateFormat"; // a module helper written by me
class GeneriClass {
constructor() {
DateFormat.init();
let columns = eval(tableDefinition); // this code retrieves 'DateFormat' not defined
}
}
The error on eval is: "'DateFormat' not defined!"

Related

Mix Node's CommonJS and Typescript's ES modules

I have a legacy app in Node.js v10 (but upgrading is an option) which uses CommonJS modules (require).
The codebase is written in JS.
Now, I want to refactor part of the project and write it in Typescript using TS modules (import/export) and classes.
What is the best way to interface those newly generated JS files (compiled from TS) from my legacy JS code?
Say I have a class in TS:
export default class DemoClass {
public static sayHello() {
console.log("Hello from demo class...");
}
}
which gets compiled to:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var DemoClass = /** #class */ (function () {
function DemoClass() {
}
DemoClass.sayHello = function () {
console.log("Hello from demo class...");
};
return DemoClass;
}());
exports.default = DemoClass;
//# sourceMappingURL=DemoClass.js.map
I have set "module": "commonjs" in my tsconfig.json.
Now, how do I require that DemoClass.js from my legacy app.js and e.g. invoke sayHello()?
The following code seems to work, but this "default" stuff does not seem right:
var DemoClass = require('./lib/DemoClass');
DemoClass.default.sayHello();
Instead of using export default, use export =.
export = class DemoClass {
public static sayHello() {
console.log("Hello from demo class...");
}
}
Playground link

Use rollup.js with jQuery adaptor in same file

I have the main function to export and the jQuery adaptor in the same file. And I would like to keep them this way.
Is there a way with rollup.js to create the bundle file compatible with AMD, CommonJS and Browsers?
Right now I have this test file:
//src/foo.js
export default function(){
function initialise() {
var TEST = {};
TEST.version = '1.0.0';
TEST.hello = function(){
console.log("hello man!!");
};
return TEST;
}
//jQuery adapter
(function($){
$.fn.demo = function(options) {
$.fn.demo.test = 'test';
};
})(jQuery);
return initialise;
};
And I tried using this rollup config:
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'umd',
globals: {
$: '$'
}
}
};
However I can't seem to have access to $.fn.demo:
// src/main.js
import jQuery from 'jQuery';
import pepe from './foo.js';
console.log(jQuery); //<--- undefined
console.log($); //<--- undefined
console.log("-- JS--");
console.log(pepe); //<---- working fine
console.log("-- $.fn.demo --");
console.log($.fn.demo); //<--- undefined
Note that in your main.js file pepe is a function (one which you exported from foo) and you didn't call it hence $.fn.demo is undefined. You must call pepe(); in order for you adapter to be executed.
See also how to tell Rollup that jquery is external and the jquery module ID equates to the global $ variable.

In NodeJS, how to use the same object in different files?

there are three files :
a.js
b.js
token.js
I need to use the same token in a.js and b.js, How do I achieve that? for example, set token in a.js and get token in b.js
I am using a singleton but it does not work :(
token.js
class Token {
private static instance: Token
private _hash = 'default-hash'
private constructor() {
}
static getInstance() {
if (!Token.instance) {
Token.instance = new Token()
}
return Token.instance
}
//setter and getter for _hash
}
export default Token
The module.exports or exports is a special object which is included in every JS file in the Node.js application by default. module is a variable that represents current module and exports is an object that will be exposed as a module. So, whatever you assign to module.exports or exports, will be exposed as a module.
Examples: Export Literals
File: message.js
module.exports = 'Hello world';
Now, import this message module and use it as shown below.
File: app.js
var msg = require('./messages.js');
console.log(msg);
Example: Export Object
message.js
exports.SimpleMessage = 'Hello world';
//or
module.exports.SimpleMessage = 'Hello world';
In the above example, we have attached a property "SimpleMessage" to the exports object. Now, import and use this module as shown below.
app.js
var msg = require('./messages.js');
console.log(msg.SimpleMessage);
Example: Export Function
You can attach an anonymous function to exports object as shown below.
log.js
module.exports = function (msg) {
console.log(msg);
};
Now, you can use the above module as below.
app.js
var msg = require('./log.js');
msg('Hello World');

How to call global function from controller class in AngularJs component

In app.module.js file, import JS file from external lib
import 'assets/scripts/admin';
with global function:
function anonymousAdmin() {
"use strict";
implementation();
}
Now in app.component.js file have controller with function call:
export const AppComponent = {
controller: class AppComponent {
$onInit() {
/* global anonymousAdmin */
anonymousAdmin();
}
}
};
Run Webpack/Babel to save all files (ES6) into one file (ES5). Unfortunately i have error in console:
ReferenceError: anonymousAdmin is not defined
Someone knows how I can call this function in the controller?
anonymousAdmin is not global function. The file is imported as ES module, and ES modules force strict mode that prevents them from leaking variables to global scope.
It should be explicitly defined as a global:
function anonymousAdmin() {...}
window.anonymousAdmin = anonymousAdmin;
If the file belongs to third-party module that cannot be directly edited, and considering that Webpack is being used, the latter can be configured to expose a variable from file ES module export with exports loader, something like:
...
module: {
rules: [
{
test: require.resolve('assets/scripts/admin'),
use: 'exports-loader?anonymousAdmin'
}
]
},
...
And the function is being imported like:
import { anonymousAdmin } from 'assets/scripts/admin';
Try this one. You need to have alias for the script.
import * as admin from 'assets/scripts/admin';
export const AppComponent = {
controller: class AppComponent {
$onInit() {
/* global anonymousAdmin */
admin.anonymousAdmin();
}
}
};

Namespace is undefined after compile

I am writing a little game engine in typescript, and when I compile it to javascript, I get an error when running the javascript. It compiles without error too.
My main entry file (main.ts) starts with these two lines:
require('./core/Obj');
require('./core/Component');
It builds out fine but when I run it, the second require has some issues and gives this error:
Uncaught TypeError: Class extends value undefined is not a function or null
core/Obj.ts
namespace GameEngine {
export class Obj {
// Some functions/methods
}
}
core/Component.ts
namespace GameEngine {
export class Component extends Obj {
}
}
Then once it is compiled, it looks something like this:
(function (exports, require, module, __filename, __dirname, process, global) { (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[
function(require,module,exports){
var GameEngine;
(function (GameEngine) {
class Component extends GameEngine.Obj { // Error is here
}
GameEngine.Component = Component;
})(GameEngine || (GameEngine = {}));
},{}],
5:[function(require,module,exports){
var GameEngine;
(function (GameEngine) {
class Obj {
}
GameEngine.Obj = Obj;
})(GameEngine || (GameEngine = {}));
},{}]
});
Here is the gulp task that I am running:
gulp.task('compile-engine', function () {
return browserify()
.add('./GameEngine/main.ts')
.plugin(tsify, {})
.bundle()
.on('error', function (error) { throw error; })
.pipe(source('gameEngine.js'))
.pipe(buffer())
.pipe(gulp.dest('build/'));
});
Each module has its own GameEngine namespace - as modules don't pollute the global scope. (In the compiled bundle in your question, you can see that they are separate.) There is an answer here that explains namespaces and modules.
In using tsify, you're using (external) modules. Things can be made simpler if you do away with the namespacing. The TypeScript Handbook has this to say about using namespaces with modules:
A key feature of modules in TypeScript is that two different modules will never contribute names to the same scope. Because the consumer of a module decides what name to assign it, there's no need to proactively wrap up the exported symbols in a namespace.
You could change the exports and imports to something like this:
core/Obj.ts
export class Obj {
// Some functions/methods
}
core/Component.ts
import { Obj } from "./Obj";
export class Component extends Obj {
}
main.ts
import { Component } from "./core/Component";
// Do something with Component

Categories