Integrate jQuery into a electron app - javascript

I'm trying to add jquery functionality to a desktop app written in electron
Using the electron-quick-start repo i'm adding the downloaded jquery file to the main.html file like so:
<script> require("./jquery.min.js"); </script>
or so:
<script>window.$ = window.jQuery = require('./jquery.min.js');</script>
Then in the index.js file i'm adding code in the createWindow function, since that seems the proper place, but to be honest any place i try gets me the same error more or less.
mainWindow.$ is undefined and the same goes for BrowserWindow and app
mainWindow is defined inside the createWindow function like so:
mainWindow = new BrowserWindow({width: 800, height: 600})
and BrowserWindow is declared on top of the file like so:
const BrowserWindow = electron.BrowserWindow
Any idea where i'm going wrong, what declarations i should change/add?
Thanks in advance

While using electron, some additional symbols are also inserted into DOM causing problems. So, you can use jquery as follow
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js" onload="window.$ = window.jQuery = module.exports;"></script>
Notice the code inside "onload".

When you call require inside index.js, or the main process, it's looking for the node module. So you'll need to install jQuery via npm and save it as a dependency in your apps package.json file.
npm install jquery --save
Then your index.js should theoretically see it just fine using
let $ = require('jquery');
mainWindow.$ = $;
Refer to the Node.JS section for installing jQuery. This is what Electron uses.
--
OLD ANSWER
Inside your main.html, just include the JavaScript like you would any traditional JS file.
<script src="./jquery.min.js"></script>

To integrate jQuery into your Electron Application follow these simple steps
Step 1: Run in terminal
npm install jquery --save
Step 2: Add this line to your angular.json or angular-cli.json file
"build": {
"options": {
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.js", //add this line
"node_modules/bootstrap/dist/js/bootstrap.min.js"
],
...
...
}
}
Step 3: Finally add this line to your index.html file
<!-- Need this for jQuery electron -->
<!-- Insert this line above script imports -->
<script>if (typeof module === 'object') {
window.module = module;
module = undefined;
}</script>
<!-- Insert this line after script imports -->
<script>if (window.module) module = window.module;</script>
</head>
You can also use this template

Related

Ruby on Rails 6 Webpack with Javascript libraries

I am building a new project in Rails 6. I have a front-end library I want to use (#tarekraafat/autocomplete.js) that is installed by yarn and exists in my node_modules directory, but is not being made available to other JS code in the browser. Here is what I have set up currently:
/package.json:
"dependencies": {
"#tarekraafat/autocomplete.js": "^8.2.1"
}
/app/javascript/packs/application.js:
import "#tarekraafat/autocomplete.js/dist/js/autoComplete.min.js"
/app/views/.../example.html.erb
<script type="text/javascript">
window.onload = () => {
new autoComplete({
[...]
});
};
</script>
I am getting an error in the browser pointing to the new autoComplete():
Uncaught ReferenceError: autoComplete is not defined
Some reading seems to indicate that I need to modify the /config/webpack/environment.js file, in which I have tried various versions of the following with no luck (including restarting the dev server):
/config/webpack/environment.js:
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
autoComplete: 'autocomplete.js'
})
);
module.exports = environment
First, what do I need to do to add this library so it can be used correctly? Second, as someone who has not directly used webpack previously, what is the function of adding this definition to the environments.js file, and why don't I need to do it for some libraries (bootstrap, popper) but I do for others (jquery, and maybe autocomplete.js)?
In Webpacker, the usage of this library would be as follows:
// app/javascript/src/any_file.js
import autoComplete from "#tarekraafat/autocomplete"
new autoComplete(...)
// app/javascript/packs/application.js
import "../src/any_file"
This alone does not import the autoComplete variable into the global scope. To do that, the simplest thing is assign the variable to window from within your webpack dependency graph.
// app/javascript/src/any_file.js
import autoComplete from "#tarekraafat/autocomplete"
window.autoComplete = autoComplete
As an aside, you don't need to use the ProvidePlugin configuration for this library. The ProvidePlugin says: “add this import to all files in my dependency graph.” This might be helpful for something like jQuery to make legacy jQuery plugins work in webpack. It is not necessary to make your autocomplete lib work

