How to access variables across Javascript files with babel? - javascript

I'm trying to migrate my code from ES5 to ES6 and use babel. I use the module pattern quite a bit in my code, such that if I have a module like apple I'll do something like this:
var appleModule = (function() {
var yummy = true;
var eat = function() { }
return { "eat": eat }
})();
and then access appleModule in a different file. However, when moving everything from this:
<script type="text/javascript" src="/scripts/apple.js"></script>
<script type="text/javascript" src="/scripts/banana.js"></script>
to this:
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.25/browser.js"></script>
<script type="text/babel" src="/scripts/apple.js"></script>
<script type="text/babel" src="/scripts/banana.js"></script>
I can no longer access appleModule in different files. I get a ReferenceError saying it doesn't exist. How do access variables across files with babel and ES6?

Please actually read the documentation for babel-browser
Not intended for serious use
Compiling in the browser has a fairly limited use case, so if you are working on a production site you should be precompiling your scripts server-side. See setup build systems for more information.
You're not supposed to use babel-browser like that in a production environment. Not even in a development one, really.
Instead, setup a proper build step for your code to transpile and bundle your code.
You don't even have to create your own modules like that
a.js
var yummy = true;
var eat = function(){};
export var eat;
b.js
import {eat} from './a.js';

ES6 exporting only takes the exported parts and everything else is practically equivalent of being in a function, to import appleModule
export var appleModule = (function() {
var yummy = true;
var eat = function() { }
return { "eat": eat }
})();
import {appleModule as appleModule} from './apple';

Related

Import array of modules (MDBootstrap js modules) into Laravel Mix

I have a fresh Laravel 5.8 installation and I would like to include the js modules from MDBootstrap.
In my bootstrap.js file I have:
require('./mdb/modules');
The ./mdb/modules.js file has:
exports.modules = [
'./js/_intro-mdb-pro.js',
'./js/scrolling-navbar.js',
'./js/vendor/jquery.easing.js',
'./js/vendor/velocity.js',
'./js/vendor/chart.js',
'./js/vendor/wow.js',
... 30 more
];
The compilation works ok, but of course, it doesn't take any effect from these modules include.
I don't know how to include all of them at once as they are not looking like a regular module so I can import like 'import * from 'my-module'
I also tried the ES6 way:
import * as MDBootstrap from './mdb/modules';
but I got the same result: successful compilation without including them into the compiled js file.
The content of these 'modules' doesn't seem to look like a normal module where we export default {} or some other functions or variables. It looks like:
//mdb/js/scrolling-navbar.js
"use strict";
(function ($) {
var SCROLLING_NAVBAR_OFFSET_TOP = 50;
$(window).on('scroll', function () {
var $navbar = $('.navbar');
if ($navbar.length) {
if ($navbar.offset().top > SCROLLING_NAVBAR_OFFSET_TOP) {
$('.scrolling-navbar').addClass('top-nav-collapse');
} else {
$('.scrolling-navbar').removeClass('top-nav-collapse');
}
}
});
})(jQuery);
Even 'exports.modules = [..]' is not familiar to me. I know about 'module.export = ...' but this 'exports' looks like it's a Node.js object.
I know there's also another method to include the dist version of the plugin. I also tried it, but I got some errors: 'Identifier '_classCallCheck' has already been declared'. I looked deeper and I found that actually many of those files are declaring the '_classCallCheck' function and of course that it a redeclare error. Maybe I can refer to this particular error directly to them (MDBootstrap).
So here I am, trying to include and use these modules/files in my Laravel project without success. Any help is appreciated.

How can I define a Webpack "global module" to hold my Knockout viewmodel?

