At the bottom of my index.html file I have the following.
<script src="/resources/js/require.js"></script>
<script>
$(document).ready(function() {
require(['main'], function (main) {
main.start();
});
});
</script>
This does indeed load the main.js file and waits for it to finish before calling main.start(). Now the problem is the main variable that is returned is not the module but it is instead undefined.
Here is the main.js:
define('/src/main', ['exports', '../screens/loginScreen'], function (exports, _loginScreen) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.start = undefined;
function main() {};
var start = exports.start = function start() {
new _loginScreen.default().open();
};
});
//# sourceMappingURL=main.js.map
I tried having an actual return statement at the end of the main.js file. No matter what I return require still gives undefined.
I tried your code and got the same error. The problem I think has to do with your main.js location. If it is on src folder on the root of your project, you need to pass its relative from the root of your project to require, like this:
require(['src/main'], function (main) {
main.start();
});
Also, in your main.js, use relative path as well:
define('src/main', ['exports', '../screens/loginScreen'], function...
The problem with your actual module is that it does not return anything, so it will just return undefined.
You need to wrap your module in a function and return this function, here's what you will need:
define('/src/main', ['exports', '../screens/loginScreen'], function(exports, _loginScreen) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var Main = function Main() {
}
Main.start = exports.start = function start() {
new _loginScreen.default().open();
};
return new Main();
});
Or if you want your module not to be the same instance shared in all pages and to be always instanciated with the new keyword, you can just return the Main function:
return Main;
Instead of returning an instance of it in return new Main();.
Related
I have an old IIFE that is injected into legacy pages via <script src.
However, I want to use all these old libraries in a react app. I just need to use the global function exposed.
I figure loading dependencies that will work both via script or via react's import or nodejs require
Here is an example of an example IIFE
example.js :
var $ = $;
var geocomplete = $.fn.geocomplete;
var OtherExternalLib = OtherExternalLib;
var Example = (function() {
return {
init: function () {
// stuff
}
}
)();
Where the legacy code is calling Example.init(), and likewise the react code will call the same function.
Where $ (jQuery), $.fn.geocomplete, and OtherExternalLib are all dependencies that must be loaded, either they should be loaded on-demand or just throw a big loud error message.
I suspect if the solution loads dynamically example.js would look something like
var $ = load("\libs\jquery.js");
var geocomplete = load("\libs\$.fn.geocomplete.js");
var OtherExternalLib = load("\libs\OtherExternalLib.js");
var Example = (function() {
return {
init: function () {
// stuff
}
}
)();
And the legacy application can still use <script src=example.js and React can use
import {Example} from example
Understandably this is somewhat a round-about way to of using legacy code in new applications, so I am open to other ideas on how best to expose an IIFE (with or without dependencies) and using it in React
I am using react+typescript in my project with some limitations which is why I had to dynamically import my package (my project runs in a shell project with AMD module, not having my own startup, and change the way project files get bundled).
Since I could only use the dependent modules on the fly during the run time, I had to assume them were valid while building and bundling . Most of them were IIFE.
So I used the lazy dynamic import .
something like this
import("somePolyfill");
This would be translated by TSC
new Promise(function (resolve_3, reject_3) { require(["arrayPolyfill"], resolve_3, reject_3); });
This would call the IIFE and execute the polyfills or initializing any window or global variable, so the rest of the code is aware of that.
If it returns a module or throughs error can be handled like normal promise then and catch.
So I created a wrapper
export class DepWrap {
public static Module: any = {};
public constructor() {
this.getPI();
this.getSomeModule();
}
public async getPI() {
DepWrap.Module["PI"] = 3.14;
}
public async getSomeModule() {
await import('somepath/somemodule').then(($package) => {
DepWrap.Module["somemodule"] = $package;
}).catch(() => {
window.console.log("Some Module error");
});
}
}
this got compiled to
define(["require", "exports", "tslib"], function (require, exports, tslib_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var DepWrap = /** #class */ (function () {
function DepWrap() {
this.getPI();
this.getSomeModule();
}
DepWrap.prototype.getPI = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
DepWrap.Module["PI"] = 3.14;
return [2 /*return*/];
});
});
};
DepWrap.prototype.getSomeModule = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, new Promise(function (resolve_1, reject_1) { require(['somepath/somemodule'], resolve_1, reject_1); }).then(function ($package) {
DepWrap.Module["somemodule"] = $package;
}).catch(function () {
window.console.log("Some Module error");
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
DepWrap.Module = {};
return DepWrap;
}());
exports.DepWrap = DepWrap;
});
with this I could use all the dependency modules from my wrapper and every time i need to import a new one I would create another function to add that to my wrap module.
import { DepWrap } from "wrapper/path";
const obj = new DepWrap(); // initialize once in the beginning of project so it would import all the dependencies one by one .
Afterwards in all file, I can import my module from the wrapper
import { DepWrap } from "wrapper/path";
const { PI, somemodule} = DepWrap.Module;
I am not sure if the code will work for your scenario as well, but I guess tweaking it a bit might come in handy for your useCase .
Plus : if you are writing unit test case it will help jest to just ignore the modules and can create a mock for this so that you can test your actual code .
I am learning how to test Javascript code in Vanilla Javascript so I am following a tutorial. My project structure looks like this:
Modules/File.js,File2.js (each file contains a function I want to test)
app.js (a file for testing which works together with test.js file)
index.html
index.js (currently I keep my main code there)
test.html (I use it to run test, according to the tutorial)
test.js (this is where I describe tests)
I want to be able to import functions from File.js, and File2.js in app.js, so I can run tests. How do I achieve that?
P.S. I am using es6 modules import/export. But I would like to see how can I run imported functions for test. Maybe using $myapp global variable for it since thats how its done in the tutorial.
test.js:
(function () {
'use strict';
/**
* test function
* #param {string} desc
* #param {function} fn
*/
function it(desc, fn) {
try {
fn();
console.log('\x1b[32m%s\x1b[0m', '\u2714 ' + desc);
} catch (error) {
console.log('\n');
console.log('\x1b[31m%s\x1b[0m', '\u2718 ' + desc);
console.error(error);
}
}
function assert(isTrue) {
if (!isTrue) {
throw new Error()
}
}
it('test if its a string', function () {
assert($myapp.isValidString(2))
})
})();
app.js file:
(function () {
'use strict';
// Create a global variable and expose it to the world
var $myapp = {};
self.$myapp = $myapp;
$myapp.isValidString = function (value) {
return typeof value === 'string' || value instanceof String;
}
})();
From what I understand, you want to import JS functions from one file into another file.
ES6 introduced the module's functionality which allows the import/export of Javascript functions between different files.
Below is a simple example:
// helloworld.js
export function helloWorld() {
return 'Hello World!';
}
// main.js
import helloWorld from './helloworld.js';
console.log(helloWorld());
File 1 - Monitor.js
var MONITOR = (function () {
// File Content
return {
doThing: function() {
doThing();
}
};
})();
File 2 - Test.js
var monitor = require('../public/js/monitor.js');
I want to access doThing() in File 2. I have tried various syntax and no luck so far.
From the frontend HTML I can simply include Monitor.js in a script tag, and call MONITOR.doThing(); without trouble but in Test.js this is proving difficult.
Any advice on how?
You have to export MONITOR so that someone else can access it with require().
Add this:
module.exports = MONITOR;
at the bottom of Monitor.js.
And, if you want the monitor.doThing() method to return some value, then you have to add a return statement to the function as in:
var MONITOR = (function () {
// File Content
return {
doThing: function() {
return "hello";
}
};
})();
I have a worker.js file:
self.importScripts('/static/utils/utils.js')
onmessage = (e) => {
let a = e.data[0]
let b = e.data[1]
let c = func1(a,b)
postMessage(c)
}
The utils.js file looks something like this:
module.exports = {
func1: function(a,b){
return a+b
}
I keep getting error:
Uncaught ReferenceError: module is not defined
at utils.js:1
Obviously require, and import and any other server side imports aren't working but I'm not sure why it's having a problem with my importScripts - https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/importScripts
The correct solution is to pack your worker with webpack. If you don't want to do that, read below.
I usually write myself a polyfill for node require:
// This will not work in normal UI thread
// None of this should make it into production
function require(moduleName) {
self.module = { exports: null };
// Nasty sttuff right here, probably should throw error instead
if (moduleName == "fs")
return null;
// This part is especially unprofessional
if (!moduleName.endsWith(".js"))
moduleName += ".js";
importScripts(moduleName);
return self.module.exports;
}
This makes use of the fact that importScripts is synchronous. Note that this will still cause errors if you try to load native node modules (eg. fs) or if other module properties are used.
Try this utils.js:
(function () {
self.func1 = function (a, b) {
return a + b
}
}());
Try to do this:
//inside worker.js
self.addEventListener("message",(event)=>{
importScripts("module.js")
utils.print1()
utils.print2()
})
//inside module.js
//setting a variable in global scope, allows worker.js to use it.
var utils = {
print1(){
console.log("This is a content from a module.")
},
print2(){
console.log("This is a another content from a module.")
}
}
I have created the following:
module Admin.Grid {
export function addGridControls() {
$('#createLink')
.click(function () {
var $link = $(this);
$link.prop('disabled', true);
adminDialog($link);
return false;
});
}
}
This is converted to:
var Admin;
(function (Admin) {
(function (Grid) {
function addGridControls() {
$('#createLink').click(function () {
var $link = $(this);
$link.prop('disabled', true);
adminDialog($link);
return false;
});
Previously when it was not inside a module I called the function like this:
$(document).ready(function () {
"use strict";
addGridControls()
});
Now it's inside of a module what's the best way for me to call this
function so it gets executed every time the document is ready?
One way of doing this is, is to add the function to some object.
var Admin = {};
(function (Admin) {
(function (Grid) {
Admin.addGridControls = function () {
....
And call it like
$(document).ready(function () {
"use strict";
Admin.addGridControls()
});
As #Mike Lin has commented, you need to import the module.
Working in TypeScript (and assuming AMD module format, with your module in another file), you can do it like this:
import g = module('path-to-admin-grid-module');
$(document).ready(() => {
"use strict";
g.Admin.Grid.addGridControls();
});
Otherwise, if you're just using internal modules within the same file, it's as simple as:
$(document).ready(() => {
"use strict";
Admin.Grid.addGridControls();
});
The latter case is nicely previewed in the Walkthrough: Modules example here: http://www.typescriptlang.org/Playground/
There's a pretty good example of the former here: TypeScript compile AMD modules with required defines and AMD is covered in more detail here: http://requirejs.org/docs/whyamd.html