Using non-npm(legacy) javascript library with Jspm - javascript

I'm trying to integrate this library which is non-npm. I failed many times already as I always thrive for using some modern framework which makes it impossible for me to integrate.
I tried backbone.js with require.js, even Dart and now I'm stubbornly trying to achieve the same using gulp, jspm, aurelia. The problem is that this library probably doesn't follow the module concept. I had lot of problems with initialization of this lib, made a lot of shimming.
So the question is how can I use such kind of libraries. Using in the same time modern ways to build javascript applications.

For older libraries that don't follow modern module patterns the approach is usually to shim them.
If you're using webpack, you can shim modules by declaring imports and exports.
RequireJS has a similar shim config, but needs more wiring to declare dependencies. I'd strongly recommend webpack over Grunt/gulp/RequireJS.
However, looking at the mapy.cz library you linked, it dynamically loads many other assets by writing script tags to the page. I can see how that's hard to work with.
I think your options are really:
If the licence is a friendly open-source one, fork it and expose it in a more modern module format that can be easily imported via npm. Check out the UMD style - you can write a declaration that'll export the module in a format usable by most module systems (AMD, CommonJS, etc). The webpack library and externals page has some guidelines for writing modules in a format that others can use.
If it's not an open-source licence, you could get in touch with the author(s) to ask them to change how the library is bundled and loaded. It should be an easy sell: an npm module would allow more people to use their code, and would be easier to work with - especially if they started versioning it. You could offer to do it for them, or just do it as an example they can copy from.
They have a page detailing terms and conditions, as well as a 'contact us' button - I'd start there: http://napoveda.seznam.cz/cz/mapy/mapy-licencni-podminky/licencni-podminky-mapovych-podkladu/