I'm working on moving some legacy code into Webpack (to help me control some dependancy hell that I'm having. All's going well so far. The issue comes from the existing codes use of Knockout. I need a way to access the view model in various components. So I need something to hold this view model. This question seems to provide me a good solution:
Put your variables in a module.
Webpack evaluates modules only once, so your instance remains global
and carries changes through from module to module. So if you create
something like a globals.js and export an object of all your globals
then you can import './globals' and read/write to these globals.
I can't really figure out how to do this though. I'm pretty new to webpack/import/export statements so I'm not up to date on the fundamentals. I want a "Module". Great what does webpack have to say on this:
What is a webpack Module
In contrast to Node.js modules, webpack modules can express their
dependencies in a variety of ways
What? Really, that's it?! So I'm struggling to come to terms with what a module is and how I should use one?
Up till now I've defined exported functions and imported them (are these modules??!). So I would do something like this:
export default function koModule(){
var viewModel = {}
function setViewModel(vm){
viewModel = vm;
}
function getViewModel(){
return viewModel;
}
return {
setViewModel:setViewModel,
getViewModel : getViewModel
}
}
I'm think I can then kinda use this when I create my initial viewmodel:
import koModule from './koModule.js'
...
//obviously wrong....
var myKoModule = koModule();
myKoModule.setViewModel(vm);
...
But that's obviously wrong as the myKoModule will be instantiated every time I call the function... and any module trying to do read it is just going to get a blank object:
import koModule from './koModule.js'
...
//obviously wrong....
var myKoModule = koModule();
var vm = myKoModule.getViewModel();
//vm is undefined...
In the previous question it states "Webpack evaluates modules only once". So I'm obviously missing what a module is and how I should be using them then.
So given my requirements, can someone provide an example of a working Webpack "Module" and it's usage in holding,reading and writing a global variable while still allowing me to import it?
I'm obviously missing something fundamental here but I can't really figure out what it is.
This is about as close I can get for you without knowing exactly how you want to use your models and what not. This is often how I use viewModels in webpack, they are essentially just constructor functions with built in methods that I can call on when needed.
Main.js
import ko from 'knockout'
import koModule from './koModule.js'
const model = new koModule('Budhead2004 was here', 'More Stuff here');
ko.applyBindings(model);
KoModule.js
import ko from 'knockout'
// This is your viewModel
class koModule {
constructor(r,t) {
this.Test1 = ko.observable(t);
this.Something = ko.observable(r);
this.Click1 = function() {
alert('test')
}
}
}
export default koModule
HTML
<!-- language: html -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<h1 data-bind="text: Something"></h1>
<input type="text" data-bind="textInput: Test1" />
<span data-bind="text: 'Results of Test1: ' + (Test1() ? Test1() : '')"></span>
<br>
<button data-bind="click: Click1">Click Me</button>
<script src="main.js"></script>
</body>
</html>
Working example here

Webpack: single scope for multiple js files?

Imagine two javascript files and one entry point file:
app.js:
require(a.js);
require(b.js);
a.js:
var a = 4;
b.js:
var b = a+1;
console.debug(b);
This unfortunately does not work because the context of file a is lost in file b, meaning b.js does not know of any variable called a.
How can I fix that using Webpack - I simply want get the same result as
<script src="a.js"></script>
<script src="b.js"></script>
with the added effect of bundling through Webpack.
Using ES2015 modules (which may not be available for you, you can use require instead)
a.js:
export var a = 4;
b.js
import { a } from "./b.js";
var b = a+1;
console.debug(b);
Webpack is a module building/bundling system that works by creating UMD (universal modules) from javascript files. You have to import/export these modules in order for them to be in scope.

Use function from the main.js in imported module