How to load html files from a folder and display them as a link on a local webpage(edited with new question) [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.

JS, Browserify: function not defined

I have files as represented:
-js/
- calc.js
- tool.js
-index.html
calc.js is a node module of following structure:
module.exports = {
calculate: function() {...},
getPrecision: function() {...}
}
and tool.js use require and adds some functions, like that:
const fpcalc = require('./fpcalc');
function changeState() {
//some code using fpcalc
}
I used Browserify to generate bundle.js and added that as script src.
One of my buttons on HTML page is using onclick=changeState(). After clicking I'm getting
ReferenceError: changeState is not defined
at HTMLAnchorElement.onclick
Why is that? Is there any other way to make it work?
The function "changeState" is not exported in your tool.js.
That means it is only visible inside your bundle.js, but not outside.
Have a look at this: https://makerlog.org/posts/creating-js-library-builds-with-browserify-and-other-npm-modules
It shows you how to expose your code to the global namespace in javascript.
Here's a very simple way to make it work like you want.
const fpcalc = require('./fpcalc');
window.changeState = () => {
//some code using fpcalc
}
I have same error, here is my working example.
mac, browserify https://github.com/perliedman/reproject
Must use sudo install globally
sudo npm install -g brwoserify
https://github.com/perliedman/reproject
sudo npm install reproject // install locally is fine
Must manually create 'dist' folder for later output file use
Must use --s expose global variable function 'reproject' and or 'toWgs84' you will use later in browser js.
Without --s , will get 'reproject' undefined error . https://makerlog.org/posts/creating-js-library-builds-with-browserify-and-other-npm-modules
browserify --help will list all options.
-o means output file directory
browserify node_modules/reproject/index.js --s reproject -o node_modules/reproject/dist/reproject.js
HTML script tag include your above dist/reproject.js
Now, you will not get 'reproejct' undefined error
return reproject(_geometry_, ___from_projection, proj4.WGS84, crss)

Is there a way to allow browserify modules access to the global scope (window object)?

The Scenario
I'm using Browserify (or NodeJS/CommonJS like imports) to require some JavaScript libraries. However, I'm having trouble getting them to play nice since apparently Browserify by default denies global scope access to all modules. For example, doing this doesn't work;
file1.js
require('moment');
file2.js
moment(new Date()); // throws moment is undefined
But this works by changing the contents of file1.js to the following;
window.moment = require('moment');
The Problem
This has worked well enough so far, however now I'm having trouble loading the moment timezone library (an extension of MomentJS). Moment Timezone's docs imply both scripts should run on the window global scope by adding them as script tags like so;
<script src="moment.js"></script>
<script src="moment-timezone-with-data.js"></script>
So they can be used like this;
moment().tz("America/Los_Angeles").format();
This however, seems very hard to achieve, since if I try the following;
window.moment = require('moment');
require('./../../node_modules/moment-timezone/builds/moment-timezone-with-data-2010-2020'); // the location of my moment-timezone library
I get a runtime error saying that moment.tz is undefined (meaning that the second library wasn't run with the global scope). And if I try to add the window.moment to the second line of code, I'll be rewriting the first instance of the full library.
So, in short;
Is there a way to allow certain Browserify imports to have global scope access, or to run with the window object as their scope?
I'm aware of the security implications this has, but selectively used, this would be immensely useful while requiring things like JavaScript libraries that need global access to set up themselves correctly. Any help would be greatly appreciated.
Put tiny libraries into vendor.js, include that on your page with <script>, make them known to browserify with browserify-shim and use them with require('libname') in your modules.
Larger libraries may be included from, say, vendor CDNs, and also be made known to browserify with browserify-shim.
index.html
<html>
<head>
<script src="vendor.js"></script>
<script src="bundle.js"></script>
</head>
<body>
Open devtools and inspect the output
</body>
</html>
package.json
{
"scripts": {
"build": "cat vendor1.js vendor2.js > dist/vendor.js && cp index.html dist/index.html && browserify index.js -o dist/bundle.js"
},
"browserify-shim" : {
"vendor1" : "global:vendor1",
"vendor2" : "global:vendor2"
},
"browserify" : {
"transform" : [ "browserify-shim" ]
},
"devDependencies": {
"browserify": "^14.1.0",
"browserify-shim": "^3.8.14"
},
"dependencies": {
"moment": "^2.18.1",
"moment-timezone": "^0.5.11"
}
}
A couple of things to note about the above package.json:
build: it builds 'application' in dist folder, creating the following structure:
dist
index.html
bundle.js
vendor.js
"browserify" entry: it just adds browserify-shim
"browserify-shim" entry: it tells browserify that vendor1 and vendor2 are available as properties on window (global) object. Browserify won't attempt to bundle them, and require() will just return those properties. You need to make sure they are actually available (so index.html above includes them with <script src="vendor.js">
index.js
var momentfromnpm = require('moment-timezone');
var vendor1 = require('vendor1');
var vendor2 = require('vendor2');
console.log("Hello");
console.log("Using module from npm", momentfromnpm().tz("Europe/London").format());
console.log("using a function from vendor1.js (bundled into vendor.js)", vendor1());
console.log("using a 'module' from vendor2.js (bundled to vendor.js)", vendor2.doWork());
vendor1.js
window.vendor1 = function() { // could also be just `function vendor1()...`
return "I'm a simple function, defined on a window";
};
vendor2.js
var vendor2 = { // could also be window.vendor2
doWork: function() {
console.log("vendor2 doing work");
}
};
Install the moment-timezone package as instructed on the website.
npm install moment-timezone --save
In file1.js, define window.moment as so:
window.moment = require('moment-timezone/builds/moment-timezone-with-data-2010-2020');
This should allow you to use moment().tz() in file2.js

How to create QUnit tests with reference to another class?

I'm trying to add unit testing for JavaScript into my web site. I use VS2013 and my project is an ASP.NET web site.
Based on recommendations (http://www.rhyous.com/2013/02/20/creating-a-qunit-test-project-in-visual-studio-2010/) I've done so far:
Created new ASP.NET app
Imported QUnit (using NuGet)
Into "Scripts" added links to js-file in my original web site (files PlayerSkill.js - containts PlayerSkill class and trainings.js - contains Trainer and some other classes)
Created new folder "TestScripts"
Added TrainingTests.js file
Wrote simple test:
test( "Trainer should have non-empty group", function () {
var group = "group";
var trainer = new Trainer(123, "Name123", group, 123);
EQUAL(trainer.getTrainerGroup(), group);
});
Notice: my trainings.js file among others contains
function Trainer(id, name, group, level) {
...
var _group = group;
this.getTrainerGroup = function () { return _group ; }
};
When I execute my test I see error: Trainer is not defined.
It looks like reference to my class is not recognized. I feel like linking file is not enough, but what did I miss?
Please help add reference to the original file with class and run unit test.
Thank you.
P.S. Question 2: Can I add reference to 2 files (my unit test will require one more class which is in another file)? How?
You should add all the relevant logic of your application to your unit testing file so they all execute before you run your tests
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Test Results</title>
<link rel="stylesheet" href="/Content/qunit.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="/Scripts/qunit.js"></script>
<script src="/Scripts/PlayerSkill.js"></script>
<script src="/Scripts/trainings.js"></script>
<script src="/TestScripts/TrainingTests.js"></script>
</body>
</html>
You should not use linked files because they will not exist physically in the script folder.
If you really want to use them you should let the Visual Studio intellisense resolve the physical path of the file like this.
Type the script tag <script src=""></script>
Place the cursor inside the quotes in the src attribute and press CTRL + SPACE
Search your files and let the resolved path untouched
If your project location changes you must update the linked files and also the script references.
{Edit1}
Solution 2:
You could also use an MVC Controller and a Razor View to create your unit testing page and the linked files will work as expected with the only issue that you will have an extra controller in your project but this is not bad at all if for example you want to test the loading of content using ajax that is by default blocked by the browser if they are run from a local file.
Solution 3:
You can also setup a new MVC project just for your javascript unit testing just as you usually setup a new project for any server side code and this will help to prevent your testing to interfere with your production code
{Edit 2}
Solution 4:
As part of the javascript ecosystem you could use grunt or gulp to automate the copy of your scripts from anywhere to your project before running the tests. You could write a gulpfile.js like this
var sourcefiles = [/*you project file paths*/];
gulp.task('default', function () {
return gulp.src(sourcefiles).pipe(gulp.dest('Scripts'));
});
And then run it opening a console and running the command gulp or gulp default
Looks like trainings.js is not defined when calling TrainingTests.js . See this question for more details regarding why this happens! Once that is fixed it does work. And yes similar to trainings.js you can have any number of files in any folder as long as you reference them properly. I have created a sample fiddle accessible # http://plnkr.co/edit/PnqVebOzmPpGu7x2qWLs?p=preview
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="http://code.jquery.com/qunit/qunit-1.18.0.js"></script>
<script src="trainings.js"></script>
<script src="TrainingTests.js"></script>
</body>
In my case I wanted to run my tests from within my ASP.NET web application, and also on a CI server. In addition to the other information here I needed the following, otherwise I experienced the same error as the OP on my CI server:
Add one or more require() calls to test scripts.
Set the NODE_PATH environment variable to the root of my application.
Example of require()
Within my test scripts I include a requires block, the conditional allows me to use this script from a web browser without needing to adopt a third-party equivalent such as requirejs (which is convenient.)
if (typeof(require) !== 'undefined') {
require('lib/3rdparty/dist/3p.js');
require('js/my.js');
require('js/app.js');
}
Example of setting NODE_PATH
Below, 'wwwroot' is the path of where /lib/ and other application files are located. My test files are located within /tests/.
Using bash
#!/bin/bash
cd 'wwwroot'
export NODE_PATH=`pwd`
qunit tests
Using powershell
#!/usr/bin/pwsh
cd 'wwwroot'
$env:NODE_PATH=(pwd)
qunit tests
This allowed me to run tests both within my ASP.NET web application, and also from a CI server using a script.
HTH.
If you're wondering how to make your tests see your code when running from command line (not from browser!), here is a bit expanded version of Shaun Wilson's answer (which doesn't work out-of-the-box, but contains a good idea where to start)
Having following structure:
project
│ index.js <--- Your script with logic
└───test
tests.html <--- QUnit tests included in standard HTML page for "running" locally
tests.js <--- QUnit test code
And let's imagine that in your index.js you have following:
function doSomething(arg) {
// do smth
return arg;
}
And the test code in tests.js (not that it can be the whole content of the file - you don't need anything else to work):
QUnit.test( "test something", function( assert ) {
assert.ok(doSomething(true));
});
Running from command line
To make your code accessible from the tests you need to add two things to the scripts.
First is to explicitly "import" your script from tests. Since JS doesn't have sunch a functionality out-of-the box, we'll need to use require coming from NPM. And to keep our tests working from HTML (when you run it from browser, require is undefined) add simple check:
// Add this in the beginning of tests.js
// Use "require" only if run from command line
if (typeof(require) !== 'undefined') {
// It's important to define it with the very same name in order to have both browser and CLI runs working with the same test code
doSomething = require('../index.js').doSomething;
}
But if index.js does not expose anything, nothing will be accessible. So it's required to expose functions you want to test explicitly (read more about exports). Add this to index.js:
//This goes to the very bottom of index.js
if (typeof module !== 'undefined' && module.exports) {
exports.doSomething = doSomething;
}
When it's done, just type
qunit
And the output should be like
TAP version 13
ok 1 Testing index.js > returnTrue returns true
1..1
# pass 1
# skip 0
# todo 0
# fail 0
Well, due to help of two answers I did localize that problem indeed was in inability of VS to copy needed file into test project.
This can be probably resolved by multiple ways, I found one, idea copied from: http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
Solution is simple: add tag dynamically
In order to achieve this, I've added the following code into tag:
<script>
var fileref = document.createElement('script');
fileref.setAttribute("type", "text/javascript");
var path = 'path'; // here is an absolute address to JS-file on my web site
fileref.setAttribute("src", path);
document.getElementsByTagName("head")[0].appendChild(fileref);
loadjscssfile(, "js") //dynamically load and add this .js file
</script>
And moved my tests into (required also reference to jquery before)
$(document).ready(function () {
QUnit.test("Test #1 description", function () { ... });
});
Similar approach also works for pure test files.

Categories

Resources