After looking at the code, I got it working (I used require.js, but you can use whatever you like):
// main.js
////////////////
require(['mapy-loader'], function (Loader) {
// load mapy async and wait for it to finish
Loader.async = true;
Loader.load(null, null, function () {
var stred = SMap.Coords.fromWGS84(14.41, 50.08);
var mapa = new SMap(JAK.gel("mapa"), stred, 10);
mapa.addDefaultLayer(SMap.DEF_BASE).enable();
mapa.addDefaultControls();
});
});
<!doctype html>
<html>
<head>
<script data-main="main.js" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js"></script>
<script>
requirejs.config({
paths: {
"mapy-loader": "//api.mapy.cz/loader"
},
shim: {
'mapy-loader': {exports: 'Loader'}
}
});
</script>
</head>
<body>
<div id="mapa" style="width:600px; height:400px;"></div>
</body>
</html>
(It won't run in the snippet here, since the JavaScript should be placed in a file named main.js)
EDIT:
Adding jspm / System.js snippet:
(main.js is unchanged)
// main.js
////////////////
define(['mapy-loader'], function (Loader) {
// load it async and wait for it to finish!
Loader.async = true;
Loader.load(null, null, function () {
var stred = SMap.Coords.fromWGS84(14.41, 50.08);
var mapa = new SMap(JAK.gel("mapa"), stred, 10);
mapa.addDefaultLayer(SMap.DEF_BASE).enable();
mapa.addDefaultControls();
});
});
<!doctype html>
<html>
<head>
<script src="jspm_packages/system.js"></script>
<script>
System.config({
baseURL: "/",
defaultJSExtensions: true,
transpiler: "babel",
paths: {
"mapy-loader": "//api.mapy.cz/loader"
},
meta: {
'mapy-loader': {
format: 'global',
exports: 'Loader'
}
}
});
</script>
<script>
System.import('main.js');
</script>
Run
</head>
<body>
<div id="mapa" style="width:600px; height:400px;"></div>
</body>
</html>

Related

How can I run a Python function with JavaScript and HTML? [duplicate]

I am writing an application with the Node.js, Express.js, and Jade combination.
I have file client.js, which is loaded on the client. In that file I have code that calls functions from other JavaScript files. My attempt was to use
var m = require('./messages');
in order to load the contents of messages.js (just like I do on the server side) and later on call functions from that file. However, require is not defined on the client side, and it throws an error of the form Uncaught ReferenceError: require is not defined.
These other JavaScript files are also loaded at runtime at the client, because I place the links at the header of the webpage. So the client knows all the functions that are exported from these other files.
How do I call these functions from these other JavaScript files (such as messages.js) in the main client.js file that opens the socket to the server?
This is because require() does not exist in the browser/client-side JavaScript.
Now you're going to have to make some choices about your client-side JavaScript script management.
You have three options:
Use the <script> tag.
Use a CommonJS implementation. It has synchronous dependencies like Node.js
Use an asynchronous module definition (AMD) implementation.
CommonJS client side-implementations include (most of them require a build step before you deploy):
Browserify - You can use most Node.js modules in the browser. This is my personal favorite.
Webpack - Does everything (bundles JavaScript code, CSS, etc.). It was made popular by the surge of React, but it is notorious for its difficult learning curve.
Rollup - a new contender. It leverages ES6 modules and includes tree-shaking abilities (removes unused code).
You can read more about my comparison of Browserify vs (deprecated) Component.
AMD implementations include:
RequireJS - Very popular amongst client-side JavaScript developers. It is not my taste because of its asynchronous nature.
Note, in your search for choosing which one to go with, you'll read about Bower. Bower is only for package dependencies and is unopinionated on module definitions like CommonJS and AMD.
I am coming from an Electron environment, where I need IPC communication between a renderer process and the main process. The renderer process sits in an HTML file between script tags and generates the same error.
The line
const {ipcRenderer} = require('electron')
throws the Uncaught ReferenceError: require is not defined
I was able to work around that by specifying Node.js integration as true when the browser window (where this HTML file is embedded) was originally created in the main process.
function createAddItemWindow() {
// Create a new window
addItemWindown = new BrowserWindow({
width: 300,
height: 200,
title: 'Add Item',
// The lines below solved the issue
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})}
That solved the issue for me. The solution was proposed here.
ES6: In HTML, include the main JavaScript file using attribute type="module" (browser support):
<script type="module" src="script.js"></script>
And in the script.js file, include another file like this:
import { hello } from './module.js';
...
// alert(hello());
Inside the included file (module.js), you must export the function/class that you will import:
export function hello() {
return "Hello World";
}
A working example is here. More information is here.
Replace all require statements with import statements. Example:
// Before:
const Web3 = require('web3');
// After:
import Web3 from 'web3';
It worked for me.
In my case I used another solution.
As the project doesn't require CommonJS and it must have ES3 compatibility (modules not supported) all you need is just remove all export and import statements from your code, because your tsconfig doesn't contain
"module": "commonjs"
But use import and export statements in your referenced files
import { Utils } from "./utils"
export interface Actions {}
Final generated code will always have(at least for TypeScript 3.0) such lines
"use strict";
exports.__esModule = true;
var utils_1 = require("./utils");
....
utils_1.Utils.doSomething();
This worked for me
Get the latest release from the RequireJS download page
It is the file for RequestJS which is what we will use.
Load it into your HTML content like this:
<script data-main="your-script.js" src="require.js"></script>
Notes!
Use require(['moudle-name']) in your-script.js,
not require('moudle-name')
Use const {ipcRenderer} = require(['electron']),
not const {ipcRenderer} = require('electron')
Even using this won't work. I think the best solution is Browserify:
module.exports = {
func1: function () {
console.log("I am function 1");
},
func2: function () {
console.log("I am function 2");
}
};
-getFunc1.js-
var common = require('./common');
common.func1();
window = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
I confirm. We must add:
webPreferences: {
nodeIntegration: true
}
For example:
mainWindow = new BrowserWindow({webPreferences: {
nodeIntegration: true
}});
For me, the problem has been resolved with that.
People are asking what is the script tag method. Here it is:
<script src='./local.js'></script>.
Or from network:
<script src='https://mycdn.com/myscript.js'></script>
You need plugin the right url for your script.
I was trying to build metronic using webpack. In my package.json I had to remove the "type": "module" section.

How do I import and use my transpiled Typescript library using SystemJS?

I have a TypeScript library that I've created. I need to know how to import and use this library in a browser. First, I am using tsc v2.1.4; I am also using gulp's TypeScript plugins to help with the development process. I have a gulp task that compiles my *.ts files to *.js files as follows.
gulp.task('dist', function() {
var tsResult =
gulp.src(['src/**/*.ts'])
.pipe(sourcemaps.init())
.pipe(tsc({ out: 'mylib.js', noImplicitAny: true, target: 'es6', sourceMap: true, module: 'system' }));
return tsResult.js
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist'));
});
The generated mylib.js file looks something like the following.
System.register("vehicle/car",[], function(exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var Car;
return {
execute: function() {
Car = class Car {
constructor(make, model) {
this.make = make;
this.model = model;
}
};
exports_1("Car", Car);
};
});
I then attempt to follow the documentation on SystemJS and create a index.html to test usage.
<html>
<head>
<title>Test MyLib</title>
</head>
<body onload="start()">
<script src="node_modules/systemjs/dist/system.js"></script>
<script>
function start() {
SystemJS.import('dist/mylib.js')
.then(function(lib) {
console.log(lib);
//what do i do here? how do i use my classes/objects here?
});
}
</script>
</body>
</html>
Looking at the JavaScript console, I see no errors. Where I log the lib out, it is just an Object with a bunch of functions that I'm not sure how to use to instantiate the classes/objects from my library.
I'm continuing to read more on how this TypeScript to ES6 to ES5 stuff works. Apparently, even though I've generated a JavaScript file (e.g. mylib.js) I just can't simply reference it like
<script src="dist/mylib.js"></script>"
and then use it. I have to go through SystemJS (which I'm new to and is a part of the confusion). Apparently, it seems like I can just reference my *.ts files directly and use other plugins (babel) with SystemJS to transpile on the fly. It doesn't help that the documentation on babel systemjs plugin is out of date (the usage instructions is out of date it seems).
The SystemJS usage instructions are a bit confusing too. In some cases I see SystemJS.config({...}) and in some cases I see System.config({...}). I'm speculating they changed SystemJS from System, but I'm really not sure.
I'd appreciate clarification on how to go from a TypeScript library project all the way browser usage; any online examples or guidance on here is appreciated (and I'm continuing to search as well).

How can I use a videojs plugin when I also use RequireJS

I'm working on a website that includes some JS code that I do not control. That code uses RequireJS to load dependencies and all.
Disclaimer: I'm a RequireJS noob. I understand the basics, but that's pretty much it...
In my website, I need to use VideoJS. VideoJS can work with, or without RequireJS but from what I understand, if RequireJS is used somewhere in the page, I cannot use VideoJS without it.
So I'm loading VideoJS with RequireJS like this:
var MyRequire = requirejs.config({
baseUrl: '/_/js',
paths: {
videojs: 'http://vjs.zencdn.net/5.3.0/video'
}
});
MyRequire(["videojs"], function(videojs) {
videojs('myPlayer', {}, function(){
console.log('...');
});
});
And it's working.
But I want to use a VideoJS plugin to manage preroll ads. (https://github.com/dirkjanm/videojs-preroll)
I tried to include the plugin script with RequireJS, the script is included but as soon as the plugin tries to access the videojs object, I get an error telling me that videojs is not defined.
My guess is that when I load VideoJS as a RequireJS module, it's not in the global scope and the plugin that I'm using is looking for VideoJS in the global scope and that's why I get that error.
Is there any way I can use VideoJS without loading it as a RequireJS module? Or how can I help the plugin find the VideoJS object?
Thanks for your help!
You should use shim from requirejs and inject videojs into global scope.
I made an example of code for your case. I tested it and it works (you can see images below):
Loading order:
"videojs"
"add-video-js-in-global-scope"
"ads" (at this moment videojs var already in window object)
"preroll"
Requirejs analysis order:
requirejs(["preroll", "ads"] - entry point
"preroll" - requires "ads"
"ads" - requires "add-video-js-in-global-scope"
"add-video-js-in-global-scope" - requires "videojs" and add videojs var in window object.
app.js
requirejs.config({
paths: {
"videojs": "./libs/video",
"ads": "./libs/videojs.ads",
"preroll": "./libs/videojs-preroll"
},
shim:{
"preroll": {
deps: ['ads']
},
"ads": {
deps: ["add-video-js-in-global-scope"],
}
}
});
define("add-video-js-in-global-scope",["videojs"], function(videojs) {
window.videojs = videojs;
});
requirejs(["preroll", "ads"], function (preroll,ads) {
// preroll and ads will be undefined because it's not amd.
videojs('idOne', {}, function () {
var player = this;
player.ads(); // initialize the ad framework
// your custom ad integration code
});
});
index.html
<html>
<head>
</head>
<body>
<script data-main="app.js" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js"></script>
<div id="idOne"></div>
</body>
</html>
result:
files:

Requirejs, basic information

I'm learning Requirejs and I started with two simple .html pages: index.html and second.html.
On the index.html I worte:
<script data-main="assets/js/app.min" src="js/vendor/require.js"></script>
The app.min.js file look like this:
requirejs.config({
baseUrl: 'js/vendor',
paths: {
app: '../app',
jquery: 'jquery-1.10.1.min'
}
});
requirejs(["app/main"]);
My app/main.js file has just a jQuery alert:
define(['jquery'], function($) {
$(function() {
alert('Hello World');
});
});
It works fine!
Now I'm worried just about one thing... What about if I need to load the app/main globally for all my pages and then another file like app/second that run only on second.html page?
Probably I'm missing something about Requirejs... I don't thinks that I need to load everything on the app.min.js file like did for the app/main.
I understand that I can define modules on separate js files but then how can I manage different files for different pages without loading everything in just one file? Probably I'm wrong, I hope you can open the light in my brain for that.
Thanks
I understand that a page might need its own code in addition to what is in app.min. You could do something like this:
<script data-main="assets/js/app.min" src="js/vendor/require.js"></script>
<script>
// You can call the config function as many times as you need to add new configuration.
requirejs.config({
// Presumably, baseUrl does not need to be changed.
// baseUrl: 'js/vendor',
paths: {
// additional paths you may need
}
});
// This loads the code proper to this page.
requirejs(["app/second"]);
</script>
If app/second depends on app/main make sure to have that dependency listed in app/second's define call.
Take a look at this example: https://github.com/requirejs/example-multipage. The example demonstrates how you can create page1.js and page2.js and in those files load the common stuff + page specific things. That's one of several ways to do it.
Another way to do which is what I often use is putting something like this in all your pages:
<script src="require.js"></script> <!-- just require -->
<script src="app.min.js"></script> <!-- your config and also loading the main module -->
and then on second.html, you would also add this
<script>require(["app/second"])</script>
You can use this setup for development, and for production you can replace the first 2 lines with just <script src="optimized-bundle.js"></script>. The optimized-bundle.js could include require.js + config + app/main + app/second. Or if you want to load app/second only on the second.html in production to make your main script smaller, you can have require.js + config + app/main in the primary bundle and optimize app/second into a separate bundle - the html would stay the same in both cases.
Hope this helps.

Mocha + BlanketJS + RequireJS, No method 'reporter'

I'm using Mocha with RequireJS and tests are running fine, however, when I try to add in blanket code coverage I'm getting Uncaught TypeError: Object #<HTMLDivElement> has no method 'reporter',
Here's the code I'm running:
<div id="mocha"></div>
<script src="../src/js/vendor/requirejs/require.js"></script>
<script src="../src/js/vendor/blanket/dist/qunit/blanket.js"
data-cover-adapter="../src/js/vendor/blanket/src/adapters/mocha-blanket.js"></script>
<script src="SpecRunner.js" data-cover></script>
and my specrunner:
require(["../src/js/require-config.js"], function () {
// Set testing config
require.config({
baseUrl: "../src/js",
paths: {
"mocha": "vendor/mocha/mocha",
"chai": "vendor/chai/chai"
},
urlArgs: "bust=" + (new Date()).getTime()
});
require([
"require",
"chai",
"mocha"
], function (require, chai) {
var should = chai.should();
mocha.setup("bdd");
require([
"specs.js",
], function(require) {
if (window.mochaPhantomJS) {
mochaPhantomJS.run();
} else {
mocha.run();
}
});
});
});
Like I said - my tests are all running fine, I just can't figure out why blanket's not working.
Update:
I can get it to run by including the script tag for mocha at the beginning, however, now it runs the mocha tests twice.
There's a problem with how you use RequireJS. If you load code with RequireJS and load code with <script> tags, and:
The two sets of code are not dependent on one another, then you can load them in any order.
The code loaded with <script> depends on code loaded by RequireJS, then you should convert the code loaded with <script> to be loaded with RequireJS. If you do not do this, you run into intermittent failures.
The code loaded with RequireJS depends on the code loaded with <script>, then the code loaded with <script> must load and execute before you start loading code with RequireJS.
From looking at the documentation for Blanket, I determine that your case is the second. You load the Blanket adapter before you start loading modules with RequireJS, but the adapter wants Mocha to be present already.
You will have to use a shim. I can't be certain of the exact shim you use (because I don't use blanket) but something like this should help you in the right direction:
shim: {
"blanket": {
exports: "blanket"
},
"mocha-blanket": ["mocha", "blanket"]
}
Obviously the names "blanket" and "mocha-blanket" have to be adapted to your situation. I do not see a need to have an exports value on the adapter itself since the adapter attaches itself to Mocha rather than export something in the global space.
I figured it out and did a write-up on getting Blanket to work with Mocha in AMD. Here's a blog post outlining the process as well as a repo with the working code.
I'm using the following to load my tests:
require(["../src/js/require-config"], function () {
require.config({
baseUrl: "../src/js",
paths: {
chai: "vendor/chai/chai"
}
});
require([
"chai"
], function (chai) {
chai.should();
window.expect = chai.expect;
mocha.setup("bdd");
require([
"specs.js"
], function () {
mocha.run();
});
});
});
And then the following code on the page:
<div id="mocha"></div>
<script src="../src/js/vendor/mocha/mocha.js"></script>
<script data-main="main-tests" src="../src/js/vendor/requirejs/require.js"></script>
<script src="../src/js/vendor/blanket/dist/qunit/blanket.js" data-cover-only="../src/js/component"></script>
<script type="text/javascript" src="../node_modules/grunt-blanket-mocha/support/mocha-blanket.js"></script>
<script>
/* global blanket */
if (window.PHANTOMJS) {
blanket.options("reporter", "../node_modules/grunt-blanket-mocha/support/grunt-reporter.js");
}
</script>
The published mocha adapter from blanket does not works.
Install the not yet released version with bower bower install blanket#master --save-dev
Also, the order of scripts inclusion matter
<script src="mocha.js"></script>
<script>mocha.setup('bdd');</script>
<script data-main="config.js" src="../bower_components/requirejs/require.js"></script>
<script src="../bower_components/blanket/dist/qunit/blanket.js" data-cover-never="bower_components"></script>
<script src="../bower_components/blanket/src/adapters/mocha-blanket.js"></script>

Categories