I'm trying to include IOUtil.js and ChannelReplacement.js in my add-on, using the Cu.import(...) function. These two both use xpcom_generateQI, which I'm trying to obtain from the XPCOM jsm, but the two scripts cant access it.
const {Cc, Ci, Cu, Cr} = require("chrome");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const xpcom_generateQI = XPCOMUtils.generateQI;
Cu.import(self.data.url("IOUtil.js"));
Cu.import(self.data.url("ChannelReplacement.js"));
gives me xpcom_generateQI is not defined.
How do I access a function which is defined in main.js?
Issues
Don't use Cu.import for local SDK modules. Don't write JS code modules for SDK add-ons, the SDK uses CommonJS-style modules together with the require() facility which also comes with proper cleanup for free, which cannot be said for JS code modules and Cu.import (you'd need to properly Cu.unload everything and likely kill some references yourself).
That https-everywhere stuff are neither JS code modules nor SDK modules, but uses the subscript loader. Either convert it to SDK code modules, or use the subscript loader yourself.
It is OK to import built-in JS Code modules in different scopes/modules. There is not actually a need to make available xpcom_generateQI from main (although it can be done; well, get to that).
To be future proof, you should bind your xpcom_generateQI shortcut properly, as in XPCOMUtils.generateQI.bind(XPCOMUtils). Otherwise, if the implementation changes and requires a proper this, your stuff will break.
To export something from any CommonJS module, you need to put it into the exports module. See the first link.
To import something, use require() (first link again).
Be aware of circular references, where Module A imports Module B imports Module A. Right now this kinda works (but only kinda, because some stuff might not be available from Module A when Module B imports it like this, as Module A is not fully loaded). Better avoid it.
Example 1 (circular)
So here is a example with circular require (main imports modules imports main)
main.js
function someFunction() {
console.log("some function called");
}
exports.someFunction = someFunction;
var mod = require("./module");
mod.anotherFunction();
module.js
const { someFunction } = require("./main");
exports.anotherFunction = function() {
someFunction();
}
Now, because of circular references this is a fragile construct. If works right now, but when modules get more complex or the SDK changes, it might break... Better put someFunction into a third module.
Example 2 (avoiding circular imports)
main.js
var mod = require("./module");
mod.anotherFunction();
// Or call someFunction directly
var { someFunction } = require("./utils");
someFunction();
module.js
const { someFunction } = require("./utils");
exports.anotherFunction = function() {
someFunction();
}
utils.js
function someFunction() {
console.log("some function called");
}
exports.someFunction = someFunction;
There are no circles anymore. If you wanted to reuse xpcom_generateQI, you'd put it as a property of exports in utils.js (in this example) and later require it with require("./utils").
https-everywhere
The https-everywhere stuff needs to be either converted or loaded using the subscript loader. I would recommend against the subscript loader, because in all likelihood the verbatim https-everywhere code does not clean up after itself. I'd actually also recommend against just converting it by throwing some stuff in (exports.xzy = ...). This code is not meant to be run in the SDK. Better create your own implementation and just borrow ideas from https-everywhere where needed.

Require in Typescript

Can someone explain how would this look in TypeScript. Can it be done via imports?
JS:
var casper = require('casper').create({})
CoffeeScript:
casper = require("casper").create()
Visual Studio error: Error 1 The name ''casper'' does not exist in the current scope
import something = module('something');
var somevar = something.create({});
The point to note here I think is that TS today doesn't allow dotting off of module('something') so you have to break your statement into two.
I've put together a blog on using require.js with Typescript.
http://blorkfish.wordpress.com/2012/10/23/typescript-organizing-your-code-with-amd-modules-and-require-js/
You will be able to write code like this:
require["casper", (casper) => {
var item = casper.create();
};
If you use a module flag when you compile your TypeScript:
--module commonjs
Or
--module amd
It will convert imports into the appropriate module loading statement:
import something = module('something');
var somevar = something.create();
If that casper thing is something written in JavaScript, you need to declare a module for it too (or else it won't compile).
By convention, you put such declaration in a separate file named casper.d.ts:
declare module casper {
export class SomeClassInCasper {
}
export function someFunctionInCasper();
}
And you would include a reference to that casper.d.ts at the top above your import/module:
/// <reference path="casper.d.js" />
import casper = import("casper");
casper is installed through npm on the global scope.
typings install dt~casperjs --global --save
declare var casper; (on your code)
A short casper with typescript how to can be seen here:
https://medium.com/#guyavraham/smoke-tests-casper-js-with-typescript-8b01b504f3a4
I wrote a fairly comprehensive post on using Require in TypeScript. My approach does NOT require you to use the ugly
require(['dependency'], function() {
}
syntax. Instead, in TypeScript you get to use the convenient import x = module("x") syntax.

Categories